在书写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吧!
尊重原创,转载请注明来自:https://cloud.tencent.com/developer/article/1997342 肥仔John