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