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 } }