数据双向绑定简易原理
<input type="text" id="username">
<span id="uName"></span>
let obj = {
}
Object.defineProperty(obj, 'username', {
// 使用 defineProperty 中的 get 来双向绑定数据
set (v) {
document.getElementById('uName').innerText = v;
document.getElementById('username').value = v;
},
get () {
console.log('get')
}
})
document.getElementById('username').addEventListener('keyup', function (e) {
obj.username = e.target.value
})
defineProperty 实现原理
const vm = {
name: 'bob',
age: 11,
enjoy: ['1', 'a', 3],
hobby: {
a: 'eat' }
}
const orginalProto = Array.prototype
const arrayProto = Object.create(orginalProto) // 先克隆份 Array 原型
const methodToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodToPatch.forEach(method => {
arrayProto[method] = function () {
console.log('method changed: ', method, arguments)
orginalProto[method].apply(this, arguments)
}
})
const observe = (data) => {
if (!data || typeof data !== 'object') return
if (Array.isArray(data)) {
// 如果是数组,重写原型链 data.__proto__ = arrayProto
Object.setPrototypeOf(data, arrayProto);
for (let i = 0; i < data.length; i++) {
observe(data[i])
}
} else {
Object.keys(data).forEach(key => {
dr(data, key, data[key])
})
}
}
const dr = (data, key, val) => {
observe(val) // 递归制造响应式数据
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
set(nv) {
console.log('val changed: ', nv)
val = nv
},
get() {
return val
}
})
}
observe(vm)
vm.name = 'lucy'
vm.age = 11
vm.hobby.a = 'play'
vm.enjoy.push(123)
vm.sex = 'female' // 监听不到
// 问题:直接 watch 对象下某个属性监听不到
@Watch('searchList', {
deep: true, immediate: true })
onSearchListWatch(newVal, oldVal) {
const getSubBu = (list) => list?.find((item) => item.index === 1)?.subBuCode;
if (getSubBu(newVal) !== getSubBu(oldVal)) {
this.initLineList();
}
}
// 解决
@Watch('oneSearchList', {
deep: true, immediate: true })
onSearchListWatch(newVal, oldVal) {
if (newVal !== oldVal) {
this.initLineList(