在Vue应用中,单文件组件(Single File Components)是一种特殊的文件格式,以 .vue 为后缀,它允许开发者在一个文件中定义一个Vue组件的全部内容。
每个单文件组件由三个部分组成:template(模板)、script(脚本)和style(样式)。这些部分分别代表Vue组件的结构、逻辑和样式。
具体而言,一个单文件组件的构成如下:
标签,用于包含模板内容。单文件组件的优点在于:
总的来说,单文件组件是Vue框架中一个重要的特性,它帮助开发者更高效地开发和管理复杂的用户界面。
<template>
<div id="app">
<input v-model="name" type="text"/>
<p>Name: {{ name }}</p>
<p>Reversed Name: {{ reversedName }}</p>
</div>
</template>
<script>
export default {
data() {
return {
name: 'John Doe'
};
},
computed: {
reversedName: function () {
console.log('this => ', this)
return this.name.split(' ').reverse().join(' ');
}
},
mounted: function () {
this.$watch('name', function (newVal, oldVal) {
console.log('Name changed from ' + oldVal + ' to ' + newVal);
});
}
};
</script>
在Vue中,VueComponent是组件化开发的核心概念。VueComponent是一个构造函数,用于创建Vue组件。通过VueComponent,我们可以定义组件的属性、方法、生命周期钩子、计算属性等等。
在Vue中,组件是可复用的Vue实例,接受相同的选项对象(除了一些根特定的选项)并且可以拥有完全独立的作用域。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义元素,通过Vue提供的全局API(vue-loader/vueify)进行注册,然后在HTML中就可以使用这些自定义元素了。
在VueComponent中,我们可以定义以下选项:
通过VueComponent,我们可以将复杂的UI拆分成多个独立的、可复用的组件,提高代码的可维护性和可重用性。
在Vue组件的钩子函数中,this 关键字通常指向当前组件的实例对象。这个实例对象包含了组件的数据、方法、计算属性等信息。
例如,在 created 钩子函数中,this 指向当前组件的实例对象:
new Vue({
data: {
message: 'Hello, world!'
},
created: function() {
console.log(this.message); // 输出:Hello, world!
}
});
在上面的例子中,this.message 表示组件实例对象的 message 属性。
但是,在某些情况下,this 的指向可能会发生变化,比如在回调函数或者箭头函数中。在这些情况下,需要格外小心,确保 this 指向正确的对象。可以使用箭头函数或者使用 bind 方法来确保 this 的正确指向。
关于this指向:
data函数、methods中的函数、watch中的函数、computed中的函数,他们的this均是VueComponent实例对象
data函数、methods中的函数、watch中的函数、computed中的函数,他们的this均是Vue实例对象
在Vue中,VM是ViewModel的缩写,是视图模型的意思,是连接View和Model的桥梁,负责业务逻辑处理,并对数据进行加工后交给View展示。通过Vue类创建的对象叫Vue实例化对象,这个对象就是MVVM模式中的VM层,模型通过它可以将数据绑定到页面上,视图可以通过它将数据映射到模型上。
VueComponent.prototype.__proto__ === Vue.prototype
原型是Javascript中的继承的基础,JavaScript的继承就是基于原型的继承。每一个JS对象都可以获得自己的原型,通过原型可以共享函数对象和实例对象之间的属性和方法。
原型的出现,就是为了解决 构造函数 的缺点:
每一次new一个对象时,都会创建一份render()代码浪费资源。通过原型,我们提供了一个给对象添加函数的方法,不然构造函数只能给对象添加属性,不能合理的添加函数就太 LOW 了。
prototype
每一个函数天生自带一个成员 - prototype,是一个对象空间,即然每一个函数都有,构造函数也是函数,构造函数也有这个对象空间。这个 prototype 对象空间可以由函数名来访问:
function Person() {}
console.log(Person.prototype) // 是一个对象
即然是个对象,那么我们就可以向里面放入一些东西:
function Person() {}
Person.prototype.name = 'prototype'
Person.prototype.sayHi = function () {}
我们发现了一个叫做 prototype 的空间是和函数有关联的,并且可以向里面存储一些东西。
重点: 在函数的 prototype 里面存储的内容,不是给函数使用的,是给函数的每一个实例化对象使用的。
那实例化对象怎么使用?
每一个对象都天生自带一个成员,叫做__proto__
,是一个对象空间,即然每一个对象都有,实例化对象也是对象,那么每一个实例化对象也有这个成员。这个 __proto__
对象空间是给每一个对象使用的:
当你访问一个对象中的成员的时候,如果这个对象自己本身有这个成员,那么就会直接给你结果,如果没有,就会去 __proto__
这个对象空间里面找,里面有的话就给你结果。
那么这个 __proto__
又指向哪里呢?
这个对象是由哪个构造函数 new 出来的,那么这个对象的 __proto__
就指向这个构造函数的 prototype。
function Person() {}
var p1 = new Person()
console.log(p1.__proto__ === Person.prototype) // true
我们发现实例对象的 __proto__
和所属的构造函数的 prototype 是一个对象空间,我们可以通过构造函数名称来向 prototype 中添加成员。Person.prototype.name = 'prototype'
对象在访问的时候自己没有,可以自动去自己的 __proto__
中查找
我们可以把函数放在构造函数的 prototype 中,实例化对象访问的时候,自己没有,就会自动去 __proto__
中找。
function Person() {}
Person.prototype.sayHi = function () {
console.log('hello Person')
}
var p1 = new Person()
p1.sayHi()
1 p1 自己没有 sayHi 方法,就会去自己的
__proto__
中查找 p1.__proto__
就是 Person.prototype
我们又向 Person.prototype 中添加了 sayHi 方法 所以 p1.sayHi 就可以执行了
到这里,当我们实例化多个对象的时候,每个对象里面都没有方法,都是去所属的构造函数的 protottype 中查找,那么每一个对象使用的函数,其实都是同一个函数。
function Person() {}
Person.prototype.sayHi = function () {
console.log('hello')
}
var p1 = new Person()
var p2 = new Person()
console.log(p1.sayHi === p2.sayHi)
p1 是 Person 的一个实例
p2 是 Person 的一个实例
也就是说 p1.__proto__
和 p2.__proto__
指向的都是 Person.prototype
当 p1 去调用 sayHi 方法的时候是去 Person.prototype 中找
当 p2 去调用 sayHi 方法的时候是去 Person.prototype 中找
那么两个实例化对象就是找到的一个方法,也是执行的一个方法。
总结: 当我们写构造函数的时候,属性我们直接写在构造函数体内,方法我们写在原型上。