组件的虚拟节点

更新组件

每个组件都有一个自己的 渲染Watcher ,数据变化后就会通知对应组件的 渲染Watcher ,然后调用组件自己的 updateComponent ,再调用 _update 方法进行更新。

  1. 第一次渲染调用 _update 方法时,没有 prevVnode 旧的虚拟节点,所以把传进来的 vnode 存储起来
  2. 后续再调用 _update 方法时,就可以把传进来的 vnode 和上次的 prevVnode 做新旧虚拟节点的比较了

image.png

Vue.extend

我们在定义全局组件或局部组件时,其实内部都调用了一个叫做 Vue.extend 的 API。

image.png

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 的子类。

实现 Vue.extend

继承父类,接收 options 选项,最后返回一个子类构造函数。

image.png

为什么 Vue 组件中的 data 不能是个对象?

这里引申出一个面试题,如标题。一旦 data 是个对象而不是个函数,就会导致在声明组件子类构造函数时传入的 options 中的数据源 {data:数据源} 是同一份引用,当同一个组件使用多次并修改数据源时就会相互影响。但如果是个函数就不一样了,每次使用组件都是在 new 一个新实例,里边的 data 现在不是个对象而是函数返回的新对象,就不会出现修改同一份数据源的问题了。

Vue.component

把用户的组件包装成构造函数挂载到 Vue.options.components 上去,并且判断用户传入的是个 Vue.extend 函数还是对象:

image.png