博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「从源码中学习」彻底理解Vue选项Props
阅读量:6528 次
发布时间:2019-06-24

本文共 4863 字,大约阅读时间需要 16 分钟。

最近都在写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)    }}复制代码

划重点:

  • propsOptionsopts.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

转载于:https://juejin.im/post/5c88e669f265da2d8f47792a

你可能感兴趣的文章
制作Windows Server 2003/08 image详细步骤与OpenStack介绍
查看>>
2016国赛小结
查看>>
Android Studio 第六十四期 - Android业务组件化之URL Scheme使用
查看>>
Hyper-V 2016 系列教程41 Windows 10 Hyper-V 系统要求
查看>>
EC2 WordPress 移动目录
查看>>
Windows Server 2008 启用公共文件夹共享
查看>>
【运维故事】职场如何领先一步?
查看>>
如何提高SEO优化团队效率
查看>>
做业务与技术之间的桥梁
查看>>
SFB 项目经验-17-Windows 2012 R2-补丁打到最新-问题-KB2982006
查看>>
用hadoop中的libhdfs和fuse-dfs构建快速云存储
查看>>
VMTools和虚拟硬件升级
查看>>
不知道自己不知道(Unknown Unknowns)的知识决定了你的发展
查看>>
Apple Watch的非“智能手表”卖点
查看>>
fedora17升级到fedora18
查看>>
单例模式(Singleton)
查看>>
函数指针和指针函数
查看>>
认识配置设置文件(INI与XML)
查看>>
DZ!NT论坛 3.6.711删除用户各种错解决方案
查看>>
Python的函数参数传递:传值?引用?
查看>>