Vue.js source code analysis (xv) Instructions v-bind Detailed instructions

Vue.js template instruction is one of the most frequently used functions, it is prefixed V-, such as the above said v-if, v-html, v-pre like. The main responsibilities of command is that when changing the value of its expression, the corresponding certain behaviors to the DOM, first introduced v-bind command

v-bind dynamically bind to one or more characteristics, or a prop assembly to the expression.

E.g:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <title>Document</title>    
</head>
<body>
    <div id="app"><a v-bind:href="href">链接</a></div>
    <script>
    Vue.config.productionTip=false;
    Vue.config.devtools=false;
    var app = new Vue({
        el:'#app',
        data:{href:"http://www.baidu.com"}
    })
    </script> 
</body>
</html>

Rendered as:

When we click on a hyperlink will jump to the entire http://www.baidu.com, if the input app.href = "http://www.taobao.com" in the console:

Click the button after the jump to Taobao

 

Source code analysis


 In the above example, for example, internal parsed into a DOM Vue AST when the object performs the parse () function, which is parsed into a node to perform processElement () function, the first function key, ref, slot, after the class and parse style executes processAttrs () function, as follows:

function processAttrs (EL) {     // line 9526 pairs remaining attributes analyzed 
  var List = el.attrsList;
   var I, L, name, rawName, value, modifiers, isProp; 
   for (I = 0, L = List.length ; I <L; I ++) {               // iterate each attribute 
    name = rawName = List [I] .name; 
    value = List [I] .Value;
     IF (dirRE.test (name)) {                                 // if the property to v -, @ or: at the beginning, that this is an internal command Vue 
      // Mark AS Dynamic Element 
      el.hasBindings = to true ;
       // modifiers
      = parseModifiers modifiers (name);                      // Get modifier, such as: {Native: to true, Prevent: to true} 
      IF (modifiers) { 
        name = name.replace (modifierRE, '' ); 
      } 
      IF (bindRE.test (name) ) { // v-bind // bindRD equal to / ^: | ^ v-bind : /, i.e., the property is, for example, v-bind instructions: <a :href="url"> Hello </a> 
        name = name.replace (bindRE, '');                           // remove command characteristic, obtaining a characteristic name, such as the href 
        value = parseFilters (value);                               // for some analytical expressions do, for example A {| func1 |} func2 
        isProp = to false ;                                            //Is bound to the DOM object 
        IF (modifiers) {
           IF (modifiers.prop) {                                    // if modifier 
            isProp = to true ; 
            name = camelize (name);
             IF (name === 'innerHtml') {name = ' the innerHTML ' ;} 
          } 
          IF (modifiers.camel) { 
            name = camelize (name); 
          } 
          IF (modifiers.sync) { 
            addHandler ( 
              EL, 
              ( "Update:" + (camelize (name))), 
              genAssignmentCode (value,"$event")
            );
          }
        }
        if (isProp || (
          !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name)    //如果isProp为true
        )) {                                                                            //则调用addProp()
          addProp(el, name, value);
        } else {
          addAttr(el, name, value);                                               //否则调用addAttr()
        }
      } else if (onRE.test(name)) { //v-on // onRE equal to / ^ @ | ^ v-on : /, i.e. the property is a v-on instruction 
        name = name.replace (onRE, '' ); 
        addHandler (EL, name, value, modifiers, to false , The warn $ 2 ); 
      } the else { // normal directives // generic command 
        name = name.replace (dirRE, '' );
         // the parse Arg 
        var argMatch = name.match (argRE);
         var Arg = argMatch && argMatch [. 1 ];
         IF (Arg) { 
          name = name.slice (0, - (+ arg.length. 1 )); 
        }
        addDirective(el, name, rawName, value, arg, modifiers);
        if ("development" !== 'production' && name === 'model') {
          checkForAliasModel(el, value);
        }
      }
    } else {
      /**/
    }
  }
}

addAttr () function is used to add a attrs AST property on the object, as follows:

function addAttr (EL, name, value) {     // line 6550 
  . (el.attrs || (el.attrs = [])) Push ({name: name, value: value});      // The {name: name, value: value} to save el.attrs inside 
  el.plain = to false ;                                                       // correction is el.plain to false 
}

AST corresponding to the object when performed as in the example here:

Performing generate () function to get data $ 2 determines whether there attrs when attributes, if there will be saved to the property attrs, rendering the examples in examples render function is equal to:

  if (el.attrs) {     //第10306行
    data += "attrs:{" + (genProps(el.attrs)) + "},";
  }

 genProps value corresponding to piece together, as follows:

function genProps (The props) {      // line 10537 patchwork properties or DOM object properties with AST 
  var RES = '' ;   
   for ( var I = 0; I <props.length; I ++) {     // iterate PRPs 
    var prop = the props [I];                          // value corresponding to the 
    / * Istanbul the ignore IF * / 
    { 
      RES + = "\" "+ (prop.name) +" \ ":" + (transformSpecialNewlines (prop.value)) + "," ;    // put together the string 
    } 
  } 
  return res.slice (0, -1 ) 
}

