首页>>前端>>Vue->Vue 事件原理(从源码角度带你分析)

Vue 事件原理(从源码角度带你分析)

时间:2023-11-30 本站 点击:0

事件特性我们在Vue的日常开发中经常使用,但是你了解Vue中事件的原理吗?本系列我们从源码角度,来分析Vue event的原理。

本节我们从event的编译开始吧。

event编译之parse

在之前的过程中我们分析了编译流程,其中parse流程第一步会扫描开始标签,将开始标签上的所有属性存储在match对象的attr属性数组中,然后生成初始的AST树,解析attr数组属性,丰富AST树上的内容(不清楚可以点击这里)。当处理到事件的属性解析时,会进入processAttrs函数,接下来我们来分析event的编译的parse流程:

解析事件修饰符

event的属性解析会进入processAttrs函数:

export const dirRE = /^v-|^@|^:/export const bindRE = /^:|^v-bind:/export const onRE = /^@|^v-on:/const modifierRE = /\.[^.]+/gfunction processAttrs (el) {  // 拿到match对象的attrsList(存放扫描开始标签后各种属性的地方)  const list = el.attrsList  let i, l, name, rawName, value, modifiers, isProp  // 遍历list数组  for (i = 0, l = list.length; i < l; i++) {    name = rawName = list[i].name    value = list[i].value    // 匹配(v-)(@)(:)    if (dirRE.test(name)) {      // 匹配上了      // mark element as dynamic      // 标记元素节点为动态节点      el.hasBindings = true      // modifiers      // 解析修饰符      modifiers = parseModifiers(name)      if (modifiers) {        // 存在修饰符,将name后面所有的修饰符去掉        name = name.replace(modifierRE, '')      }      // 匹配(:)(v-bind)      if (bindRE.test(name)) { // v-bind        ......      } else if (onRE.test(name)) { // v-on        // 匹配(v-on)(@),去掉(v-on)(@)前缀        name = name.replace(onRE, '')        // 执行addHandler函数        addHandler(el, name, value, modifiers, false, warn)      } else { // normal directives // 普通指令        ......      }    } else {      ......    }  }}

const modifierRE = /\.[^.]+/g// 匹配.function parseModifiers (name: string): Object | void {  // 修饰符解析称为数组  const match = name.match(modifierRE)  // 数组存在的话,遍历数组,(例如含有修饰符native,则将ret.native = true),返回对象ret  if (match) {    const ret = {}    match.forEach(m => { ret[m.slice(1)] = true })    return ret  }}

processAttrs函数的整体逻辑就是解析事件的修饰符,通过parseModifiers函数将修饰符全部存取进对象modifiers中,处理完成事件的修饰符后,执行addHandler函数,并将解析后的修饰符对象modifiers当做参数传入。

addHandler函数

export function addHandler (  el: ASTElement,  name: string,  value: string,  modifiers: ?ASTModifiers,  important?: boolean,  warn?: Function) {  modifiers = modifiers || emptyObject  ......  // check capture modifier  if (modifiers.capture) {    // 删除capture属性,name前添加'!'    delete modifiers.capture    name = '!' + name // mark the event as captured  }  if (modifiers.once) {    // 删除once属性,name前添加'~'    delete modifiers.once    name = '~' + name // mark the event as once  }  /* istanbul ignore if */  if (modifiers.passive) {    // 删除passive属性,name前添加'&'    delete modifiers.passive    name = '&' + name // mark the event as passive  }  // normalize click.right and click.middle since they don't actually fire  // this is technically browser-specific, but at least for now browsers are  // the only target envs that have right/middle clicks.  // 鼠标修饰符相关  if (name === 'click') {    // 普通的click    if (modifiers.right) {      // 修饰符有right属性,名称改写为contextmenu      name = 'contextmenu'      delete modifiers.right    } else if (modifiers.middle) {      // 修饰符有middle属性,名称改写为mouseup      name = 'mouseup'    }  }  let events  if (modifiers.native) {    // 修饰符有native属性,events赋值为nativeEvents    delete modifiers.native    events = el.nativeEvents || (el.nativeEvents = {})  } else {    // 修饰符没有native属性,events赋值为events    events = el.events || (el.events = {})  }  const newHandler: any = {    // value是当前事件对应的表达式    value: value.trim()  }  if (modifiers !== emptyObject) {    // 如果modifiers还不是空对象    newHandler.modifiers = modifiers  }  // 取出这个handles表达式  const handlers = events[name]  /* istanbul ignore if */  // 如果handlers是数组  if (Array.isArray(handlers)) {    // important是false,是数组直接将新值push进入当前数组    important ? handlers.unshift(newHandler) : handlers.push(newHandler)  } else if (handlers) {    // handles存在但不是数组    // important是false,生成新数组,将之前的handles与新生成的组成一个数组    events[name] = important ? [newHandler, handlers] : [handlers, newHandler]  } else {    // 直接将newHandler赋值给event    events[name] = newHandler  }  // 当前节点的plain赋值为false  el.plain = false}

addHandler函数根据事件的修饰符,对event做不同的处理,最终在当前的AST element节点上添加events对象,将处理后的handler函数丰富在events[name]中。

小结

我们清楚了在模板上定义event,经过编译后最终会在AST树上生成events(或nativeEvents)属性,下一节我们继续分析event编译的codegen过程。

原文:https://juejin.cn/post/7096277031788216351


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Vue/3778.html