You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** * 初始化 inject 配置项 * 1、得到 result[key] = val * 2、对结果数据进行响应式处理,代理每个 key 到 vm 实例 */exportfunctioninitInjections(vm: Component){// 解析 inject 配置项,然后从祖代组件的配置中找到 配置项中每一个 key 对应的 val,最后得到 result[key] = val 的结果constresult=resolveInject(vm.$options.inject,vm)// 对 result 做 数据响应式处理,也有代理 inject 配置中每个 key 到 vm 实例的作用。// 不不建议在子组件去更改这些数据,因为一旦祖代组件中 注入的 provide 发生更改,你在组件中做的更改就会被覆盖if(result){toggleObserving(false)Object.keys(result).forEach(key=>{/* istanbul ignore else */if(process.env.NODE_ENV!=='production'){defineReactive(vm,key,result[key],()=>{warn(`Avoid mutating an injected value directly since the changes will be `+`overwritten whenever the provided component re-renders. `+`injection being mutated: "${key}"`,vm)})}else{defineReactive(vm,key,result[key])}})toggleObserving(true)}}
resolveInject
/src/core/instance/inject.js
/** * 解析 inject 配置项,从祖代组件的 provide 配置中找到 key 对应的值,否则用 默认值,最后得到 result[key] = val * inject 对象肯定是以下这个结构,因为在 合并 选项时对组件配置对象做了标准化处理 * @param {*} inject = { * key: { * from: provideKey, * default: xx * } * } */exportfunctionresolveInject(inject: any,vm: Component): ?Object{if(inject){// inject is :any because flow is not smart enough to figure out cachedconstresult=Object.create(null)// inject 配置项的所有的 keyconstkeys=hasSymbol
? Reflect.ownKeys(inject)
: Object.keys(inject)// 遍历 keyfor(leti=0;i<keys.length;i++){constkey=keys[i]// 跳过 __ob__ 对象// #6574 in case the inject object is observed...if(key==='__ob__')continue// 拿到 provide 中对应的 keyconstprovideKey=inject[key].fromletsource=vm// 遍历所有的祖代组件,直到 根组件,找到 provide 中对应 key 的值,最后得到 result[key] = provide[provideKey]while(source){if(source._provided&&hasOwn(source._provided,provideKey)){result[key]=source._provided[provideKey]break}source=source.$parent}// 如果上一个循环未找到,则采用 inject[key].default,如果没有设置 default 值,则抛出错误if(!source){if('default'ininject[key]){constprovideDefault=inject[key].defaultresult[key]=typeofprovideDefault==='function'
? provideDefault.call(vm)
: provideDefault}elseif(process.env.NODE_ENV!=='production'){warn(`Injection "${key}" not found`,vm)}}}returnresult}}
Vue 源码解读(2)—— Vue 初始化过程
当学习成为了习惯,知识也就变成了常识。 感谢各位的 点赞、收藏和评论。
新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn
文章已收录到 github 仓库 liyongning/blog,欢迎 Watch 和 Star。
封面
目标
深入理解 Vue 的初始化过程,再也不怕 面试官 的那道面试题:
new Vue(options)
发生了什么?找入口
想知道
new Vue(options)
都做了什么,就得先找到 Vue 的构造函数是在哪声明的,有两个办法:从 rollup 配置文件中找到编译的入口,然后一步步找到 Vue 构造函数,这种方式 费劲
通过编写示例代码,然后打断点的方式,一步到位,简单
我们就采用第二种方式,写示例,打断点,一步到位。
/examples
目录下增加一个示例文件 ——test.html
,在文件中添加如下内容:test.html
,则会进入断点调试,然后找到 Vue 构造函数所在的文件 点击查看演示动图,动图地址:https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d839ea6f3e5d4adcaf1ea9a8f6ff1a70~tplv-k3u1fbpfcp-watermark.awebp
得到 Vue 构造函数在
/src/core/instance/index.js
文件中,接下来正式开始源码阅读,带着目标去阅读。源码解读 —— Vue 初始化过程
Vue
Vue.prototype._init
resolveConstructorOptions
resolveModifiedOptions
mergeOptions
initInjections
resolveInject
initProvide
总结
Vue 的初始化过程(new Vue(options))都做了什么?
处理组件配置项
初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上
初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率
初始化组件实例的关系属性,比如 $parent、$children、$root、$refs 等
处理自定义事件
调用 beforeCreate 钩子函数
初始化组件的 inject 配置项,得到
ret[key] = val
形式的配置对象,然后对该配置对象进行浅层的响应式处理(只处理了对象第一层数据),并代理每个 key 到 vm 实例上数据响应式,处理 props、methods、data、computed、watch 等选项
解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上
调用 created 钩子函数
如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount
接下来则进入挂载阶段
链接
感谢各位的:点赞、收藏和评论,我们下期见。
当学习成为了习惯,知识也就变成了常识。 感谢各位的 点赞、收藏和评论。
新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn
文章已收录到 github 仓库 liyongning/blog,欢迎 Watch 和 Star。
The text was updated successfully, but these errors were encountered: