VueComponent
先写个组件
<div id="root">
<school></school>
</div>
提示:一个 school 组件;
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data(){
return{
schoolName:'51CTO',
address:'北京'
}
}
})
new Vue({
el:'#root',
components:{school},
data:{
}
})
看下效果:
控制台看下 school 组件:
school 组件是一个构造函数,叫 VueComponent(),是Vue内部生成的;
Vue.js 源码中有个函数:
既然 school 是一个叫 VueComponent() 的函数,那再写一个组件 hello ,是不是也叫 VueComponent() 呢?
是的。为了验证这个事件,再写一个 hello 组件。
<div id="root">
<hello></hello>
<school></school>
</div>
提示:这次是2个 组件, hello 和 school
// 学校组件
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
data(){
return{
schoolName:'51CTO',
address:'北京'
}
}
})
// hello 组件
const hello = Vue.extend({
template:`<h1>{{msg}}</h1>`,
data(){
return{
msg:'你好,Vue!'
}
}
})
// 分别输出 这两个组件,并比较
console.log('@',school);
console.log('#',hello);
console.log(school == hello );
new Vue({
el:'#root',
components:{school,hello},
data:{
}
})
分别输出这两个组件,并比较:
这两个组件都是 VueComponent() 构造函数,并且不相等,而是每次 Vue.extend() 函数被调用,都会生成一个新的 VueComponent() 函数,看下源码:
源码折叠后,可以看出,Vue.extend() 每次被调用 都会 返回一个新的 VueComponent() ;
那么 school 组件方法中的 this 指向是谁呢? 是 VueComponent() 的实例对象
school 组件,改一下:
// 学校组件
const school = Vue.extend({
template:`
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click='showName'>点击显示校名</button> // 添加按钮
</div>
`,
data(){
return{
schoolName:'51CTO',
address:'北京'
}
},
methods: {
showName(){
console.log(this.schoolName,this); // 让他输出校名,也输出 this
}
},
})
提示:添加按钮和事件,输出 this
看下结果:
这就说明了,组件里的 this 是向组件实例对象(vc);这跟 vm 里的 this 都指向 vm 一样类似;
怎么能体现,vm 在管理着 vc 呢?
控制台输出一下 vm 就知道了:
可以看到,当前 vm 下正管理着两个 vc ;如果子组件里有子组件,也可以用这种方法来查看;
VueComponent 总结
1)school 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是Vue.extend生成的;
2)我们只需要写 <school/> 或 <school></school> , Vue 解析时会帮我们创建 school 组件的实例对象,即Vue帮我们执行的 new VueComponent(options)
3)特别注意:每次调用 Vue.extend,返回的都是一个全新的 VueComponent!
4)关于this 指向:
1、组件配置中:data 函数、methods 中的函数、watch中的函数、computed中的函数,它们的 this 均是 VueComponent() 实例对象;
2、new Vue() 配置中: data 函数、methods 中的函数、watch中的函数、computed中的函数,它们的 this 均是 Vue() 实例对象;
5)VueComponent 的实例对象,以后简称 vc,也可称之为:组件实例对象,Vue的实例对象简称 vm;
VC 与 VM的区别
因为组件是可复用的Vue实例,所以它们与 new Vue 接收相同的选项,例如: data 、computed、watch 、methods 以及生命周期钩子等;
其中一个是像 el 这样根实例(vm)特有的选项;也就是说 vm 决定着容器为谁服务且管理着 vc ;
还有个是 data 在 vc 里要用 函数式 返回属性对象,这才能保证 vc 复用时避免数据的引用关系;否则多个复用共享 data 数据,就麻烦了;
Vue与VueComponent的内置关系
VueComponent.prototype__proto__ === Vue.prototype
让组件实例对象(vc)可以访问到 Vue 原型上的属性和方法;
复习一下原型和继承
function Demo(){
this.a = 1;
this.b = 2;
}
const d = new Demo()
console.log(Demo.prototype); // 显示原型属性
console.log(d.__proto__); // 隐式原型属性
console.log(Demo.prototype === d.__proto__); // 全等
Demo.prototype.x = 100; // 在原型上定义了属性 x 的值
console.log(d); // 输出实例化对象
console.log(d.x); // 实例化对象则继承了 x 属性
看下结果:
一个是构造函数,一个是构造函数的实例化对象;
构造函数的显示原型属性: Demo.prototype ;实例化对象的隐式原型属性: d.__proto__
这两个都指向同一个对象,即原型对象,简称原型,原型上创建的属性,会被实例化对象继承;
验证这个内置关系
VueComponent.prototype__proto__ === Vue.prototype
school.prototype.__proto__ === Vue.prototype // true
vm 是 Vue 是实例化对象,所以:
vm.__proto__ === Vue.prototype // true
这么一来:
school.prototype.__proto__ ===vm.__proto__ // true
这是Vue内部内置实现的:来个图;
让原本 “school.prototype.__proto__
”该指向 Object 对象,指向了 Vue.prototype
;图中黄线;
从而 school 就继承了 Vue.prototype 身上的方法和属性了,也难怪 vc 和 vm 这么像了;
有一点要注意: school 是 function ;而 vm 是 object ;
console.log(typeof vm); // object
console.log(typeof school); // function
再次验证
知道了这层关系,就可以粗暴的再验证一下:改下 school 组件的方法,以显示这个 x ;
<div id="root">
<school></school>
<button @click="showX">(vm)点我显示X</button>
</div>
提示:结构里引入 school 标签后, school 也会被生成;
Vue.prototype.x = 100; // 先在Vue原型上定一个 x
const school = Vue.extend({
template: `
<div>
<h2>学校名称:{{schoolName}}</h2>
<button @click='showX'>点击显示X</button>
</div>
`,
data() {
return {
schoolName: '51CTO'
}
},
methods: {
showX(){ // 来个方法,显示这个 this.x
console.log(this.x);
}
},
})
const vm = new Vue({
el: '#root',
components: { school }, // 注册 school 模板
methods:{
showX(){
console.log(this.x);
}
}
})
一个极简的 vm 和 vc(school),来验证这个 x 是否都能输出, school 能否继承到 Vue 原型的属性;
提示:school 里的方法是 showX(){},vm 里的方法也一样是 showX(){} ,而且 this 指向不相同;
提示:school 通过自己的原型链找到 Vue 原型;vm 则直接继承自 Vue 原型属性;
看下结果:
知道了 Vue和VueComponent 的关系,可以进入 “单文件组件”的学习。