0
点赞
收藏
分享

微信扫一扫

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系

舍予兄 2022-12-06 阅读 170

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:{

}
})

看下效果:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue

控制台看下 school 组件:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue_02

school 组件是一个构造函数,叫 VueComponent(),是Vue内部生成的;

Vue.js 源码中有个函数:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_VueComponent_03

既然 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:{

}
})

分别输出这两个组件,并比较:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue_04

这两个组件都是 VueComponent() 构造函数,并且不相等,而是每次 Vue.extend() 函数被调用,都会生成一个新的 VueComponent() 函数,看下源码:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_VueComponent_05

源码折叠后,可以看出,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

看下结果:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue_06

这就说明了,组件里的 this 是向组件实例对象(vc);这跟 vm 里的 this 都指向 vm 一样类似;

怎么能体现,vm 在管理着 vc 呢?

控制台输出一下 vm 就知道了:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_VueComponent_07

可以看到,当前 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 属性

看下结果:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_VueComponent_08

一个是构造函数,一个是构造函数的实例化对象;

构造函数的显示原型属性: 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内部内置实现的:来个图;

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue_09

让原本 “​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 原型属性;

看下结果:

Vue2(笔记22) - 组件 - VueComponent 以及 Vue 和 VueComponent 的内置关系_Vue_10

知道了 Vue和VueComponent 的关系,可以进入 “单文件组件”的学习。


举报

相关推荐

0 条评论