一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。 当笔记总结下,主要讲讲实现原理,细节末端忽视
new一个Vue会发生什么?
const vm = new Vue(options).$mount()
beforeCreate
初始化一堆属性,例如生命周期判断有关的还有我们日常用的那堆$属性,还会初始化来自父组件绑定到当前组件的事件。
触发beforeCreate对应的函数和事件.正如上面所说的初始化事件,这里会触发hook:beforeCreate事件
create
这里提一手,那种可以接受多种格式的option,在真正使用前都会修正成统一格式,方便后面使用,以下的data、props之类的都会有这个过程。
统一下名词简称:
- 深绑定:响应式深度绑定,会递归到每个值上面做响应式绑定
- 浅绑定:响应式浅度绑定,只会对第一层数据做响应式绑定
-
初始化 inject,它会一直往自己的祖先上找对应的 provideKey,找不到的话,就使用自己定义的 default,得出的值浅绑定到vue实例上。
-
初始化 props,拿到父组件传进来的 propsData 匹配赋值,如果没有对应的 propKey 值,则使用子组件prop上的 default,会对 default 的值走一遍深绑定。后面浅绑定到 _props 对象上,再代理到vue实例上。为什么 default 要多做一遍深响应呢?因为从父组件传过来的 propsData 大概率是一个响应式对象,只需要做一层响应就行,而后者大概率是一个单纯的对象,所以要深响应,当然,你的默认值是被
observable包裹过的话,不会再次深绑定,会判断然后退出。 -
初始化 methods,这个比较简单,会判断是否是函数,不是函数的话就给一个
空函数noop到vue实例上,是函数的话,会使用bind绑定vue实例到方法上 -
初始化 data,把data代理到vm实例上,并且对data深绑定。这里有一个小点,在调用data函数的时候,他会关闭watch收集,是为了防止子组件初始化data时引用到父组件传过来的prop的值,导致子组件的prop错误的收集到父组件的watch,当修改父组件该值时,会触发下列逻辑:
- 触发父组件的watch调用render函数,修改子组件prop的值
- 子组件的prop被修改后,会触发已经收集到的父组件watch,从而再次调用render函数
- 上述造成了两次更新,因为后续的值已经是相等,所以不会无限循环下去
说一下props特别之处
从 create 生命周期知道,props 的响应式绑定并不简单,那为什么要这样做呢。下面我们详细讨论下:
从浅绑定说起。父组件传递过来的值,有可能不是一个响应式数据,因为基础类型即使父组件那边做了响应式处理,传过来已经丢失了响应,所以要跟子组件的 _props 做一层浅绑定,这样才能收集watch。
那是不是意味已经绑定了响应式的引用类型就可以不用再次浅绑定到 _props 了?
就vue表现来看,因为对每个prop都做了一次浅绑定的缘故,直接在子组件覆盖掉父组件传递的值,还是会触发子组件的响应,虽然vue并不提倡这样做,会造成数据来源混乱,并且还会在开发环境发出警告,但还是保留了这个特性,为了给开发者提供一些保底的操作吧。
而只对于非 default 只做浅响应的操作,会出现一些数据修改不响应的情况,例如我直接给子组件传一个单纯的对象,在子组件修改这个对象里面的属性时,是不会触发组件更新
谢幕
未完待续