最近都在写Vue相关的文章,感兴趣的可以看回我之前写的。
作者文章总集
正文:吃下这条鱼? - props
初始化
initProps
是如何运行的:
1.normalizeProps
: initProps
之前的规范化数据
normalizeProps
的代码有点长,这里只列举经过规范化后的prop
类型和结果
1.1 字符串
props: ["data"]// 规范化后props: { data:{ type: null }}复制代码
1.2 对象
props: { data1: { type: String, default: '' } data2: Number,}// 规范化后props: { data1: { type: String, default: '' }, data2: { type: Number },}复制代码
2.initProps
: 处理props
源码分析如下:
function initProps (vm: Component, propsOptions: Object) { const propsData = vm.$options.propsData || {} const props = vm._props = {} const keys = vm.$options._propKeys = [] const isRoot = !vm.$parent if (!isRoot) { toggleObserving(false) } for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) if (process.env.NODE_ENV !== 'production') { const hyphenatedKey = hyphenate(key) if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { if (!isRoot && !isUpdatingChildComponent) { warn( `Avoid mutating a prop direct....`, vm ) } }) } else { defineReactive(props, key, value) } if (!(key in vm)) { proxy(vm, `_props`, key) } } toggleObserving(true)}复制代码
2.1 常量定义
const propsData = vm.$options.propsData || {} const props = vm._props = {} const keys = vm.$options._propKeys = [] const isRoot = !vm.$parent复制代码
propsData
: 存储着传递进来的props
的值props: 引用
vm._props`,并初始化为{}keys
: 在vm.$options
上添加_propKeys
属性isRoot
: 判断是否存在vm.$parent
,若无则为根节点
2.2 条件判断及循环
if (!isRoot) { toggleObserving(false)}for (const key in propsOptions) { // 省略...}toggleObserving(true)复制代码
!isRoot
:若当前实例非根节点,关闭toggleObserving
toggleObserving
: 可以理解为数据观测的开关for...in
: 遍历propsOptions
2.2.1: 遍历propsOptions
做什么
for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) if (process.env.NODE_ENV !== 'production') { const hyphenatedKey = hyphenate(key) if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { if (!isRoot && !isUpdatingChildComponent) { warn( `Avoid mutating a prop directly since the value will be ` + `overwri tten whenever the parent component re-renders. ` + `Instead, use a data or computed property based on the prop's ` + `value. Prop being mutated: "${key}"`, vm ) } }) } else { defineReactive(props, key, value) }}复制代码
划重点:
propsOptions
即opts.props
key
就是每个prop
的名字
此时进入循环:
keys.push(key)const value = validateProp(key, propsOptions, propsData, vm)复制代码
- 将
key
添加到vm.$options._propKeys
value
: 用validateProp
校验是否为预期的类型值,然后返回相应 prop 值(或default值)
2.2.2: 接着进入 if...else
:
这里注释一下:
if (process.env.NODE_ENV !== 'production') { // 驼峰转连字符 const hyphenatedKey = hyphenate(key) // 校验prop是否为内置的属性 // 内置属性:key,ref,slot,slot-scope,is if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { // 子组件直接修改属性时 弹出警告 if (!isRoot && !isUpdatingChildComponent) { warn( `Avoid mutating a prop directly since the value will be ` + `overwri tten whenever the parent component re-renders. ` + `Instead, use a data or computed property based on the prop's ` + `value. Prop being mutated: "${key}"`, vm ) } }) } else { defineReactive(props, key, value) }复制代码
最后简化:
if (process.env.NODE_ENV !== 'production') { // 驼峰转连字符 // 校验prop是否为内置的属性 // 内置属性:key,ref,slot,slot-scope,is // 若是内置,弹出警告 defineReactive(props, key, value, () => { // 子组件直接修改属性时 弹出警告 } else { defineReactive(props, key, value) }复制代码
工具函数:
2.2.3: defineReactive
: 最终处理
defineReactive(props, key, value)复制代码
defineReactive
是老熟人了,但这里要注意一点: 先前toggleObserving(false)
,关闭了观测的开关,所以defineReactive
中调用 observe
, 是一个无效调用。
此时到这里,可以得出一个结论
props
是通过 defineReactive
定义的,此时虽然是响应式数据,但没有进行深度定义。
即,父组件传给子组件props后,子组件不必再重复观测props
2.2.4 toggleObserving(true)`: 最后打开观测开关
toggleObserving(true)复制代码
重新打开观测开关,避免影响后续代码执行。
感悟:相比分析源码,理解后写成博客更难。用文字讲清楚一件事可比敲代码难多了。
求一份深圳的内推
目前本人在准备跳槽,希望各位大佬和HR小姐姐可以内推一份靠谱的深圳前端岗位!
- 微信:
huab119
- 邮箱:
454274033@qq.com