1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| function Compile(el, vm) { this.vm = vm this.el = document.querySelector(el) this.fragment = null this.init() }
Compile.prototype = { init: function() { if (this.el) { this.fragment = this.nodeToFragment(this.el) this.compileElement(this.fragment) this.el.appendChild(this.fragment) } else { console.log('Dom元素不存在') } }, nodeToFragment: function(el) { const fragment = document.createDocumentFragment() let child = el.firstChild while(child) { fragment.appendChild(child) child = el.firstChild } return fragment }, compileElement: function(el) { const childNodes = el.childNodes const self = this Array.prototype.forEach.call(childNodes, function (node) { const reg = /\{\{(.*)\}\}/ const text = node.textContent if (self.isElementNode(node)) { self.compile(node) } else if (self.isTextNode(node) && reg.test(text)) { self.compileText(node, reg.exec(text)[1]) } if (node.childNodes && node.childNodes.length) { self.compileElement(node) } }) },
compile: function (node) { const nodeAttrs = node.attributes const self = this
Array.prototype.forEach.call(nodeAttrs, function (attr) { const attrName = attr.name const exp = attr.value const dir = attrName.substring(2) if (self.isDirective(attrName)) { if (self.isEventDirective(dir)) { self.compileEvent(node, self.vm, exp, dir) } else { self.compileModel(node, self.vm, exp) } } }) },
compileText: function (node, exp) { const self = this const initText = this.vm[exp] this.updateText(node, initText) new Watcher(this.vm, exp, function(value) { self.updateText(node, value) }) },
compileEvent: function (node, vm, exp, dir) { const eventType = dir.split(':')[1] const cb = vm.methods && vm.methods[exp]
if (eventType && cb) { node.addEventListener(eventType, cb.bind(vm), false) } },
compileModel: function (node, vm, exp) { let val = vm[exp] const self = this this.modelUpdater(node, val) node.addEventListener('input', function (e) { const newValue = e.target.value self.vm[exp] = newValue }) },
updateText: function (node, value) { node.textContent = typeof value === 'undefined' ? '' : value },
modelUpdater: function(node, value) { node.value = typeof value === 'undefined' ? '' : value },
isEventDirective: function(dir) { return dir.indexOf('on:') === 0 },
isDirective: function(attr) { return attr.indexOf('v-') === 0 },
isElementNode: function(node) { return node.nodeType === 1 },
isTextNode: function(node) { return node.nodeType === 3 } }
|