本节的示例代码如下
child.vue组件
desc.vue组件
经过上一节分析我们知道,组件在合并配置过程中对数组和对象两种形式的props规范成了统一的对象形式并且他们都有着type属性
本节将继续梳理初始化过程:校验--响应式处理--代理
校验(validateProp)
入参为key(如:name)、规范化过程中处理过的props对象、真实传递的props值、组件实例
规范化过程中处理过的props对象,如
propsData是从组件的render函数中提取的props值,是已经被执行过运算的值。在prender阶段将会调用已经被编译为render函数的模板,并对值进行访问取到真正传递的值如age:12。之后再patch过程中将从vnode中提取到props
prop=propOptions[key];从规范化后的对象中取key对应的值,如name对应的为{type:Number}
hasOwn判断key是否是继承过来的,此处的name是组件本身的,故为false
从提取的propsData中获取真正的值,如name取得值为12
booleanIndex是对布尔值的判断结果,若不等于-1,则当前值的类型为布尔值,则对布尔类型的值是否缺省做校验,比如用户只写了一个name时候,那么应当认定为true;就像html标签中的disabled一样,可以写成disabled="true",也可以不给值
我们向desc组件添加布尔值来命中这个逻辑,假设key为isShow,value为[Boolean,String]。且在app.vue时不传递。我们已经知道在规范化处理中将被规范为{isShow:{type:[Boolean,String]}},进入判断
由于isShow也是组件自身定义的,故absent为false,走else逻辑,此时拿到的value为空字符串,则手动将其值填为true。实际上我们即使我们给定值,也会置为true,这是因为我们在定义时将Boolean写在前了
接着处理非布尔值没传的情况,我们这里将:age="age"去掉以命中该逻辑,进入判断
调用getPropDefaultValue尝试去取它的默认值
--如果没有定义default函数,则说明没有默认值,则返回undefined,如我们当前age就返回undefined
--如定义了,但是定义的不是vue期望的函数类型,则报警告
--框住的位置是vue做的一点优化,由于函数每次返回的对象都是一个新的引用,当组件更新的时候,为了避免不必要watcher update而设置。因为在初始化时候已经将值代理到了_props上
--调用定义的default函数取默认值
最后调用assertProp进行断言,入参为:{type:Number}、age、undefine、组件实例、true
如果定义了required属性,则说明是必传的,但是当前为undefined,所以warn用户
如果不是必须的,则直接将undefined返回
let valid = !type || type === true为true的情况则对应的是字符串数组的props形式,因为被统一规范为{type:null},然后进入判断查找是否符合其一,如[Boolean、Number、String]的情况下是否是其中一种,如果不是则warn用户
最后判断有没有自定义的校验器,如果有则执行,并在校验器返回false时触发warn
响应式处理
当走到这里,即表明我们定义的当前次的key是合法的。那么调用defineReactive将其变成响应式的,根据之前的分析,这将在之后访问时触发get收集依赖,并在设置时触发set。不过我们这里的set是不会向data那样触发派发更新的set,而是重新定义了一个set函数。当设置值时将触发warn。这样做是为了保证props的单项流动以避免不必要的bug
代理
调用proxy将key代理到_props上
此后我们对vm.key的访问实际上访问的是vm._props.key。这将触发sharedPropertyDefinition函数的get,设置将触发其set
网友评论