VUE2.x
2020-10-29 22:11:21 3 举报
AI智能生成
vue思维导图
作者其他创作
大纲/内容
Vue初渲染
this._init
initMixin
initState
initProps
initMethods
initData
proxy
observer
defineProperty
defineReactive
get
对数据做响应式
set
walk
observeArray
initComputed
initWatch
vm.$mount
compileToFunctions
parseHTML
generate
mountComponent
new Watcher
调用render方法生成vdom
调用vm._update产生真实dom
patch
createElm
updateProperties
createTextNode
lifecycleMixin
混入update方法
混入mountComponent方法
globalApi
mixin
混入生命周期
mergeOptions
mergeHook
renderMixin
混入render方法
数据响应式
对象类型
数组类型
分支主题
先初始化数据
将模板编译
生成虚拟节点
生成真实的dom
分支主题
挂载页面上
dep(小管家)
watcher
dep(大管家)
get将dep与watcher相互建立关系
set
get将dep与watcher相互建立关系
new Observer类
页面重新更新渲染
自由主题
render 函数
mountComponent
对响应式数据操作
vue的数据更新流程
nextTick更新原理
queueWatcher
nextTick
手动调用vm.$nextTick(cb)
watch监控原理
watch属性
initWatch
createWatcher
new Watcher生成一个用户watcher
watcher身上的user标识
执行watch上定义的方法
patch
传入了新vdom与老vdom进行比较
1.比较老vdom最外层标签与新vdom的最外层标签
不一样时,直接将新vdom生成真实dom替换老的vdom
oldVnode.el.parentNode.replaceChild
一样时,继续往下比对
2.比较是文本节点
是文本节点,直接将新的vdom上文本替换掉老的dom文本
oldVnode.el.textContent = vnode.text
不是,继续往下比对
3.到了这时,那么说明标签一样,标签存在可复用的情况
1.比较新老vdom上的属性并做更新页面dom
updateProperties
2.比较元素里面的子节点
1.当老的vdom上有子节点,而新vdom没有,直接将老dom上节点置空
el.innerHTML = ''
2.当老的vdom上没有子节点,而新的vdom子节点,直接将新vdom上的子节点生成真实dom追加到老dom树上
el.appendChild(createElm(child))
3.当老vdom与新vdom都有子节点
做diff比较
定义新老vdom子节点的指针与指针对应元素
循环比较新老vdom里的元素
1.比较old头<--->new头
相等
孩子间节点比较
移动指针,老与新的开头指针都+1
不相等,继续往下对比
2.比较old尾<--->new尾
相等
孩子间节点比较
移动指针,老与新的结尾指针都-1
不相等,继续往下对比
3.比较old头<--->new尾
相等
孩子间节点比较
移动指针,老的开头指针+1,新的结尾指针-1
不相等,继续往下对比
4.比较old尾<---->new头
相等
孩子间节点比较
移动指针,老的结尾指针-1,新的开头指针+1
不相等,继续往下对比
5.暴力对比
将新vdom上的孩子与老vdom的孩子一一比对
1.如果老的没有,而新的有,则将新vdom的节点创建为真实节点,在将其追加到老的开头指针指向元素的前面
2.匹对对应上则证明该子节点是可复用的,将该可复用节点追加到老的开头指针指向的元素前面,在比较两者的属性与孩子节点
diff流程,diff都是将老新的vdom进行比较后,在去新老的差异更新到老dom上,能移动元素就不创建元素,只有是老的没有该元素复用才创建元素
computed实现
initComputed
new Watcher
defineComputed
dirty
计算属性的本质也是一个watcher
computedWatcher执行getter(computed内部定义的方法),这个watcher被创建后要等到它定义的属性名被读取之后才会与内部依赖的data值进行关联,关联之后,我们的watcher栈中还有渲染watcher时,那么我们就会将这个watcher放到Dep.traget上,然后我们可以通过dep与watcher是n对n的关系,通过这个计算属性watcher去找他收集起来的dep,将渲染watcher添加到这些dep身上。
组件创建挂载流程
defineReactive
当页面第一次渲染时
createComponent
Vue.extend()
在data.hook上添加init方法,这个init方法是用于创建组件实例的
页面第一次render函数执行结束
执行页面第一次渲染的patch
createElm生成父节点,并递归创建真实的子节点元素
通过 createComponent 判断是否是组件的节点
执行组件中的init方法,创建组件的实例,将template的内容在生成真实dom追加到这个组件的内部,在这个过程中的由于child.$mount()未传入挂载点,那么这个template生成的真实节点会挂载到实例vm.el上,随着组件节点被组件到页面上
以<my-button></my-button>为例
vuex源码分析
vuex
Store类
ModuleCollection
register(path,rawModule)
Module类
getChild
获取module实例下的_children对应的属性
addChild
给module实例下的_children添加子实例
forEachMutation
将模块定义好的mutations方法添加到实例下的 this._raw.mutations
forEachAction
将模块定义好的actions方法添加到实例下的 this._raw.actions
forEachGetter
将模块定义好的getters方法添加到实例下的 this._raw.getters
forEachChild
将Module实例下的_children属性进行遍历
getNamespaced
得到模块的命名
有无namespace对模块的state、mutations、actions、getters的影响
// vuex的nameSpace策略
// 有没有namespace是对root_state 和 module_state 没有影响的,module_state 都会将module_state以module_name+module_state的值用vue.set进行响应式观测
// namespace 对getter mutations actions 的区别
// getter: 没有时 module_getters 会对 root_getters 进行覆盖,而有时,会以module_name 进行注册,调用时要用 this.$store.getters['module_name'+'/'+key]
// mutations: 没有namespace 时,module_mutations 会和 root_mutations 进行合并成一个数组,当有时,module_mutations 会以 [module_name + key(方法名)] 进行注册 调用时要用 commit('module_name+'/'+key',payload)
// actions: 没有namespace时,module_actions 会和 root_actions 进行合并成一个数组,当有时,module_actions 会以[module_name+'/'+key(方法名)]进行注册,调用时要用 dispatch('module_name'+'/'+key,payload)
// 有没有namespace是对root_state 和 module_state 没有影响的,module_state 都会将module_state以module_name+module_state的值用vue.set进行响应式观测
// namespace 对getter mutations actions 的区别
// getter: 没有时 module_getters 会对 root_getters 进行覆盖,而有时,会以module_name 进行注册,调用时要用 this.$store.getters['module_name'+'/'+key]
// mutations: 没有namespace 时,module_mutations 会和 root_mutations 进行合并成一个数组,当有时,module_mutations 会以 [module_name + key(方法名)] 进行注册 调用时要用 commit('module_name+'/'+key',payload)
// actions: 没有namespace时,module_actions 会和 root_actions 进行合并成一个数组,当有时,module_actions 会以[module_name+'/'+key(方法名)]进行注册,调用时要用 dispatch('module_name'+'/'+key,payload)
installModule
resetStoreVM
plugin
vuex可以使用插件,例如内置的logger日志插件和持久化插件
主要靠的是
vue-router源码分析
store.js
Vue.use
执行install方法
使用Vue.mixin()上混入beforeEach方法
注册全局组件`router-link`与`router-view`
link.js
最简单的就是渲染一个<a></a>标签
view.js
这里需要根据递归来获取到渲染对应路由组件
在Vue原型上定义$route与$router属性
自由主题
当使用router-link组件进行路由切换或者是调用this.$router.push()
vue-ssr原理分析
app.js
client-entry
client.bundle.js
server-entry
server.bundle.js
后端处理 koa服务
使用vue-server-renderer包创建一个渲染器---> render
前端打包的js包,用于客户端激活
传入template,页面渲染模板
传入后端打包的boundle
vue-router
vuex
三种watcher的创建以及何时收集依赖
computed-watcher(computed方法)
在initState就被创建出来了,但由于是lazy的特点,它不会默认执行回调函数,即不会立马建立watcher与依赖的数据之间的关系,直到我们去读取computed定义额属性时,触发evaluate方法,之后在去触发getter的方法,由于getter的方法有data上值,调用getter就相当于取了data上的值,那么这个watcher就会被这个值的dep收集起来
user-watcher(watch方法)
在initState就被创建了,如果传入了 immediate 属性,那么会立马执行回调函数,若未传,则是把这个watcher推入到watcher栈中
渲染watcher
在组件挂载时,创建出来的,之后立马入watcher栈中,为了在执行页面更新函数时,读取页面的值时,让这些值的dep去收集这个watcher
注册新模块
this._modules.register(path, module)
为了将动态添加的模块的父子关系确定好
installModule(this, this.state, path, module.newModule);
这里将动态模块拿去注册,并在里面找到动态模块的父子关系
resetVM(this, this.state); // 销毁重来
vuex内部重新注册的话 会重新生成实例, 虽然重新安装了 ,只解决了状态的问题,但是computed就丢失了
自由主题
0 条评论
下一页