一、为什么要有MVVM
在框架出现之前:
- 数据更新或视图更新之后,需要开发者主动去使用 DOM api 去修改或查询 DOM
- 同样的数据映射到不同的视图时,需要重写一套代码逻辑,复用性低
- 状态管理比较麻烦
- 大量的DOM操作使得业务逻辑繁琐冗长,代码的可维护性差
开发的痛点:视图(view)和数据(model)的绑定
- 将DOM操作隐藏,关注数据操作(Model),在数据和视图间做到同步(数据绑定和更新监听),不需要人为干预。
- 同样的数据可以方便地对应多个视图。
- 方便管理状态和路由
- 其他:
- 方便地实现视图逻辑(声明式或命令式)
- 方便地创建和连接、复用组件
二、响应式原理及思路
简单地说,view
通过DOM listener(比如输入事件)
对 model
进行绑定,model
通过Directives(指令)
与view
进行绑定。
其中在model
和view
进行绑定是采用数据劫持结合发布者-订阅者模式的方式:
- 通过
Object.defineProperty()
来劫持各个属性的setter
,getter
; - 在数据变动时发布消息给订阅者(视图),触发相应的监听回调。
具体步骤:
observer:
- 对 data 对象进行递归遍历,将所有属性都实现为存取器属性
setter/getter
- 在 getter 中将当前数据的使用者(即 watcher)加入当前数据的依赖队列
- 当给 data 对象的某个属性赋值时,就会触发setter,在 setter 遍历当前数据的
依赖队列
, 将数据变化通知到每一个 使用者(即 watcher).
compiler:
- 解析模板字符串,为节点创建 watcher
- 通过 watcher 将节点中的变量替换为 data 中的对应属性值
- 因为在这个过程中调用了数据的 getter, 这个数据的
依赖队列
就是会把这个 watcher 添加进去 - 当数据更新时,setter 就会通知
依赖队列
里面的 watcher ,watcher 接受到新数据, 并将数据更新到DOM
watcher:
- 是 observer和 compiler 之间通信的桥梁,主要做的事情是:
- 在自身实例化时, 在初始化节点的数据的同时将自己添加到数据的
依赖队列
- 实现一个 update 方法, 数据更新调用setter,在数据的 setter 中调用该方法实现对DOM更新
MVVM:
作为数据绑定的入口,通过 compile 来解析编译模板, 为节点创建 watcher,watcher 通过 observer 来监听数据变化, 达到数据变化 => 视图更新;视图变化 => 数据model变更的双向绑定效果。