本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-05-31
Vue2.0会对每一个节点去做对比,是否有改动有则更新数据,没有则什么都不做。Vue3.0会给动态节点(使用了Vue指令或者包含了Vue插值表达式的节点)绑定 PatchFlag,在更新的时候判断是否有标记,没有标记不去对比直接拿过来用,有标记再去做对比,数据修改过则更新数据。
<div>
<p>1</p>
<p>2</p>
<p>3</p>
<p>{{msg}}}</p>
</div>
只有第4个P元素参与数据更新:
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("p", null, "1"),
_createVNode("p", null, "2"),
_createVNode("p", null, "3"),
_createVNode("p", null, _toDisplayString(_ctx.msg) + "}", 1 /* TEXT */) // PatchFlag
]))
}
PatchFlag 附录:
这个设计有一点像权限设计,当有多个的时候,可以使用位运算来快速判断,当又是文本节点有具有动态class的时候,就会 1 | 2 = 3。查看是否有某个Tag的时候,就可以用 17 & 1, 转换出来如下:
// <p :class="{b}">{{msg}}}</p>
_createVNode("p", { class: {b: _ctx.b} }, _toDisplayString(_ctx.msg) + "}", 3 /* TEXT, CLASS */)
在 Vue2 中无论元素是否参与更新,每次都会重新创建(如上一样每次都调用_createVNode重新创建),然后再渲染。而 Vue3.0 对于不参与更新的元素,会做静态提升,再渲染直接复用。
// 当启用静态提升之后
const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "1", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "2", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "3", -1 /* HOISTED */) // 静态提升
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_hoisted_1, // 直接复用
_hoisted_2,
_hoisted_3,
_createVNode("p", null, _toDisplayString(_ctx.msg) + "}", 1 /* TEXT */)
]))
}
默认情况下 @click 会为其加上一个 PatchFlag 的,当做动态属性。
但是实际上,@click 接受的动态属性是一个函数,这个函数是不会变化的,所以没必要追踪变化,直接缓存起来复用即可。
<div>
<button @click="handleClick">按钮</button>
</div>
// 默认会被处理为:
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", { onClick: _ctx.handleClick }, "按钮", 8 /* PROPS */, ["onClick"])
]))
}
// 开启事件侦听缓存之后 不再有 PatchFlag
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.handleClick && _ctx.handleClick(...args)))
}, "按钮")
]))
}