vue源碼分析(二十五)Vue之指令(v-bind)

我們先打開文件src\compiler\parser

function processAttrs (el) {
  const list = el.attrsList
  let i, l, name, rawName, value, modifiers, syncGen, isDynamic
  for (i = 0, l = list.length; i < l; i++) {
    name = rawName = list[i].name
    value = list[i].value
    if (dirRE.test(name)) {
      // mark element as dynamic
      el.hasBindings = true
      // modifiers
      modifiers = parseModifiers(name.replace(dirRE, ''))
      // support .foo shorthand syntax for the .prop modifier
      if (process.env.VBIND_PROP_SHORTHAND && propBindRE.test(name)) {
        (modifiers || (modifiers = {})).prop = true
        name = `.` + name.slice(1).replace(modifierRE, '')
      } else if (modifiers) {
        name = name.replace(modifierRE, '')
      }
      if (bindRE.test(name)) { // v-bind
        name = name.replace(bindRE, '')
        value = parseFilters(value)
        isDynamic = dynamicArgRE.test(name)
        if (isDynamic) {
          name = name.slice(1, -1)
        }
        if (
          process.env.NODE_ENV !== 'production' &&
          value.trim().length === 0
        ) {
          warn(
            `The value for a v-bind expression cannot be empty. Found in "v-bind:${name}"`
          )
        }
        if (modifiers) {
          if (modifiers.prop && !isDynamic) {
            name = camelize(name)
            if (name === 'innerHtml') name = 'innerHTML'
          }
          if (modifiers.camel && !isDynamic) {
            name = camelize(name)
          }
          if (modifiers.sync) {
            syncGen = genAssignmentCode(value, `$event`)
            if (!isDynamic) {
              addHandler( el, `update:${camelize(name)}`,  syncGen, null, false, warn,  list[i] )
              if (hyphenate(name) !== camelize(name)) {
                addHandler( el,  `update:${hyphenate(name)}`, syncGen, null, false, warn,  list[i] )
              }
            } else {
              // handler w/ dynamic event name
               addHandler( el,  `"update:"+(${name})`, syncGen, null, false, warn, list[i], true // dynamic )
            }
          }
        }
        if ((modifiers && modifiers.prop) || (
          !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name)
        )) {
          addProp(el, name, value, list[i], isDynamic)
        } else {
          addAttr(el, name, value, list[i], isDynamic)
        }
      } else if (onRE.test(name)) { // v-on
        name = name.replace(onRE, '')
        isDynamic = dynamicArgRE.test(name)
        if (isDynamic) {
          name = name.slice(1, -1)
        }
        addHandler(el, name, value, modifiers, false, warn, list[i], isDynamic)
      } else { // normal directives
        name = name.replace(dirRE, '')
        // parse arg
        const argMatch = name.match(argRE)
        let arg = argMatch && argMatch[1]
        isDynamic = false
        if (arg) {
          name = name.slice(0, -(arg.length + 1))
          if (dynamicArgRE.test(arg)) {
            arg = arg.slice(1, -1)
            isDynamic = true
          }
        }
        addDirective(el, name, rawName, value, arg, isDynamic, modifiers, list[i])
        if (process.env.NODE_ENV !== 'production' && name === 'model') {
          checkForAliasModel(el, value)
        }
      }
    } else {
      // literal attribute
      if (process.env.NODE_ENV !== 'production') {
        const res = parseText(value, delimiters)
        if (res) {
          warn(
            `${name}="${value}": ` +
            'Interpolation inside attributes has been removed. ' +
            'Use v-bind or the colon shorthand instead. For example, ' +
            'instead of <div id="{{ val }}">, use <div :id="val">.',
            list[i]
          )
        }
      }
      addAttr(el, name, JSON.stringify(value), list[i])
      // #6887 firefox doesn't update muted state if set via attribute
      // even immediately after element creation
      if (!el.component &&
          name === 'muted' &&
          platformMustUseProp(el.tag, el.attrsMap.type, name)) {
        addProp(el, name, 'true', list[i])
      }
    }
  }
}

在調用processAttrs函數之前已經調用過模板解析了,el參數的結構如下:


image.png

