作用
1、数据驱动视图
数据值的改变导致页面改变
2、双向数据绑定
自定义数据值变化->页面数据变化
反过来,页面数据变化->自定义数据值变化(代码中的数据初始值不改变)
MVVM
1、Model
数据模型:渲染到页面的数据
2、View
页面视图
3、ViewModel
视图模型:联系数据和视图的桥梁,是双向数据绑定的核心
ViewModel原理
MVVM工作流程
主要工作:
劫持变化的数据,将新数据渲染到页面
如何劫持数据:
1、Object.defineProperty()给类和数据对象的属性绑定get和set方法
2、通过调用类属性的set方法间接调用回调函数,渲染更新页面
class ViewModel {
constructor(options = {}) {
this._data = options.data // 数据源
this.watchAttr = ''
this.watchers = {}
Object.keys(this._data).forEach((attr) => {
this._proxy(attr)
})
if (this._data && typeof this._data === 'object') {
Object.keys(this._data).forEach((attr) => {
this._proxyData(attr)
})
}
}
_proxy(attr) {
// 这个是绑定到类上属性的get和set
Object.defineProperty(this, attr, {
get: () => {
return this._data[attr]
},
set: (val) => {
this._data[attr] = val
}
})
}
_proxyData(attr) {
let val = this._data[attr]
// 这个是绑定到data对象上属性的get和set
Object.defineProperty(this._data, attr, {
get: () => {
return val
},
set: (newVal) => {
// 监听属性和方法拿完后在set值
setTimeout(() => {
if (val !== newVal) {
val = newVal
// set谁就调用谁的处理方法
this.watchAttr = attr
if (this.watchers.hasOwnProperty(this.watchAttr)) {
this.watchers[this.watchAttr](newVal)
}
}
}, 0)
}
})
}
$watch(watchAttr, cb) {
// 不同的监听数据和处理函数放入对象
this.watchAttr = watchAttr
if (
!this.watchers.hasOwnProperty(this.watchAttr) ||
this.watchers[this.watchAttr] !== cb
) {
this.watchers[this.watchAttr] = cb
}
}
}
const vm = new ViewModel({
data: {
text: '一个数据',
username: 'zhangsan'
}
})
// 测试
vm.text = 'gaibinale'
vm.username = 'pppp'
vm.text = 'oioi'
vm.$watch('text', (str) => console.log('text', str))
vm.$watch('username', (str) => console.log('username', str))