vue的挂载过程
new Vue的时候,在初始化生命周期、初始化data, prop, 事件中心结束后, 会判断是否有挂载的节点,
有的话就会调用vm.$mount方法进行挂载。如果没有render方法,就调用getOuterHTML把html元素或者通
过模版编译生成render方法,然后在调用mountComponent方法进行挂载,这个方法首先会定义一个更新
视图的方法,new一个watcher的时候把更新方法传进去,当我们触发set方法的时候就会调用这个更新视图的
方法更新页面。这个更新视图的方法首先会调用render方法生成虚拟dom,然后再调用update方法更新视图。
调用render方法生成虚拟dom主要是调用了一个createElement方法, 把编译后的children啊,data,tag传
进去,主要做的是chidren的规范化(因为chidren的类型是很多的)。patch方法通过vnode创建真实dom通过vue底层
封装的一些操作dom方法挂载
组件化
先构造一个子类的构造函数,然后再安装组件钩子函数和实例化 vnode,
createComponent 后返回的是组件 vnode,它也一样走到 vm._update 方法,进而执行了 patch 函数
nextTick实现
vue会定义两个函数,一个微任务函数,一个宏任务函数,宏任务函数的实现就是判断是否存在setImmediate、
MessageChannel、兜底的话就是setTimeOut了。微任务函数就是判断promise是否存在,不存在的话就把宏任务
函数的引用赋值给微任务函数。我们在写nextTick函数的时候,它实际上会把回调函数push到一个callback数组中,
push到数组中以后会根据环境判断立即执行宏任务还是微任务把一个执行函数推到事件队列中,执行函数执行的时候它
都是把callback数组的函数遍历执行。
编译
编译前会做一个baseOptions的合并的,因为它在同一种平台上它会执行多次编译的,
所以vue底层用了一个函数柯里化的技巧把baseOptions参数保留,我们每次编译的时候其实都会用到这个baseOptions,
编译的第一步就是通过parse方法把模版和baseOptions作为参数通过词法分析和语法分析得到一个抽象语法树,
这一步会用到大量的正则表达式去匹配。第二步就是抽象语法树做一个优化,就是对不会变动的元素做一个静态标记,对模版更新其实
有极大的优化作用的。就是深度地遍历打静态节点标记,做的大概就是比如这个节点包含了表达式,包含了除v-if,v-for之类的
指令的话它就不是静态节点,纯文本就是静态节点。第三步的话就是调用一个generate方法生成一个render字符串,
最后再调用new Function()生成一个render函数。
事件
不管是原生还是自定义事件都会通过模版编译把这些事件名解析出来并且判断它是原生事件还是自定义事件,原生事件通过addEventListener添加到真实元素上,自定义事件事件实际上都是注册在vnode里面的,我们触发emit的时候就直接拿
它父组件对应的回调函数来执行
v-model
就是一个语法糖,大多数情况下就是一个bind value和input事件的结合,对于一些下拉框、单选或者复选框,做一些特殊的
处理嘛,把input事件改成change事件嘛
插槽
普通插槽和作用域插槽的实现。它们有一个很大的差别是数据作用域,普通插槽是在父组件编译和渲染阶段生成 vnodes,所以数据的作用域是父组件实例,子组件渲染的时候直接拿到这些渲染好的 vnodes。而对于作用域插槽,父组件在编译和渲染阶段并不会直接生成 vnodes,而是在父节点 vnode 的 data 中保留一个 scopedSlots 对象,存储着不同名称的插槽以及它们对应的渲染函数,只有在编译和渲染子组件阶段才会执行这个渲染函数生成 vnodes,由于是在子组件环境执行的,所以对应的数据作用域是子组件实例。
keep-alive
它的实现通过自定义 render 函数并且利用了插槽, 实际上它内部是缓存vnode, 对缓存的组件不会执行mounted,
但是又提供了 activated 和 deactivated 钩子函数
transition组件
1.自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
2.如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
3.如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。
vue router
Vue 编写插件的时候要提供静态的 install方法,我们use一个插件的时候其实就是在执行这个install方法,
vueRouter在执行install方法的时候把route和router挂载到vue的原型上,然后注册RouterLink和routerView两个全局组件,
还有一个操作就是用vue.mixin方法把beforeCreate和destroyed两个生命周期钩子混入到vue和options里面,相当于每个组件
都注入 beforeCreate 和 destoryed 钩子函数,在 beforeCreate 做一些私有属性定义和路由初始化工作。所以我们在每个组件里面都可以使用vue-router的一些相关组件和方法了
vuex
可以把store想象成是一个仓库,为了方便管理,把store拆成一些小的module,
整个 modules 是一个树型结构。每个 module 又分别定义了 state,getters,mutations、actions,
通过递归遍历模块的方式都完成了它们的初始化,为了 module 具有更高的封装度和复用性,还定义了 namespace 的概念,