可以看到el.attrsList的結構包含了所有DOM節點上的屬性,而不僅僅限于通過vue指令綁定的。

image.png

dirRE.test(name)

可以看到接下來就就會遇到dirRE(/^v-|^@|^:|^#/)正則來匹配,我們這里是主要匹配 v-開頭或者 : 開頭。

  // 檢查是否存在修飾符
  modifiers = parseModifiers(name.replace(dirRE, ''))
  // support .foo shorthand syntax for the .prop modifier
  if (process.env.VBIND_PROP_SHORTHAND && propBindRE.test(name)) {
     (modifiers || (modifiers = {})).prop = true
     name = `.` + name.slice(1).replace(modifierRE, '')
   } else if (modifiers) {
     name = name.replace(modifierRE, '') //清空修飾符
   }

緊接著又會來查找指令上面是否有修飾符,在bind指令上面修飾符,比較少,一般是在v-on上面比較多,比如:
.stop 阻止單擊事件繼續傳播
.prevent // 阻止默認行為
.capture // 事件捕獲
.self//捕獲本身的事件
.once//一次性事件

if (bindRE.test(name)) { // v-bind
  // 去掉“:”或者“v-bind:”指令(例子中是把“:title”變成title“”)
   name = name.replace(bindRE, '')
  // 格式解析,bind綁定可以通過單引號'、雙引號"、字符串模板``、大括號()、中括號[]
   value = parseFilters(value)
   // dynamicArgRE /^\[.*\]$/ 匹配大括號里面的任何字符串
   isDynamic = dynamicArgRE.test(name)
   if (isDynamic) {
      name = name.slice(1, -1)
    }
        if ( process.env.NODE_ENV !== 'production' && value.trim().length === 0 ) {
          warn(
            `The value for a v-bind expression cannot be empty. Found in "v-bind:${name}"`
          )
        }
        if (modifiers) {
          if (modifiers.prop && !isDynamic) {
            name = camelize(name)
            if (name === 'innerHtml') name = 'innerHTML'
          }
          if (modifiers.camel && !isDynamic) {
            name = camelize(name)
          }
          if (modifiers.sync) {
            syncGen = genAssignmentCode(value, `$event`)
            if (!isDynamic) {
              addHandler( el, `update:${camelize(name)}`,  syncGen, null, false, warn,  list[i] )
              if (hyphenate(name) !== camelize(name)) {
                addHandler( el,  `update:${hyphenate(name)}`, syncGen, null, false, warn,  list[i] )
              }
            } else {
              // handler w/ dynamic event name
              addHandler( el,  `"update:"+(${name})`, syncGen, null, false, warn, list[i], true // dynamic )
            }
          }
        }
        if ((modifiers && modifiers.prop) || (
          !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name)
        )) {
          addProp(el, name, value, list[i], isDynamic)
        } else {
         // 給el對象的attr屬性添加
          addAttr(el, name, value, list[i], isDynamic)
        }
      }

以上代碼就是處理v-bind指令的了,通過上面的分析我們看到所有的屬性不管是否通過vue指令綁定的屬性都是在內部的attrs數組里面。

bind綁定可以通過單引號'、雙引號"、字符串模板``、大括號()、中括號[]

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Vue 實例 屬性和方法 每個 Vue 實例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,241評論 0 6
  • 第一章 Vue概述 what? Vue是實現UI層的漸進式js框架,核心庫關注視圖層,簡單的ui構建,復雜的路由控...
    fastwe閱讀 742評論 0 0
  • 什么是指令 官方解釋: 指令 (Directives) 是帶有 v- 前綴的特殊 attribute。指令 att...
    仰望_IT閱讀 315評論 0 0
  • 1概述 上一章我們說了Vue是用于構建用戶界面的框架,它最終呈現給用戶的是一個一個HTML標簽。Vue可以使用HT...
    書上得來終覺淺閱讀 530評論 1 0
  • 大家都知道蝴蝶效應,一只蝴蝶輕輕扇動翅膀就可以帶來一場颶風。 雖然我們每一個人相對于宇宙來說,都像一粒塵埃一樣微不...
    趕緊去做閱讀 219評論 0 1