Open Leo-lin214 opened 4 years ago
在接下来要出现的 Vue 3.0 中,它更注重的点就在于以下几点。
那么下面我就看看都有哪些大的改动。
在 Vue 2.x 中,Virtual DOM 的最小粒度就是组件,那么只有相应的组件发生改变时,才会执行相应的 compiler --> render --> generate 三个阶段。
那么问题来了,在旧版本的 Vue 中,每次的更新都会遍历整个模板进行编译,包括很多静态节点。每次更新导致的静态节点的重复遍历就会导致很多性能浪费。
其实在 Vue 2.0 后续的版本中,已经有对这一步进行相应的优化,那就是将解析得到的 AST 进行相应的静态节点或静态树标注,这样可以避免下次在遍历的过程中直接跳过。但是另外一个问题出来了,那就是依然还需要对整个模板 Template 进行相应的遍历。
在 Vue 3.0 之后,就采取动静结合策略,来处理这种情况。
简单来说,就是在编译时,现将 Template 中有用到指令的节点记录保存下来,并存到一个数组当中,那么下一次更新遍历时,只需要对该数组进行相应的遍历更新即可。这样就极大滴将 Virtual DOM 的最小粒度将到了动态指令当中,而对于那些静态节点只会在第一次编译时处理,其他情景都会忽略。
当然,动静结合使得一个 VNode Tree 直接划分成了一个区块树 Block Tree。拿尤大大 PPT 中的一张图作为示例。
转化后的区块树长的是这个模样。
相信我们知道,在 Vue 3.0 版本之前,都是基于 Object.defineProperty 实现相应的数据绑定,通过设置相应的 getter 以及 setter 来将一个对象的属性进行响应式设置。
那么问题来了,对于以下的情况,Object.defineProperty 是无法进行相应的数据绑定的。
对于上述的问题,Vue 还特意使用 \$set 全局 API 实现上述的监听。为此在 Vue 3.0 之后,便不再需要担心这些问题的出现啦,通过 ES6 中的 Proxy API 可以完美解决上述的问题。
有兴趣的童鞋可以直接跳到以下链接看看。
Proxy API
class API 固然可以更好滴支持 TS,但是依旧存在的问题就是,Props 和其他需要注入到 this 的属性仍然存在声明类型的问题。另外就是,除了类型支持外,class API 并没有带来更好的优势。
那么我们先看看,所谓的 Function-based API 长的是什么样子的。
const App = { setup() { // data const count = value(0) // computed const plusOne = computed(() => count.value + 1) // method const increment = () => { count.value++ } // watch watch(() => count.value * 2, v => console.log(v)) // lifecycle onMounted(() => console.log('mounted!')) // 暴露给模板或渲染函数 return { count } } }
相比 class API,Function-based API 具有以下优势。
另外的一点,Function-based API 对于 Mixin 特别友好。
需要说明一点,原本 Mixin 会存在以下问题。
那么 React 中的高阶组件依然存在着问题。
但是使用 Function-based API 后,将会更友好滴解决以上问题。
// 旧Mixin写法 const mousePositionMixin = { data() { return { x: 0, y: 0 } }, mounted() { window.addEventListener('mousemove', this.update) }, destroyed() { window.removeEventLister('mousemove', this.update) }, methods: { update(e) { this.x = e.pageX this.y = e.pageY } } } // Function-based API const useMousePosition = function() { const x = value(0) const y = value(0) const update = e => { this.x = e.pageX this.y = e.pageY } onMounted(() => { window.addEventListener('mousemove', this.update) }) onDestroyed(() => { window.removeEventLister('mousemove', this.update) }) return {x, y} } // 在组件中使用Function-based API包装的Mixin new Vue({ template: '...', data() { const {x, y} = useMousePosition() return {x, y} } })
Function-based API 跟 React Hooks 非常的类似,同样具有逻辑复用功能。但是唯一的一点不同在于,React Hooks 在组件更新时都会将所有的 Hooks 都调用一遍,而 Function-based API 则只会调用一次。
great notes
关于 vscode 的 vue 插件: vetur 只支持 vue 2 , volar 只支持 vue 3 volar 支持 vue 2 / 3 , vetur 和 volar 两者冲突。
vscode volar 本身有一个接管模式 vscode volar 在配置 vue 2.7 时候可能会遇到麻烦
使用Volar与Vue 2.7.x时jsconfig.json增加:
Volar
Vue 2.7.x
jsconfig.json
{ "compilerOptions": {}, "vueCompilerOptions": { "target": 2.7, "extensions": [".vue"] } }
在接下来要出现的 Vue 3.0 中,它更注重的点就在于以下几点。
那么下面我就看看都有哪些大的改动。
Virtual DOM重构
在 Vue 2.x 中,Virtual DOM 的最小粒度就是组件,那么只有相应的组件发生改变时,才会执行相应的 compiler --> render --> generate 三个阶段。
那么问题来了,在旧版本的 Vue 中,每次的更新都会遍历整个模板进行编译,包括很多静态节点。每次更新导致的静态节点的重复遍历就会导致很多性能浪费。
其实在 Vue 2.0 后续的版本中,已经有对这一步进行相应的优化,那就是将解析得到的 AST 进行相应的静态节点或静态树标注,这样可以避免下次在遍历的过程中直接跳过。但是另外一个问题出来了,那就是依然还需要对整个模板 Template 进行相应的遍历。
在 Vue 3.0 之后,就采取动静结合策略,来处理这种情况。
简单来说,就是在编译时,现将 Template 中有用到指令的节点记录保存下来,并存到一个数组当中,那么下一次更新遍历时,只需要对该数组进行相应的遍历更新即可。这样就极大滴将 Virtual DOM 的最小粒度将到了动态指令当中,而对于那些静态节点只会在第一次编译时处理,其他情景都会忽略。
当然,动静结合使得一个 VNode Tree 直接划分成了一个区块树 Block Tree。拿尤大大 PPT 中的一张图作为示例。
转化后的区块树长的是这个模样。
Proxy 代理数据绑定
相信我们知道,在 Vue 3.0 版本之前,都是基于 Object.defineProperty 实现相应的数据绑定,通过设置相应的 getter 以及 setter 来将一个对象的属性进行响应式设置。
那么问题来了,对于以下的情况,Object.defineProperty 是无法进行相应的数据绑定的。
对于上述的问题,Vue 还特意使用 \$set 全局 API 实现上述的监听。为此在 Vue 3.0 之后,便不再需要担心这些问题的出现啦,通过 ES6 中的 Proxy API 可以完美解决上述的问题。
有兴趣的童鞋可以直接跳到以下链接看看。
Proxy API
抛弃 Class API,拥抱 Function-based API
class API 固然可以更好滴支持 TS,但是依旧存在的问题就是,Props 和其他需要注入到 this 的属性仍然存在声明类型的问题。另外就是,除了类型支持外,class API 并没有带来更好的优势。
那么我们先看看,所谓的 Function-based API 长的是什么样子的。
相比 class API,Function-based API 具有以下优势。
另外的一点,Function-based API 对于 Mixin 特别友好。
需要说明一点,原本 Mixin 会存在以下问题。
那么 React 中的高阶组件依然存在着问题。
但是使用 Function-based API 后,将会更友好滴解决以上问题。
Function-based API 跟 React Hooks 非常的类似,同样具有逻辑复用功能。但是唯一的一点不同在于,React Hooks 在组件更新时都会将所有的 Hooks 都调用一遍,而 Function-based API 则只会调用一次。