petite-vue源码剖析-事件绑定`v-on`的工作原理
在书写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) => 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.tsexport const listen = (
el: Element,
event: string,
handler: any,
opotions?: any
) => {
el.addEventListener(event, handler, options)
}
总结 【petite-vue源码剖析-事件绑定`v-on`的工作原理】现在我们已经了解了
v-bind
和v-on
的工作原理,后面我们一起看看v-modal
吧!推荐阅读
- 【Apollo自动驾驶源码解读】车道线的感知和高精地图融合
- 【阅读SpringMVC源码】手把手带你debug验证SpringMVC执行流程
- [源码解析]|[源码解析] NVIDIA HugeCTR,GPU 版本参数服务器 --(9)--- Local hash表
- react|react 源码中位运算符的使用详解
- Vue3|Vue3 任务调度器 scheduler 源码分析
- HAVE|HAVE FUN | SOFARegistry 源码解析
- 【官方推荐】Laravel7|【官方推荐】Laravel7 + Vue2.0前后端分离框架通用后台源码
- 读Flink源码谈设计(FileSystemConnector中的整洁架构)
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
- Vue|Vue 源码解读(12)—— patch