Examples here performs rendering render function is equal to:

with(this) {
    return _c('div', {
        attrs: {
            "id": "app"
        }
    },
    [_c('a', {
        attrs: {
            "href": href
        }
    },
    [_v("链接")])])
}

So that when the function is executed it will trigger the href attribute Vue instance, in which case it will be rendered as a watcher subscribers href attribute, and when href changes will trigger re-rendering of the rendering watcher.

Finally, when a label is generated throughout the DOM element will create a trigger event attrs module to set the href attribute , as follows:

function updateAttrs (oldVnode, the vnode) {       // first row 6294 updates attrs 
  var the opts = vnode.componentOptions;                                       // Get vnode.componentOptions (component only) 
  IF (isDef (the opts) && opts.Ctor.options.inheritAttrs === to false ) {
     return 
  } 
  IF (isUndef (oldVnode.data.attrs) && isUndef (vnode.data.attrs)) {         // if the vnode is not defined and oldVnode attrs attribute 
    return                                                                      // directly returns without processing 
  }
   var Key, CUR, Old;
   var ELM = vnode.elm;
   var oldAttrs oldVnode.data.attrs || = {};
  var attrs vnode.data.attrs || = {};                              // new VNode properties of attrs 
  // clone Observed Objects, AS The User Probably Wants to a mutate IT 
  IF (isDef (attrs .__ ob__)) { 
    attrs = vnode.data. = attrs Extend ({}, attrs); 
  } 

  for (Key in attrs) {                                             // each new traversal attrs VNode the 
    CUR = attrs [Key]; 
    Old = oldAttrs [Key];
     IF (! == Old CUR) { 
      setAttr (ELM, Key, CUR);                                      // the call set properties setAttr 
    }
  }
  // #4391: in IE9, setting type can reset value for input[type=radio]
  // #6666: IE/Edge forces progress value down to 1 before setting a max
  /* istanbul ignore if */
  if ((isIE || isEdge) && attrs.value !== oldAttrs.value) {       //IE9的特殊情况
    setAttr(elm, 'value', attrs.value);
  }
  for (key in oldAttrs) {
    if (isUndef(attrs[key])) {
      if (isXlink(key)) {
        elm.removeAttributeNS(xlinkNS, getXlinkProp(key));
      } else if (!isEnumeratedAttr(key)) {
        elm.removeAttribute (key); 
      } 
    } 
  } 
} 

function setAttr (el, key, value) {          // set el key element attribute value 
  IF (el.tagName.indexOf ( '-')> -1) {             // If the label contains the name of the el - 
    baseSetAttr (el, key, value); 
  } the else  IF (isBooleanAttr (key)) {                 // if the key is a boolean variable (for example: Disabled, Selected) 
    // SET attribute for blank value 
    // EG <Option Disabled> the Select One </ Option> 
    IF (isFalsyAttrValue (value)) { 
      el.removeAttribute (Key); 
    } the else {
      // technically allowfullscreen is a boolean attribute for <iframe>,
      // but Flash expects a value of "true" when used on <embed> tag
      value = key === 'allowfullscreen' && el.tagName === 'EMBED'
        ? 'true'
        : key;
      el.setAttribute(key, value);
    }
  } else if (isEnumeratedAttr(key)) {             //如果key是这三个之一:contenteditable,draggable,spellcheck
    el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true');
  } else if (isXlink(key)) {
    if (isFalsyAttrValue(value)) {
      el.removeAttributeNS (xlinkNS, getXlinkProp (Key)); 
    } the else { 
      el.setAttributeNS (xlinkNS, Key, value); 
    } 
  } the else {                                           // does not satisfy the conditions set attributes directly call baseSetAttr 
    baseSetAttr (el, key, value ); 
  } 
} 

function baseSetAttr (el, key, value) {          // set of key attribute el value 
  IF (isFalsyAttrValue (value)) {                   // If the value is null or to false 
    el.removeAttribute (key);                        // delete the properties 
  } the else { 
     // #7138: IE10 & 11 fires input event when setting placeholder on
    // <textarea>... block the first input event and remove the blocker
    // immediately.
    /* istanbul ignore if */
    if ( 
      isIE && !isIE9 &&
      el.tagName === 'TEXTAREA' &&
      key === 'placeholder' && !el.__ieph
    ) {                                         特殊情况 
      var blocker = function (e) {
        e.stopImmediatePropagation();
        el.removeEventListener('input', blocker);
      };
      el.addEventListener('INPUT' , Blocker);
       // $ disable-Line Flow- 
      EL .__ = IEPH to true ; / * IEs Patched placeholder * / 
    } 
    el.setAttribute (Key, value);                     // Direct call attribute setting native DOMAPI setAttribute 
  } 
}

Guess you like

Origin www.cnblogs.com/greatdesert/p/11104024.html