每个组件都有一个自己的 渲染Watcher
,数据变化后就会通知对应组件的 渲染Watcher
,然后调用组件自己的 updateComponent
,再调用 _update
方法进行更新。
_update
方法时,没有 prevVnode
旧的虚拟节点,所以把传进来的 vnode
存储起来_update
方法时,就可以把传进来的 vnode
和上次的 prevVnode
做新旧虚拟节点的比较了我们在定义全局组件或局部组件时,其实内部都调用了一个叫做 Vue.extend
的 API。
Vue.component('custom-component', {
template: `<button>add</button>`
});
// 等价于
Vue.component('custom-component', Vue.extend({
template: `<button>add</button>`
}));
new Vue({
el: '#app',
data() {},
components: {
'custom-component': {
template: `<button>add</button>`
}
}
});
// 等价于
new Vue({
el: '#app',
data() {},
components: {
'custom-component': Vue.extend({
template: `<button>add</button>`
})
}
});
所以我们声明一个组件,其实就是创建了一个 Vue
的子类。
继承父类,接收 options
选项,最后返回一个子类构造函数。
options
和全局 Vue.options
合并添加 components
策略,在组件对象上的 components
原型上添加全局 components
,这样组件在自身没找到组件后就会去全局找
这里引申出一个面试题,如标题。一旦 data 是个对象而不是个函数,就会导致在声明组件子类构造函数时传入的 options
中的数据源 {data:数据源}
是同一份引用,当同一个组件使用多次并修改数据源时就会相互影响。但如果是个函数就不一样了,每次使用组件都是在 new
一个新实例,里边的 data
现在不是个对象而是函数返回的新对象,就不会出现修改同一份数据源的问题了。
把用户的组件包装成构造函数挂载到 Vue.options.components
上去,并且判断用户传入的是个 Vue.extend
函数还是对象: