浅析Vue源码(二)—— initMixin(上)
在上一篇文章《浅析Vue源码(一)-- 造物创世》中提到在定义了一个 Vue Class的时候会引入initMixin 来初始化一些功能,这篇文章就来讲讲initMixin到底初始化了哪些原理呢?
initMixin来源init.js
let uid = 0export function initMixin (Vue: Class<Component>) {Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uidvm._uid = uid++let startTag, endTag/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {startTag = `vue-perf-start:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)}// 如果是Vue的实例,则不需要被observe// a flag to avoid this being observedvm._isVue = true// merge options// 第一步: options参数的处理if (options && options._isComponent) {// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm, options)} else {// mergeOptions接下来我们会详细讲哦~vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}// 第二步: renderProxy/* istanbul ignore else */if (process.env.NODE_ENV !== 'production') {initProxy(vm)} else {vm._renderProxy = vm}// expose real selfvm._self = vm// 第三步: vm的生命周期相关变量初始化initLifecycle(vm)// 第四步: vm的事件监听初始化initEvents(vm)// 第五步: vm的编译render初始化initRender(vm)// 第六步: vm的beforeCreate生命钩子的回调callHook(vm, 'beforeCreate')// 第七步: vm在data/props初始化之前要进行绑定initInjections(vm) // resolve injections before data/props// 第八步: vm的sate状态初始化initState(vm)// 第九步: vm在data/props之后要进行提供initProvide(vm) // resolve provide after data/props// 第十步: vm的created生命钩子的回调callHook(vm, 'created')/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {vm._name = formatComponentName(vm, false)mark(endTag)measure(`vue ${vm._name} init`, startTag, endTag)}// 第十一步:render & mountif (vm.$options.el) {vm.$mount(vm.$options.el)}}
}
复制代码
从上面一点一点注释可以看出,主要是为我们的Vue原型上定义一个方法_init。然后当我们执行new Vue(options) 的时候,会调用这个方法。而这个_init方法的实现,便是我们需要关注的地方。 前面定义vm实例都挺好理解的,主要我们来看一下mergeOptions这个方法,其实Vue在实例化的过程中,会在代码运行后增加很多新的东西进去。我们把我们传入的这个对象叫options,实例中我们可以通过vm.$options访问到。
mergeOptions
mergeOptions主要分成两块,就是resolveConstructorOptions(vm.constructor)和options,mergeOptions这个函数的功能就是要把这两个合在一起。options是我们通过new Vue(options)实例化传入的,所以,我们主要需要研究的是resolveConstructorOptions这个函数的功能。
resolveConstructorOptions 处理 options
export function resolveConstructorOptions (Ctor: Class<Component>) {let options = Ctor.options// 首先需要判断该类是否是Vue的子类if (Ctor.super) {const superOptions = resolveConstructorOptions(Ctor.super)const cachedSuperOptions = Ctor.superOptions// 来判断父类中的options 有没有发生变化if (superOptions !== cachedSuperOptions) {// super option changed,// need to resolve new options.Ctor.superOptions = superOptions// check if there are any late-modified/attached options (#4976)const modifiedOptions = resolveModifiedOptions(Ctor)// update base extend optionsif (modifiedOptions) {// 当为Vue混入一些options时,superOptions会发生变化,此时于之前子类中存储的cachedSuperOptions已经不相等,所以下面的操作主要就是更新sub.superOptionsextend(Ctor.extendOptions, modifiedOptions)}options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)if (options.name) {options.components[options.name] = Ctor}}}return options
}
复制代码
在这里我们大概会产生一个疑惑,可能不太清楚Ctor类里面每个属性到底代表了什么? 下面我们来看这一段代码:
Sub.options = mergeOptions(Super.options,extendOptions)Sub['super'] = SuperSub.superOptions = Super.optionsSub.extendOptions = extendOptionsSub.sealedOptions = extend({}, Sub.options)
复制代码
继承自Super 的子类Sub。换句话说,Ctor其实是继承了Vue,是Vue的子类。 那又有一个疑惑了,mergeOptions是什么呢?
export function mergeOptions (parent: Object,child: Object,vm?: Component
): Object {//...// 统一props格式normalizeProps(child)// 统一directives的格式normalizeDirectives(child)// 如果存在child.extends// ...// 如果存在child.mixins// ...// 针对不同的键值,采用不同的merge策略const options = {}let keyfor (key in parent) {mergeField(key)}for (key in child) {if (!hasOwn(parent, key)) {mergeField(key)}}function mergeField (key) {const strat = strats[key] || defaultStratoptions[key] = strat(parent[key], child[key], vm, key)}return options
}
复制代码
上面采取了对不同的field采取不同的策略,Vue提供了一个strats对象,其本身就是一个hook,如果strats有提供特殊的逻辑,就走strats,否则走默认merge逻辑。
const strats = config.optionMergeStrategies
strats.el = strats.propsData = ...
strats.data = ...
strats.watch ...
....const defaultStrat = function (parentVal: any, childVal: any): any {return childVal === undefined? parentVal: childVal
}
复制代码
看到这里,我们终于把业务逻辑以及组件的一些特性全都放到了vm.options拿到可用的信息。框架基本上都是对输入宽松,对输出严格,vue也是如此,不管使用者添加了什么代码,最后都规范的收入vm.$options中。
renderProxy
这一步比较简单,主要是定义了vm._renderProxy,这是后期为render做准备的,作用是在render中将this指向vm._renderProxy。一般而言,vm._renderProxy是等于vm的,但在开发环境,Vue动用了Proxy这个新API,有关Proxy,大家可以读读深入浅出ES6(十二):代理 Proxies, 这里不再展开。
github喜欢的话可以给我一个star哦~ 接下来会涉及到以下解析哦
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
复制代码
浅析Vue源码(二)—— initMixin(上)相关推荐
- 深入剖析Vue源码 - 响应式系统构建(上)
从这一小节开始,正式进入Vue源码的核心,也是难点之一,响应式系统的构建.这一节将作为分析响应式构建过程源码的入门,主要分为两大块,第一块是针对响应式数据props,methods,data,comp ...
- diff算法_深入剖析Vue源码 - 来,跟我一起实现diff算法!__Vue.js
这一节,依然是深入剖析Vue源码系列,上几节内容介绍了Virtual DOM是Vue在渲染机制上做的优化,而渲染的核心在于数据变化时,如何高效的更新节点,这就是diff算法.由于源码中关于diff算法 ...
- 源码解读_入口开始解读Vue源码系列(二)——new Vue 的故事
作者:muwoo 转发链接:https://github.com/muwoo/blogs/blob/master/src/Vue/2.md 目录 入口开始解读Vue源码系列(一)--造物创世 入口开始 ...
- vue实例没有挂载到html上,vue 源码学习 - 实例挂载
前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...
- 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现
写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...
- vue源码分析系列二:$mount()和new Watcher()的执行过程
续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...
- Vue源码之mustache模板引擎(二) 手写实现mustache
Vue源码之mustache模板引擎(二) 手写实现mustache mustache.js 个人练习结果仓库(持续更新):Vue源码解析 webpack配置 可以参考之前的笔记Webpack笔记 安 ...
- vue 二维数组_最近研究Vue源码时我发现的一些好玩函数
来源 | segmentfault.com/u/chinamasters 作者 | chinamasters 最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大 ...
- vue 初始化方法_前端发展方向指南—Vue源码初始化
Vue 的源码结构比较绕,同时使用了大量的面向对象的高级技巧.重写方法,扩展方法,多态等应用.从 Vue 实例的加载过程就可以看出来,这一节重点看看 Vue 的源码加载流程是什么. 前言 vue已是目 ...
- vue源码学习--vue源码学习入门
本文为开始学习vue源码的思路整理.在拿到vue项目源码的之后看到那些项目中的文件夹,会很困惑,不知道每个文件夹内的世界,怎么变换,怎样的魔力,最后产生了vue框架.学习源码也无从学起.我解决了这些困 ...
最新文章
- EOS从入门到精通-账户体系(文字稿)
- 查看Centos7系统参数和机器参数
- Snowleopard 截屏
- “约见”面试官系列之常见面试题之第九十四篇之MVVM框架(建议收藏)
- OpenGL ES入门
- asp.net AJAX 使用webServices调用时,出现“WebService”未定义
- asp.net:验证控件中ValidationExpression的写法
- 在树莓派上进行python编程_在树莓派上用Python控制LED
- 3D动态视频屏保热带鱼水族馆
- LaTeX 中的花体字母
- ai建立使用图案_AI如何建立剪切蒙版
- mysql存储过程转义字符_mysql存储过程转义字符
- [PTA]6-12 判断奇偶性
- 速看四川省企业技术中心拟认定名单已发布,共181家
- CRAFT字符检测算法和SynthText合成文本数据集
- php省市区中文截取
- 电信各种视频免流卡申请地址合集附地址失效解决方法
- 谷歌提出Flan-T5,一个模型解决所有NLP任务
- 2022最新简约好用的夏雨图床系统源码+UI超好看
- 邓俊辉数据结构学习笔记2
热门文章
- Sublime 3 打开GBK 编码文件中文乱码 解决办法
- 算法:Valid Sudoku(有效的数独)
- 可访问性之于类和对象
- python服务端开发调试日志系统_Loglog首页、文档和下载 - 基于 Python2.7 的日志系统 - OSCHINA - 中文开源技术交流社区...
- matplot画图控制marker点的个数_专刊主编述评 中药质量标志物(Qmarker):提高中药质量标准及质量控制理论和促进中药产业科学发展...
- Python模拟新浪微博登录转载,是我的那篇资料来源
- Hadoop中的一些基本操作
- centos 中如何将python更新到最新的版本
- 牛客 动物森友会(最大流+二分)
- 快速突破面试算法之排序篇