聊聊MVVM框架
MVVM的定义
本质是数据驱动
- Model:可以理解为服务端数据或数据库的model,用于给客户端发送数据
- View:可以理解为页面,用户看到的界面
- ViewModel:连接view和model的桥梁,可以理解为Vue这类型的框架,通常接受Model发送的数据然后经过ViewModel类框架处理自动渲染到View层,View层也能通过用户操作经过ViewModel处理再发送给服务端进行存储。
与MVC的不同
MVC中Model与View与上述一样
Controller:理解为处理用户交互的部分,包括页面展示、调用接口等业务逻辑。
- 最直观的区别就是ViewModel实现了Model和View直接数据的自动同步,我们再也不需要频繁的操作DOM来现实View。
- 之前MVC的手动频繁操作DOM会使页面渲染性能降低。MVVM可以比较好的解决这一点问题。
- VM并不是完全的取代C,只是取代了操作DOM展示View的方面,该写的业务逻辑还是要写的。
双向绑定的原理及手写
双向绑定的原理是通过 数据劫持+观察者模式 来实现的。
- 操作ViewModel的data对象,会自动更新View,原理通过Object。defineProperty
- 用户操作View,会自动更新data对象,原理是通过input事件
// 手写一个双向数据绑定
<input type="text" id="input">
<div id="text"></div>
var input = document.getElementById('input')
var text = document.getElementById('text')
var data = {
value: ''
}
Object.defineProperty(data, 'value', {
configurable: true,
enumerable: true,
set: function(val) {
text.innerHTML = val // 更新view
input.value = val
},
get: function() {
return data.value
}
})
input.onkeyup = function(e) {
data.value = e.target.value
}
设计模式-观察者模式
观察者模式就是当一个对象(目标)被修改时,则会自动通知依赖它的所有对象(观察者)。
- dep:发布者
- watcher:观察者(订阅者)
// 发布者
class Dep {
constructor() {
this.subs = [] // 观察者列表
}
addSub(sub) {
this.subs.push(sub) // 添加观察者
}
notify() {
// 通知所有观察者调用update方法
this.subs.forEach(sub => {
sub.update()
})
}
}
// 观察者(订阅者)
class Watcher {
constructor(cb) {
this.cb = cb // 回调函数
}
update() {
this.cb && this.cb()
}
}
var dep = new Dep()
var watcher1 = new Watcher(function(){console.log('watcher1');})
var watcher2 = new Watcher(function(){console.log('watcher2');})
dep.addSub(watcher1)
dep.addSub(watcher2)
dep.notify()
生命周期
mvvm类框架在生命周期定义中大致是相同的,以vue的生命周期为例
- beforeCreate:初始化实例阶段,还不能访问data、props、computed、watch、methods这些数据。
- created:能访问data、props、computed、watch、methods数据,但不能访问dom,但通常可以在这个阶段请求数据。
- beforeMount:这是一个过渡阶段,模板已经编译好了,但是还未挂载到到页面。
- mounted:表示vue整个初始化阶段已经完成,进入运行时阶段,可以访问dom。
- beforeUpdate:此时date数据是最新的,但页面是旧的,页面尚未和最新数据数据保持同步。可在更新前访问现有的DOM,如手动移出添加的事件监听器。
- updated:完成虚拟dom的重新渲染。注意:不要在此函数中操作数据(修改属性),否则就会陷入死循环。
- beforeDestroy:Vue实例就已经从运行阶段进入到销毁阶段了。实例上的所有data和methods以及过滤器和指令都是处于可用状态,此时还没有真正的执行销毁过程,通常可以在这个阶段移除事件监听器。
- destroyed:当执行到destroted函数的时候,组件已经完全销毁,此时组件中的所有的数据,方法,指令,过滤器...都已经销毁,不可用了。
实现框架
以vue框架为例