123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- function Compile(el, vm) {
- this.$vm = vm;
- this.$el = this.isElementNode(el) ? el : document.querySelector(el);
- if (this.$el) {
- this.$fragment = this.node2Fragment(this.$el);
- this.init();
- this.$el.appendChild(this.$fragment);
- }
- }
- Compile.prototype = {
- node2Fragment: function(el) {
- var fragment = document.createDocumentFragment(),
- child;
- // 将原生节点拷贝到fragment
- while (child = el.firstChild) {
- fragment.appendChild(child);
- }
- return fragment;
- },
- init: function() {
- this.compileElement(this.$fragment);
- },
- compileElement: function(el) {
- var childNodes = el.childNodes,
- me = this;
- [].slice.call(childNodes).forEach(function(node) {
- var text = node.textContent;
- var reg = /\{\{(.*)\}\}/;
- if (me.isElementNode(node)) {
- me.compile(node);
- } else if (me.isTextNode(node) && reg.test(text)) {
- me.compileText(node, RegExp.$1);
- }
- if (node.childNodes && node.childNodes.length) {
- me.compileElement(node);
- }
- });
- },
- compile: function(node) {
- var nodeAttrs = node.attributes,
- me = this;
- [].slice.call(nodeAttrs).forEach(function(attr) {
- var attrName = attr.name;
- if (me.isDirective(attrName)) {
- var exp = attr.value;
- var dir = attrName.substring(2);
- // 事件指令
- if (me.isEventDirective(dir)) {
- compileUtil.eventHandler(node, me.$vm, exp, dir);
- // 普通指令
- } else {
- compileUtil[dir] && compileUtil[dir](node, me.$vm, exp);
- }
- node.removeAttribute(attrName);
- }
- });
- },
- compileText: function(node, exp) {
- compileUtil.text(node, this.$vm, exp);
- },
- isDirective: function(attr) {
- return attr.indexOf('v-') == 0;
- },
- isEventDirective: function(dir) {
- return dir.indexOf('on') === 0;
- },
- isElementNode: function(node) {
- return node.nodeType == 1;
- },
- isTextNode: function(node) {
- return node.nodeType == 3;
- }
- };
- // 指令处理集合
- var compileUtil = {
- text: function(node, vm, exp) {
- this.bind(node, vm, exp, 'text');
- },
- html: function(node, vm, exp) {
- this.bind(node, vm, exp, 'html');
- },
- 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;
- });
- },
- class: function(node, vm, exp) {
- this.bind(node, vm, exp, 'class');
- },
- bind: function(node, vm, exp, dir) {
- var updaterFn = updater[dir + 'Updater'];
- updaterFn && updaterFn(node, this._getVMVal(vm, exp));
- new Watcher(vm, exp, function(value, oldValue) {
- updaterFn && updaterFn(node, value, oldValue);
- });
- },
- // 事件处理
- eventHandler: function(node, vm, exp, dir) {
- var eventType = dir.split(':')[1],
- fn = vm.$options.methods && vm.$options.methods[exp];
- if (eventType && fn) {
- node.addEventListener(eventType, fn.bind(vm), false);
- }
- },
- _getVMVal: function(vm, exp) {
- var val = vm;
- exp = exp.split('.');
- exp.forEach(function(k) {
- val = val[k];
- });
- return val;
- },
- _setVMVal: function(vm, exp, value) {
- var val = vm;
- exp = exp.split('.');
- exp.forEach(function(k, i) {
- // 非最后一个key,更新val的值
- if (i < exp.length - 1) {
- val = val[k];
- } else {
- val[k] = value;
- }
- });
- }
- };
- var updater = {
- textUpdater: function(node, value) {
- node.textContent = typeof value == 'undefined' ? '' : value;
- },
- htmlUpdater: function(node, value) {
- node.innerHTML = typeof value == 'undefined' ? '' : value;
- },
- 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;
- },
- modelUpdater: function(node, value, oldValue) {
- node.value = typeof value == 'undefined' ? '' : value;
- }
- };
|