Object.defineProperty实现双向数据绑定
程序员文章站
2022-07-12 21:51:18
...
数据劫持:使用Object.definePropert方法在set函数中通知Watcher是否需要更新视图
github:https://github.com/qiangf811/SelfVue
Observer
const Dep = require('./dep')
class Observer {
constructor (data) {
this.defineData(data)
}
defineData (obj) {
if (!obj || typeof obj !== 'object') {
return
}
Object.keys(obj).forEach(key => {
this.defineReactive(obj, key, obj[key])
})
}
defineReactive (obj, key, val) {
this.defineData(val)
let dep = new Dep()
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: newVal => {
if (val !== newVal) {
console.log(key + '改变了', val + '变成了' + newVal)
val = newVal
dep.notify()
}
},
get: () => {
if (Dep.target) {
dep.addSub(Dep.target)
}
return val
}
})
}
}
module.exports = function (data) {
return new Observer(data)
}
watcher
const Dep = require('./dep')
class Watcher {
constructor (vm, exp, cb) {
this.cb = cb
this.vm = vm
this.exp = exp
this.value = this.get()
}
update () {
this.run()
}
run () {
let value = this.vm.data[this.exp]
let oldVal = this.value
if (value !== oldVal) {
this.value = value
this.cb.call(this.vm, value, oldVal)
}
}
get () {
Dep.target = this
// 缓存自己
var value = this.vm.data[this.exp] // 强制执行监听器里的get函数
Dep.target = null // 释放自己
return value
}
}
module.exports = function (vm, exp, cb) {
return new Watcher(vm, exp, cb)
}
Dep
module.exports = class Dep {
constructor () {
this.subs = []
}
/**
* 添加订阅者
* @param {Watcher} sub 订阅者实例
*/
addSub (sub) {
this.subs.push(sub)
}
/**
* 通知所有订阅者
* @return {Null}
*/
notify () {
this.subs.forEach(sub => {
sub.update()
})
}
}
MyVue
const Observer = require('./observer')
const Watcher = require('./watcher')
module.exports = class SelfVue {
constructor (data, el, exp) {
let self = this
self.data = data
Object.keys(data).forEach(key => {
self.proxyKeys(key)
})
Observer(data) // 构造数据监视器
el.innerHTML = self.data[exp] // 初始化模板数据的值
Watcher(self, exp, value => { // 添加订阅者,监听具体字段
el.innerHTML = value
})
return self
}
proxyKeys (key) {
let self = this
Object.defineProperty(this, key, {
configurable: true,
enumerable: true,
get: () => {
return self.data[key]
},
set: (newVal) => {
self.data[key] = newVal
}
})
}
}
推荐阅读
-
Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案
-
vue.js利用Object.defineProperty实现双向绑定
-
C#异步绑定数据实现方法
-
VUE-Table上绑定Input通过render实现双向绑定数据的示例
-
vue数据双向绑定原理解析(get & set)
-
vue.js的双向数据绑定Object.defineProperty方法的神奇之处
-
AngularJS学习笔记(三)数据双向绑定的简单实例
-
asp.net实现XML文件读取数据绑定到DropDownList的方法
-
jquery,js简单实现类似Angular.js双向绑定
-
使用ES6实现MVVM双向绑定的方法和步骤