vue源码
2019-07-24 17:55:07 146 举报
AI智能生成
登录查看完整内容
vue源码
作者其他创作
大纲/内容
index.js
_init 具体初始化操作
具体初始化操作
混入各部分模块
init.js
state.js
render.js
events.js
lifecycle.js
proxy.js
提供各模块具体实现函数以及Mixin函数
_init
判断环境是否启用性能检测
判断合并策略
判断代理方案
initLifecycle(vm)
initEvents(vm)
initRender(vm)
initInjections(vm)
initState(vm)
initProvide(vm)
挂在实例vm.$mount(vm.$options.el)
Mixin
initMixin
混入init函数
执行各部分初始化操作
stateMixin
设置data和props的setter和getter
defineProperty在vue原型上定义
在原型上定义$watch函数
eventsMixin
Vue.prototype.$on
监听事件
如果传入的事件名为数组,则递归单个调用
将各个事件名在vue._event的部分存入回调fn
Vue.prototype.$once
一次性事件
将此回调fn放入一个on函数,并且on函数中在fn调用之前使用$off取消绑定
再将on函数通过$on进行绑定,实现一次性触发效果
Vue.prototype.$off
取消事件
检测是否在vm._events上
找到后splice删除
Vue.prototype.$emit
触发事件
找到vm._events[event]
如果是数组则toArray处理
lifecycleMixin
_update
vm.__patch__把 VNode 渲染成真实的 DOM
这里可以看一下https://blog.csdn.net/qq_37939251/article/details/90682986
以及vue diff过程
$forceUpdate
vue里面有判断,如果新值 == 旧值, 那么就不触发watcher更新视图了,所以,如果非要更新就要调用 forceupdate 来强制更新了
$destroy
beforeDestroy
destroyed
renderMixin
installRenderHelpers(Vue.prototype)
一系列渲染方法
$nextTick
dom渲染完后的回调函数
这里可以同时看一下vue批量跟新策略https://km.sankuai.com/page/110756883
_render
如果有父节点,则先处理solt
处理一位数组问题
处理如果是空节点
返回节点
代理
当前环境是开发环境,则调用initProxy方法如果不是开发环境,则vue实例的_renderProxy属性指向vue实例本身。详细解读可看 https://juejin.im/post/5b11db686fb9a01e5b10eae7
性能检测
开发环境下,标记时间startTag = `vue-perf-start:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)
合并
initLifecycle
确定第一个非抽象父组件,然后建立连接,生产children数组
while向上定位第一个非抽象祖先元素
属性赋值vm.$parent = parentvm.$root = parent ? parent.$root : vmvm.$children = []vm.$refs = {}vm._watcher = nullvm._inactive = nullvm._directInactive = falsevm._isMounted = falsevm._isDestroyed = falsevm._isBeingDestroyed = false
initEvents
获取父组件listeners,如果不为空
for in 遍历父组件事件组
normalizeEvent标准化事件,根据我们的的事件名的一些特殊标识(之前在 addHandler 的时候添加上的)区分出这个事件是否有 once、capture、passive 等修饰符。
如果当前事件有回调函数fns,则createFnInvoker分别对单个函数或者函数数组做处理
当我们第二次执行该函数的时候, 把之前绑定的 involer.fns 赋值为新的回调函数即可,这样就保证了事件回调只添加一次,之后仅仅去修改它的回调函数的引用。
initRender
如果有slot通过resolveSlots处理
定义两个创造元素的函数
_c():使用模板创建元素
$createElement():使用render方法创建元素
data无效返回空节点
没有tag返回空节点
检测:key值
依据normalizationType提供两种规范化children函数
手写render函数时 或者编译 slot、v-for:--------------------normalizeChildren
children是基础类型返回createTextVNode
是数组返回normalizeArrayChildren(children)
normalizeArrayChildren
遍历 children,获得单个节点 c,然后对 c 的类型判断,如果是一个数组类型,则递归调用 normalizeArrayChildren; 如果是基础类型,则通过 createTextVNode 方法转换成 VNode 类型;否则就已经是 VNode 类型了,如果 children 是一个列表并且列表还存在嵌套的情况,则根据 nestedIndex 去更新它的 key。这里需要注意一点,在遍历的过程中,对这 3 种情况都做了如下处理:如果存在两个连续的 text 节点,会把它们合并成一个 text 节点。
在非生产模式下 $attrs与$listeners 只读
initInjections
initInjections(vm)------------------通过依赖注入导入依赖项,while向上查找存在的inject的祖先元素,存在的话就defineReactive至当前组件
initState
initProps
如果不是根组件则toggleObserving(false),取消对 Object Array 类型 Prop 深度观测,因为在父组件中已经深度观察过了
遍历传入的propsOptions
给 props 设置响应式
如果没有key的话,_props设置代理访问
initMethods
key遍历传入的methods
如果不是函数类型报错
如果和props冲突报错
如果和vm键值冲突报错
initData
获取vm.$options.data,如果是函数类型,则calldata()执行得到返回结果
检测是否和Props,methods冲突
设置访问代理
为data开启观察者模式
initComputed
遍历获得computed键值对象,如果不是函数则取其.get
const getter = typeof userDef === 'function' ? userDef : userDef.get
判断是不是服务器端渲染,计算属性在服务器渲染的情况下只有getter。如果是服务器端渲染,Vue不会为计算属性添加Watcher。
经过判断后调用defineComputed定义计算属性。
initWatch
遍历watch数组
如果是值为数组类型,for批量createWatcher
否则单独创建
initProvide
export function initProvide (vm: Component) { const provide = vm.$options.provide if (provide) { vm._provided = typeof provide === 'function' ? provide.call(vm) : provide}}
mount
vm.$mount(vm.$options.el) 挂载实例
如果没有render函数template是字符串
如果是ID--------根据ID找到元素template = idToTemplate(template)
如果元素节点------------取innerHTMLtemplate = template.innerHTML
如果template选项不存在,那么使用el元素的outerHTML 作为模板内容template = getOuterHTML(el)
如果经过上述过程template存在的话
compileToFunctions把模板 template 编译生成 render 以及 staticRenderFns
createCompiler()
baseCompile()
得到生成的render函数options.render = renderoptions.staticRenderFns = staticRenderFns
收藏
收藏
0 条评论
回复 删除
下一页