美文网首页
vue源码分析(二十五)Vue之指令(v-bind)

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

作者: vue爱好者 | 来源:发表于2020-04-21 20:54 被阅读0次

    我们先打开文件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之指令(v-bind)

          本文链接:https://www.haomeiwen.com/subject/uaqjuhtx.html