聊聊MVVM框架

MVVM的定义

本质是数据驱动

  • Model:可以理解为服务端数据或数据库的model,用于给客户端发送数据
  • View:可以理解为页面,用户看到的界面
  • ViewModel:连接view和model的桥梁,可以理解为Vue这类型的框架,通常接受Model发送的数据然后经过ViewModel类框架处理自动渲染到View层,View层也能通过用户操作经过ViewModel处理再发送给服务端进行存储。

mvvm图

与MVC的不同

MVC中Model与View与上述一样
Controller:理解为处理用户交互的部分,包括页面展示、调用接口等业务逻辑。

  1. 最直观的区别就是ViewModel实现了Model和View直接数据的自动同步,我们再也不需要频繁的操作DOM来现实View。
  2. 之前MVC的手动频繁操作DOM会使页面渲染性能降低。MVVM可以比较好的解决这一点问题。
  3. VM并不是完全的取代C,只是取代了操作DOM展示View的方面,该写的业务逻辑还是要写的。

双向绑定的原理及手写

双向绑定的原理是通过 数据劫持+观察者模式 来实现的。

  1. 操作ViewModel的data对象,会自动更新View,原理通过Object。defineProperty
  2. 用户操作View,会自动更新data对象,原理是通过input事件

mvvm图

// 手写一个双向数据绑定
<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
}

设计模式-观察者模式

mvvm图

观察者模式就是当一个对象(目标)被修改时,则会自动通知依赖它的所有对象(观察者)。

  • 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框架为例

mvvm图