petite-vue源码剖析-事件绑定`v-on`的工作原理

Posted ^_^肥仔John

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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<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)[`$mKey`] && !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-bindv-on的工作原理,后面我们一起看看v-modal吧!

以上是关于petite-vue源码剖析-事件绑定`v-on`的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

v-on事件绑定指令

Vue模板语法——事件绑定

Vue学习之路8-v-on指令学习简单事件绑定之属性

669 v-on:绑定多个事件,参数传递,修饰符

v-on 绑定单个或多个事件

Vue之DOM元素事件绑定_v-on指令