vue3事件缓存(cacheHandlers)
<div @click="clickEvent">Hello World!</div>
vue2编译成render函数
(_ctx, _cache) => {
return (_openBlock(), _createElementBlock("div", { onClick: _ctx.clickEvent }, "Hello World!", 8 /* PROPS */, ["onClick"]))
}
// Check the console for the AST
vue3经过编程render函数
import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", {
onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.clickEvent && _ctx.clickEvent(...args)))
}, "Hello World!"))
}
// Check the console for the AST
为什么要单独加缓存?
更新事件的似乎,如果需要卸载事件,太消耗性能,如果我们可以直接更改老的事件的内存地址,何乐而不为
export function patchEvent(
el: Element & { _vei?: Record<string, Invoker | undefined> },
rawName: string,
prevValue: EventValue | null,
nextValue: EventValue | null,
instance: ComponentInternalInstance | null = null
) {
// vei = vue event invokers
const invokers = el._vei || (el._vei = {})
const existingInvoker = invokers[rawName]
if (nextValue && existingInvoker) {
// patch
existingInvoker.value = nextValue
} else {
const [name, options] = parseName(rawName)
if (nextValue) {
// add
const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
addEventListener(el, name, invoker, options)
} else if (existingInvoker) {
// remove
removeEventListener(el, name, existingInvoker, options)
invokers[rawName] = undefined
}
}
}
上面代码做的事情
- 给当前的el上挂载一个_vei属性(vue event invokers)去缓存当前这条元素身上的事件
- 进行diff比对的时候,如果有老的同名的事件就直接替换老的事件的内存地址(这样就少了一次移除事件+新增事件的性能消耗)
- 如果没有就算是新增的事件,并且如果新增的事件不存在,才真正去移除老的事件,如果新增的事件在,并且没有老的事件绑定,则重新创建缓存并且绑定到el上
invoker里面的结构类似
{
click:[event....]
change:[event...]
}