compile.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. function Compile(el, vm) {
  2. this.$vm = vm;
  3. this.$el = this.isElementNode(el) ? el : document.querySelector(el);
  4. if (this.$el) {
  5. this.$fragment = this.node2Fragment(this.$el);
  6. this.init();
  7. this.$el.appendChild(this.$fragment);
  8. }
  9. }
  10. Compile.prototype = {
  11. node2Fragment: function(el) {
  12. var fragment = document.createDocumentFragment(),
  13. child;
  14. // 将原生节点拷贝到fragment
  15. while (child = el.firstChild) {
  16. fragment.appendChild(child);
  17. }
  18. return fragment;
  19. },
  20. init: function() {
  21. this.compileElement(this.$fragment);
  22. },
  23. compileElement: function(el) {
  24. var childNodes = el.childNodes,
  25. me = this;
  26. [].slice.call(childNodes).forEach(function(node) {
  27. var text = node.textContent;
  28. var reg = /\{\{(.*)\}\}/;
  29. if (me.isElementNode(node)) {
  30. me.compile(node);
  31. } else if (me.isTextNode(node) && reg.test(text)) {
  32. me.compileText(node, RegExp.$1);
  33. }
  34. if (node.childNodes && node.childNodes.length) {
  35. me.compileElement(node);
  36. }
  37. });
  38. },
  39. compile: function(node) {
  40. var nodeAttrs = node.attributes,
  41. me = this;
  42. [].slice.call(nodeAttrs).forEach(function(attr) {
  43. var attrName = attr.name;
  44. if (me.isDirective(attrName)) {
  45. var exp = attr.value;
  46. var dir = attrName.substring(2);
  47. // 事件指令
  48. if (me.isEventDirective(dir)) {
  49. compileUtil.eventHandler(node, me.$vm, exp, dir);
  50. // 普通指令
  51. } else {
  52. compileUtil[dir] && compileUtil[dir](node, me.$vm, exp);
  53. }
  54. node.removeAttribute(attrName);
  55. }
  56. });
  57. },
  58. compileText: function(node, exp) {
  59. compileUtil.text(node, this.$vm, exp);
  60. },
  61. isDirective: function(attr) {
  62. return attr.indexOf('v-') == 0;
  63. },
  64. isEventDirective: function(dir) {
  65. return dir.indexOf('on') === 0;
  66. },
  67. isElementNode: function(node) {
  68. return node.nodeType == 1;
  69. },
  70. isTextNode: function(node) {
  71. return node.nodeType == 3;
  72. }
  73. };
  74. // 指令处理集合
  75. var compileUtil = {
  76. text: function(node, vm, exp) {
  77. this.bind(node, vm, exp, 'text');
  78. },
  79. html: function(node, vm, exp) {
  80. this.bind(node, vm, exp, 'html');
  81. },
  82. model: function(node, vm, exp) {
  83. this.bind(node, vm, exp, 'model');
  84. var me = this,
  85. val = this._getVMVal(vm, exp);
  86. node.addEventListener('input', function(e) {
  87. var newValue = e.target.value;
  88. if (val === newValue) {
  89. return;
  90. }
  91. me._setVMVal(vm, exp, newValue);
  92. val = newValue;
  93. });
  94. },
  95. class: function(node, vm, exp) {
  96. this.bind(node, vm, exp, 'class');
  97. },
  98. bind: function(node, vm, exp, dir) {
  99. var updaterFn = updater[dir + 'Updater'];
  100. updaterFn && updaterFn(node, this._getVMVal(vm, exp));
  101. new Watcher(vm, exp, function(value, oldValue) {
  102. updaterFn && updaterFn(node, value, oldValue);
  103. });
  104. },
  105. // 事件处理
  106. eventHandler: function(node, vm, exp, dir) {
  107. var eventType = dir.split(':')[1],
  108. fn = vm.$options.methods && vm.$options.methods[exp];
  109. if (eventType && fn) {
  110. node.addEventListener(eventType, fn.bind(vm), false);
  111. }
  112. },
  113. _getVMVal: function(vm, exp) {
  114. var val = vm;
  115. exp = exp.split('.');
  116. exp.forEach(function(k) {
  117. val = val[k];
  118. });
  119. return val;
  120. },
  121. _setVMVal: function(vm, exp, value) {
  122. var val = vm;
  123. exp = exp.split('.');
  124. exp.forEach(function(k, i) {
  125. // 非最后一个key,更新val的值
  126. if (i < exp.length - 1) {
  127. val = val[k];
  128. } else {
  129. val[k] = value;
  130. }
  131. });
  132. }
  133. };
  134. var updater = {
  135. textUpdater: function(node, value) {
  136. node.textContent = typeof value == 'undefined' ? '' : value;
  137. },
  138. htmlUpdater: function(node, value) {
  139. node.innerHTML = typeof value == 'undefined' ? '' : value;
  140. },
  141. classUpdater: function(node, value, oldValue) {
  142. var className = node.className;
  143. className = className.replace(oldValue, '').replace(/\s$/, '');
  144. var space = className && String(value) ? ' ' : '';
  145. node.className = className + space + value;
  146. },
  147. modelUpdater: function(node, value, oldValue) {
  148. node.value = typeof value == 'undefined' ? '' : value;
  149. }
  150. };