vue3的一些新特性
vue3的一些新特性编译diff方法优化hoistStatic 静态提升cacheHandlers 事件侦听器缓存ssr渲染Composition API核心api逻辑提取与复用变化侦测编译你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。diff方法优化以图1为例,vue2
编译
diff方法优化
以下图为例,vue2中的虚拟dom通过模板创建虚拟节点(js对象),然后使用虚拟节点跟上一次缓存的虚拟节点进行全量的对比。
在vue3中做出了改进,可以看到图中左侧动态绑定msg的span有一处注释,官方叫它patch flag,在与上次虚拟节点进行对比时候,只对比带有patch flag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容,以图中为例,要对比的就是text和props中的id。
hoistStatic 静态提升
把静态的节点进行提升,以下图为例,可以看到所有的静态span都被拿到了渲染函数体外面,也就是说在应用第一次的启动被创建了一次后,之后这些虚拟节点会在每次渲染时候被不停的复用,这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用。
cacheHandlers 事件侦听器缓存
下面图中上面部分是不使用cacheHandlers,onClick需要看成是一个动态的绑定,因为绑定的函数可能会被改变,例如fn本来是data中返回的,之后如果把它替换掉了,这在实际中是需要进行一次更新的。
下面图中下面部分是使用cacheHandlers,在第一次渲染时会自动生成一个内联的函数,在内联函数里面引用当前的fn,然后把内联函数cache起来,后续的更新会从缓存中读同一个函数,因为是同一个函数,也就没有追踪变化的必要,这样就神奇的把这个span变成了静态的。手写的内联函数也会被cache起来,这样就会避免一些没必要的更新。
当我们在组件上使用内联函数,会受益于这个改动。
ssr渲染
当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态的绑定,例如图中,会通过模板插值嵌入进去。这样会比通过虚拟dmo来渲染的快上很多很多。
当静态内容大到一定量级时候,会用_createStaticVNode方法在客户端去生成一个static node,这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
Composition API
官网介绍:在此我们将为您介绍组合式 API: 一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑。
地址:https://composition-api.vuejs.org/zh/
核心api
- reactive:接收一个普通对象然后返回该普通对象的响应式代理。
- ref:接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。
- computed:传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。
- readonly:传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
- watchEffect:立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。可显式的调用返回值以停止侦听。
- watch:全等效于 2.x this.$watch (以及 watch 中相应的选项)。
逻辑提取与复用
例如下面是一个记录鼠标位置的组件,我们可以把它想象成一个react中的hook
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
function update(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', update)
})
onUnmounted(() => {
window.removeEventListener('mousemove', update)
})
return { x, y }
}
以下是一个组件如何利用该函数的展示:
import { useMousePosition } from './mouse'
export default {
setup() {
const { x, y } = useMousePosition()
// 其他逻辑...
return { x, y }
},
}
变化侦测
ES6之前,js是没有提供**元编程**的能力的,也就是没有提供可以拦截原型方法的能力,vue通过覆盖Array原型的方法,来达到做一些自定义操作的目的,比如说发送变化通知。
vue2中覆盖了Array原型中的7个方法,分别是:push、pop、shift、unshift、splice、sort、reverse,所以当直接通过索引改变数组时,vue是追踪不到变化的。
所以在vue2中实现数据双向绑定,是通过Object.definePropertyd劫持各个属性的getter、setter,在读取数据时触发getter,修改数据时候触发setter。
在getter中收集哪些依赖使用了数据,当setter被触发时候,通知getter中收集的依赖数据变化了。
在vue3中改为用Proxy,但是Proxy只能代理一层,对于深层的无法代理。vue3中利用每次set被拦截之前都会拦截到get操作,所以vue3在get中直接对数据进行reactive,这样就大大减少了递归reactive带来的性能消耗。
与Object.definePropertyd对比优势:
1. 可以直接监听对象而非属性
2. 可以直接监听数组的变化
3. Proxy有多达13种拦截方式,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的
4. Proxy返回的是一个新对象,可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
更多推荐
所有评论(0)