Vue2的一些原理
2020-07-18 本文已影响0人
hellomyshadow
keep-alive
keep-alive
- 多看源码,方知原理,才能优化
- 作用:缓存
- 怎么缓存:用队列缓存到内存中
- 缓存什么:
VNode
虚拟DOM
- 注意点:缓存数量的限制,因为
VNode
很大,为了防止内存溢出,所以不允许缓存过多 - 缓存机制:
LRU
- 优化点:不缓存
VNode
,而是缓存data
数据
Vue的编译运行
vue runtime + complier
-
runtime
运行时 -
complier
编译时
一个单文件组件的模式:template、script、style
- 通过本地离线编译,把单文件组件编译为
render
函数(JS
文件),这个过程就是vue
的编译时。 - 编译后的文件存放到远程服务器,浏览器访问页面时,请求这些
js
文件并执行:new Vue()
把数据处理成响应式数据,并触发render
函数,进入vue
的运行时。
render()
的执行会生成VNode
,并patch
到真实DOM
上。当数据改变时,Watcher
会找到对应要更新的组件,Diff
组件级别的新旧两个VNode Tree
,生成补丁并应用到真实DOM
树中。
所以,直接使用 render
函数可以在一定程度上优化编译过程。
Look实现原理
-
computed
与watch
实际上它们都是通过watcher
实现的,最大区别就是computed
具有缓存功能。
在创建计算属性时,它会创建一个
watcher
,其中有两个属性lazy:true, dirty: true
。
创建过程默认是不执行的,只有当用户取值时才会判断dirty:true
则让这个watcher
去取值,求值结束后则改为dirty:false
,不再重新求值,再次取值直接返回上次求值结果。
那什么时候会重新计算求值呢?
只有当计算属性中依赖的值发生变化时,它会调用对应的update()
,更改dirty:true
,从而重新执行watcher
求值。
-
v-if
与v-for
不能一起使用,必要时应使用computed
先过滤出需要的数组元素。
原因是v-for
比v-if
的优先级更高,即使只需要其中一个元素(只有一个元素的v-if="true"
),每一次仍然需要遍历整个数组,严重影响性能。
源码编译// 1. v-if 在父元素上,v-for 在子元素上 VueTemplateCompiler.compile(`<div v-if="true"><span v-for="i in 3">hello</span></div>`); // 模板的编译结果 with(this) { return (true) ? _c('div', _l((3), function (i) { return _c('span', [_v("hello")]) }), 0) : _e() // _e()方法创建一个空的虚拟dom等等。 } // 2. v-for 与 v-if 连用的编译结果 VueTemplateCompiler.compile(`<div v-if="false" v-for="i in 3">hello</div>`); with(this) { return _l((3), function (i) { return (false) ? _c('div', [_v("hello")]) : _e() }) }
-
v-show
的底层实现
v-show
编译出来里面没有任何东西,只有一个directives
,它里面有一个指令叫做v-show
源码编译
只有在运行的时候它会去处理这个指令,它正是在操作DOM的VueTemplateCompiler.compile(`<div v-show="true"></div>`); with(this) { return _c('div', { directives: [{ name: "show", rawName: "v-show", value: (true), expression: "true" }] }) }
display
属性// v-show 操作的是样式 定义在platforms/web/runtime/directives/show.js bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) { vnode = locateNode(vnode) const transition = vnode.data && vnode.data.transition const originalDisplay = el.__vOriginalDisplay = el.style.display === 'none' ? '' : el.style.display if (value && transition) { vnode.data.show = true enter(vnode, () => { el.style.display = originalDisplay }) } else { el.style.display = value ? originalDisplay : 'none' } }