compile.js 3.9 KB

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