MVVM
(ModelView viewmodel)是一种基于MVC的设计,开发人员在HTML上写一些Bindings,利用一些指令绑定,就能在Model和viewmodel保持不变的情况下,很方便的将UI设计与业务逻辑分离,从而大大的减少繁琐的DOM操作。
关于实现MVVM,网上实在是太多了,本文为个人总结,结合源码以及一些别人的实现
关于双向绑定
•vue 数据劫持 + 订阅 - 发布 •ng 脏值检查 •backbone.js 订阅-发布(这个没有使用过,并不是主流的用法)
双向绑定,从最基本的实现来说,就是在defineProperty绑定的基础上在绑定input事件,达到v-model的功能
代码思路图
两个版本:
•简单版本: 非常简单,但是因为是es6,并且代码极度简化,所以不谈功能,思路还是很清晰的 •标准版本: 参照了Vue的部分源码,代码的功能高度向上抽取,阅读稍微有点困难,实现了基本的功能,包括计算属性,watch,核心功能都实现没问题,但是不支持数组
简单版本
简单版本的地址: 简单版本
这个MVVM也许代码逻辑上面实现的并不完美,并不是正统的MVVM, 但是代码很精简,相对于源码,要好理解很多,并且实现了v-model以及v-on methods的功能,代码非常少,就100多行
{ // 键盘事件触发
this[value] = e.target.value
})
this.target = new Watcher(node, 'input') // 储存到订阅者
this[value] // get一下,将 this.target 给调度员
}
if (attr.name == "@click") {
let value = attr.value // 获取点击事件名
node.addEventListener('click',
this.methods[value].bind(this)
)
}
}
}
if (node.nodeType === 3) { // 文本节点返回3
let reg = /\{\{(.*)\}\}/; //匹配 {{ }}
let match = node.nodeValue.match(reg)
if (match) { // 匹配都就获取{{}}里面的变量
const value = match[1].trim()
this.target = new Watcher(node, 'text')
this[value] = this[value] // get set更新一下数据
}
}
}
}
}
//调度员 > 调度订阅发布
class Dispatcher {
constructor() {
this.watchers = []
}
add(watcher) {
this.watchers.push(watcher) // 将指令解析器解析的数据节点的订阅者存储进来,便于订阅
}
notify(newValue) {
this.watchers.map(watcher => watcher.update(newValue))
// 有数据发生,也就是触发set事件,notify事件就会将新的data交给订阅者,订阅者负责更新
}
}
//订阅发布者 MVVM核心
class Watcher {
constructor(node, type) {
this.node = node
this.type = type
}
update(value) {
if (this.type === 'input') {
this.node.value = value // 更新的数据通过订阅者发布到dom
}
if (this.type === 'text') {
this.node.nodeValue = value
}
}
}
<Meta charset="UTF-8">
<Meta name="viewport" content="width=device-width, initial-scale=1.0">
<Meta http-equiv="X-UA-Compatible" content="ie=edge">
MVVM