共计 2206 个字符,预计需要花费 6 分钟才能阅读完成。
在书写 petite-vue 和 Vue 最舒服的莫过于通过 @click
绑定事件,而且在移除元素时框架会帮咱们主动解除绑定。省去了过来通过 jQuery 的累赘。而事件绑定在 petite-vue 中就是一个指令(directive),和其余指令相似。
深刻 v-on
的工作原理
walk
办法在解析模板时会遍历元素的个性汇合 el.attributes
,当属性名称name
匹配 v-on
或@
时,则将属性名称和属性值压入 deferred
队列的队尾,当以后元素所有属性绑定和 v-modal
解决后以及子元素所有属性绑定、v-modal
和事件绑定解决后再解决。
那问题来了,为什么要将事件绑定放到最初解决呢?
// 文件 ./src/on.ts | |
const systemModifiers = ['ctrl', 'shift', 'alt', 'meta'] | |
const modifiersGuards: Record< | |
string, | |
(e: Event, modifiers: Record<string, true>) => void | boolean | |
> = {stop: e => e.stopPropagation(), | |
prevent: e => e.preventDefault(), | |
self: e => e.target !== e.currentTarget, | |
ctrl: e => !(e as KeyedEvent).ctrlKey, | |
shift: e => !(e as KeyedEvent).shiftKey, | |
alt: e => !(e as KeyedEvent).altKey, | |
meta: e => !(e as KeyedEvent).metaKey, | |
left: e => 'button' in e && (e as MouseEvent).button !== 0, | |
middle: e => 'button' in e && (e as MouseEvent).button !== 1, | |
right: e => 'button' in e && (e as MouseEvent).button !== 2, | |
/* @click.alt.shift 将别离匹配 alt 和 shift 两个 modifiers guards,当此时按 alt+shift+ctrl 时,两个 modifiers guards 均通过。* 而 @click.alt.shift.exact 将别离匹配 alt、shift 和 exact,当此时按 alt+shift+ctrl 时,后面两个 modifiers guards 均通过,但最初的 exact guard 将返回 true,不执行事件回调函数。*/ | |
exact: (e, modifiers) => | |
systemModifiers.some(m => (e as any)[`${m}Key`] && !modifiers[m]) | |
} | |
export const on: Directive({el, get, exp, arg, modifiers}) => {let handler = simplePathRE.test(exp) | |
? get(`(e => ${exp}(e)`) | |
: get(`($event => { ${exp} })`) | |
if (arg === 'vue:mounted') { | |
// 如果绑定的是生命周期函数 mounted,但因为以后元素早已增加到 DOM 树上,因而将函数压入 micro queue 执行 | |
nextTick(handler) | |
return | |
} | |
else if (arg === 'vue:unmounted') { | |
// 如果绑定的是生命周期函数 unmounted,则返回 cleanup 函数 | |
return () => handler() | |
} | |
if (modifiers) { | |
// 如果存在 modifiers,则对事件绑定进行加强 | |
if (arg === 'click') { | |
// @click.right 对应的 DOM 事件是 contextmenu | |
if (modifiers.right) arg = 'contextmenu' | |
// @click.middle 对应的 DOM 事件是 mouseup | |
if (modifiers.middle) arg = 'mouseup' | |
} | |
const raw = hanlder | |
handler = (e: Event) => {if ('key' in e && !(hyphenate((e as KeyboardEvent).key) in modifiers)) { | |
/* 如果为键盘事件,键不在没有在 modifiers 中指定则不执行事件回调函数 | |
* key 值为 a、b、CapsLock 等,hyphenate 将 CapsLock 转换为 caps-lock | |
*/ | |
return | |
} | |
for (const key in modifiers) { | |
// 执行 modifiers 对应的逻辑,若返回 true 则不执行事件回调函数 | |
const guard = modiferGuards[key] | |
if (guard && guard(e, modifiers)) {return} | |
return raw(e) | |
} | |
} | |
} | |
// 竟然没有返回 cleanup 函数??大家能够去奉献代码了哈哈 | |
listen(el, arg, handler, modifers) | |
} |
// 文件 ./src/utils.ts | |
export const listen = ( | |
el: Element, | |
event: string, | |
handler: any, | |
opotions?: any | |
) => {el.addEventListener(event, handler, options) | |
} |
总结
当初咱们曾经理解了 v-bind
和v-on
的工作原理,前面咱们一起看看 v-modal
吧!
正文完
发表至: javascript
2022-03-11