compile(编译) 的实现
首先遍历解析的过程有多次操作 dom 节点,为提高性能和效率,会先将跟节点 el 转换成 fragment(文档碎片) 进行解析编译,解析完成,再将 fragment 添加回原来的真实 dom 节点中。代码如下:
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) // 将节点转为 fragment 文档碎片
this.compileElement(this.fragment) // 对 fragment 进行编译解析
this.el.appendChild(this.fragment)
}
},
nodeToFragment: function(el) {
const fragment = document.createDocumentFragment()
let child = el.firstChild // △ 第一个 firstChild 是 text
while(child) {
fragment.appendChild(child)
child = el.firstChild
}
return fragment
},
compileElement: function(el) {...},
}
这个简单的 mvvm 框架在对 fragment 编译解析的过程中对 {{}} 文本元素、v-on:click 事件指令、v-model 指令三种类型进行了相应的处理。
Compile.prototype = {
init: function() {
if (this.el) {
this.fragment = this.nodeToFragment(this.el) // 将节点转为 fragment 文档碎片
this.compileElement(this.fragment) // 对 fragment 进行编译解析
this.el.appendChild(this.fragment)
}
},
nodeToFragment: function(el) {...},
compileElement: function(el) {...},
compileText: function (node, exp) { // 对文本类型进行处理,将 {{abc}} 替换掉
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) { // 对 v-model 进行处理
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 // 实现 view 到 model 的绑定
})
},
}
在上述代码的 compileTest 函数中看到了期盼已久的 Watcher 实例化,对 Watcher 作用模糊的朋友可以往上回顾下 Watcher 的作用。另外在 compileModel 函数中看到了本文最开始提到的双向绑定流中的 View 到 Model 是借助 input 监听事件变化实现的。
项目地址
本文记录了些阅读 mvvm 框架源码关于双向绑定的心得,并动手实践了一个简版的 mvvm 框架,不足之处在所难免,欢迎指正。
项目演示
项目地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持黑区网络。

