1.vue 2.0
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
订阅1:<span class="box-1">1111</span>
订阅2:<span class="box-2">2222</span>
</div>
<script src="./index.js"></script>
<script>
// 开始执行数据劫持
let dataObj = {};
dataHijack({
data: dataObj, //劫持的对象
tag: 'view-1', // 唯一id,类似vue节点上的key
datakey: 'one', // 挂载到对象的属性,类似data中的属性名
selector: '.box-1', // 类名
})
dataHijack({
data: dataObj,
tag: 'view-2',
datakey: 'two',
selector: '.box-2',
})
// 修改数据
dataObj.one = '测试1'
dataObj.two = '测试2'
</script>
</body>
</html>
js
// 订阅器模式
let Dep = {
clientList: {}, //订阅者集合
// 添加订阅
listen: function (key, fn) { //key:唯一id,fn:回调函数,可能有多个
// 如果该项没有订阅,设置初始存储集合,然后添加回调函数
(this.clientList[key] || (this.clientList[key] = [])).push(fn)
},
// 推送方法
trigger: function () {
// 这里的arguments指的下面的set方法传过来的[tag, val],数组格式
// key对应的就是tag,即唯一id
let key = Array.prototype.shift.call(arguments)
// 拿到当前的函数,为什么能拿到,是因为初始化时执行Dep.listen已经存储到clientList了
// fns其实就是里面的回调函数
let fns = this.clientList[key]
if (!fns || fns.length === 0) {
return false
}
// 执行节点对应的函数,即初始化挂载的回调
for (let i = 0, fn; i < fns.length; i++) {
fn = fns[i]
fn.call(this, ...arguments)
}
}
}
// 数据劫持
let dataHijack = function ({ data, tag, datakey, selector }) {
let value = ''
// 对对象的各个属性进行劫持
Object.defineProperty(data, datakey, {
get: function () {
console.log('取值')
return value
},
set: function (val) {
// 修改dataObj后会进入这里
console.log('设置值')
value = val
// 数据变化
Dep.trigger(tag, val)
}
})
// 添加订阅者,这里指的是将订阅者1,2分别添加到clientList中,
// 此时clientList的格式为:{view-1: [ƒ],view-2: [ƒ]},f是这里传过去的函数
Dep.listen(tag, function (text) {
document.querySelector(selector).innerHTML = text
})
}
2.vue 3.0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
proxy的使用
</div>
<script>
let obj = {
name: '小明',
age: '18',
}
// 代理
const p = new Proxy(obj, {
// 查属性
get(target, propName) {
return target[propName]
},
// 新增修改属性
set(target, propName, value) {
target[propName] = value
},
// 删除属性
deleteProperty(target, propName) {
},
})
</script>
</body>
</html>