从这一小节开始,正式进入
Vue
源码的核心,也是难点之一,响应式系统的构建。这一节将作为分析响应式构建过程源码的入门,主要分为两大块,第一块是针对响应式数据props,methods,data,computed,wather
初始化过程的分析,另一块则是在保留源码设计理念的前提下,尝试手动构建一个基础的响应式系统。有了这两个基础内容的铺垫,下一篇进行源码具体细节的分析会更加得心应手。
7.1 数据初始化
回顾一下之前的内容,我们对Vue
源码的分析是从初始化开始,初始化_init
会执行一系列的过程,这个过程包括了配置选项的合并,数据的监测代理,最后才是实例的挂载。而在实例挂载前还有意忽略了一个重要的过程,数据的初始化(即initState(vm)
)。initState
的过程,是对数据进行响应式设计的过程,过程会针对props,methods,data,computed
和watch
做数据的初始化处理,并将他们转换为响应式对象,接下来我们会逐步分析每一个过程。
function initState (vm) {
vm._watchers = [];
var opts = vm.$options;
// 初始化props
if (opts.props) {
initProps(vm, opts.props); }
// 初始化methods
if (opts.methods) {
initMethods(vm, opts.methods); }
// 初始化data
if (opts.data) {
initData(vm);
} else {
// 如果没有定义data,则创建一个空对象,并设置为响应式
observe(vm._data = {
}, true /* asRootData */);
}
// 初始化computed
if (opts.computed) {
initComputed(vm, opts.computed); }
// 初始化watch
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}
}
7.2 initProps
简单回顾一下props
的用法,父组件通过属性的形式将数据传递给子组件,子组件通过props
属性接收父组件传递的值。
// 父组件
<child :test="test"></child>
var vm = new Vue({
el: '#app',
data() {
return {
test: 'child'
}
}
})
// 子组件
Vue.component('child', {
template: '<div>{
{test}}</div>',
props: ['test']
})
因此分析props
需要分析父组件和子组件的两个过程,我们先看父组件对传递值的处理。按照以往文章介绍的那样,父组件优先进行模板编译得到一个render
函数,在解析过程中遇到子组件的属性,:test=test
会被解析成{ attrs: {test: test}}
并作为子组件的render
函数存在,如下所示:
with(){
..._c('child',{
attrs:{
"test":test}})}
render
解析Vnode
的过程遇到child
这个子占位符节点,因此会进入创建子组件Vnode
的过程,创建子Vnode
过程是调用createComponent
,这个阶段我们在组件章节有分析过,在组件的高级用法也有分析过,最终会调用new Vnode
去创建子Vnode
。而对于props
的处理,extractPropsFromVNodeData
会对attrs
属性进行规范校验后,最后会把校验后的结果以propsData
属性的形式传入Vnode
构造器中。总结来说,props
传递给占位符组件的写法,会以propsData
的形式作为子组件Vnode
的属性存在。下面会分析具体的细节。
// 创建子组件过程
function createComponent() {
// props校验
var propsData = extractPropsFromVNodeData(data, Ctor, tag);
···
// 创建子组件vnode
var vnode = new VNode(
("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
data, undefined, undefined, undefined, context,
{
Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },
asyncFactory
);
}
7.2.1 props的命名规范
先看检测props
规范性的过程。**props
编译后的结果有两种,其中attr