(Still 054) Vue_ template parsing source code analysis _ _ event instruction

 Command analysis, in two ways:

1. event instruction;

2. General instructions;

==========================================

_ 04 _ template parsing event instruction .html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_模板解析_事件指令_my</title>
</head>
<body>
<div id="test">
<p>{{name}}</p>
<button v-on:click="show">提示</button>
</div>

<script type="text/javascript" src="js/mvvm/compile.js"></script>
<script type="text/javascript" src="js/mvvm/mvvm.js"></script>
<script type="text/javascript" src="js/mvvm/observer.js"></script>
<script type="text/javascript" src="js/mvvm/watcher.js"></script> Methods: { }, name: 'Zhao: Wu Nai Changshan also hero' Data: { EL: '# Test', new new the MVVM ({
<Script type = "text / JavaScript">






Show () {
Alert (this.name)
}
}
})

</ Script>
</ body>
</ HTML>
======================== ================================================== ============
L browser debugging js used
compile.js
the Compile function (el, vm) { 
// save vm
the this $ vm = vm;.
// save el elements
the this $ el = this.isElementNode (el) el:.? document.querySelector (el);
// if el element presence
IF (the this $ el.) {
// el 1. remove all child nodes, encapsulated in a subject framgment
the this $ = this.node2Fragment fragment (the this $ el.);.
// 2. compile all levels fragment child node
this.init ();
// add to el 3. the fragment of
the this el.appendChild $ ($ the this fragment.);.
}
}

Compile.prototype = {
node2Fragment: function (el) {
var = Document fragment. createDocumentFragment (),
Child;

// the native nodes to copy the fragment
the while (Child = el.firstChild) {
fragment.appendChild (Child);
}

return the fragment;
},

the init: function () {
// compiling the fragment
this.compileElement ($ the this the fragment.);
},

compileElement: function (EL) {
// get all child nodes
var childNodes el.childNodes =,
// save compile the object
Me = the this;
// loop through all child nodes
[] .slice.call (the childNodes) .forEach (function (node) {
// get the textual content of the node
var text = node.textContent ;
// canonical objects (braces expression matching)
var REG = /\{\{(.*)\}\}/; {name}} // {
// if element node
if (me.isElementNode (node )) {
// attributes compiled instruction element node
me.compile (node);
// If the node is a text expression format brace
} the else IF (me.isTextNode (Node) && reg.test (text)) {
// braces compiled expression format text node
me.compileText (node, RegExp .. $ 1); // RegExp $ 1: expression name
}
// If there is a child node child node
IF (node.childNodes && node.childNodes.length) {
// recursive call to implement compile all levels of nodes
me.compileElement ( node);
}
});
},

the compile: function (node) {
// get all tag attribute nodes
var nodeAttrs = node.attributes,
Me = the this;
// iterate through all attributes
[] .slice.call (nodeAttrs) .forEach (function (attr) {
// get property name: V-ON: the Click
var attrName = attr.name;
// determines whether an instruction attribute (whether a V-)
IF (me.isDirective (attrName)) {
: // obtain Expression (attribute values) Test
; var = exp attr.value
the Click: // instructed name: ON
; var attrName.substring the dir = (2)
// Analyzing whether the event instruction (whether it is on the beginning)
iF (me.isEventDirective (dir)) {
// event analysis processing instruction
      // node-- node, me $ vm -. vm, exp-- expression, dir-- instruction name on: click
        compileUtil.eventHandler (Node, Me $ VM, exp, the dir.); 
// generic command
} the else {
// parse generic command
compileUtil [the dir] && compileUtil [the dir] (. Node, Me $ VM, exp);
}

/ / removal instruction attribute
node.removeAttribute (attrName);
}
});
},

compileText: function (Node, exp) {
// parse the object to invoke the compiler tool
compileUtil.text (Node, the this $ VM, exp);.
},

isDirective: function (attr) {
return attr.indexOf ( 'V-') == 0;
},

isEventDirective: function (the dir) {
return dir.indexOf ( 'ON') === 0;
},

isElementNode: function ( node) {
return node.nodeType == 1;
},

isTextNode: function (node) {
return node.nodeType == 3;
}
};

// 指令处理集合
var compileUtil = {
// 解析: v-text/{{}}
text: function (node, vm, exp) {
this.bind(node, vm, exp, 'text');
},
// 解析: v-html
html: function (node, vm, exp) {
this.bind(node, vm, exp, 'html');
},

// 解析: v-model
model: function (node, vm, exp) {
this.bind(node, vm, exp, 'model');

var me = this,
val = this._getVMVal(vm, exp);
node.addEventListener('input', function (e) {
var newValue = e.target.value;
IF (Val === newValue) {
return;
}

me._setVMVal (VM, exp, newValue);
Val = newValue;
});
},

// Analytical: class V-
class: function (Node, VM, exp) {
this.bind (Node, VM, exp, 'class');
},

a method for parsing instructions true //
the bind: function (Node, VM, exp, the dir) {
/ * initialize the display implemented * /
// accordance with an instruction name (text) corresponding to the obtained node update function
var updaterFn Updater = [the dir + 'Updater'];
// update the node if the call is present to
updaterFn && updaterFn (node, this._getVMVal (VM, exp));

// Create expression type objects corresponding watcher
new Watcher (vm, exp, function (value, oldValue) {/ * update interface * /
// when the corresponding attribute value is changed, the automatic call, updates the corresponding node
&& updaterFn updaterFn (Node, value, oldValue);
});
},

// event handling
eventHandler: function (Node, VM, exp, the dir) {
// get the event name / Type: the Click
var dir.split the eventType = ( ' : ') [1],
// methods obtained from the corresponding expressions function (event callback function)
options.methods && VM VM $ $ options.methods Fn = [exp];..
// if there
if ( && the Fn eventType) {
// bind the specified event name and DOM event listener callback function, the callback function of this binding is forced vm
node.addEventListener (eventType, fn.bind (vm), false);
}
},

/ / obtain expression of the corresponding value
_getVMVal: function (VM, exp) {
var = Val vm._data;
exp = exp.split ( '.');
exp.forEach (function (K) {
Val Val = [K];
});
Return Val;
},

_setVMVal: function (VM, exp, value) {
var = Val vm._data;
exp = exp.split (); '.'
Exp.forEach (function (K, I) {
// not the last key, updates the value of val
IF (I <exp.length -. 1) {
val val = [K];
} the else {
val [K] = value;
}
});
}
};

// comprises a plurality of a method to update the node object
var Updater = {
// update node textContent
textUpdater: function (node, value) {
node.textContent = typeof value == 'undefined' '':? value;
},

// update the node's innerHTML
htmlUpdater: function (node, value) {
node.innerHTML = typeof value == 'undefined' ? '' : value;
},

// 更新节点的className
classUpdater: function (node, value, oldValue) {
var className = node.className;
className = className.replace(oldValue, '').replace(/\s$/, '');

var space = className && String(value) ? ' ' : '';

node.className = className + space + value;
},

// 更新节点的value
modelUpdater: function (node, value, oldValue) {
node.value = typeof value == 'undefined' ? '' : value;
}
};
================================================== ===================================== 
summary:
Template parsing (2): Event command parsing
1) Remove the name of the event from the instruction name - (click)
2) to give the corresponding event handler methods based on the value from the target instruction (expression) - (show)    
3) to the current element node binding specifies the name of the event and the event listener callback function dom   
4) After the command analysis, the instruction property removed


Guess you like

Origin www.cnblogs.com/curedfisher/p/12315743.html