手写简单实现vue2响应式原理
举一个例子:
小明想买一个冰墩墩, 联系淘宝商家, 商家告知没货, 商家再从厂家订购回来, 再通知小明,
小明订阅了商家冰墩墩 当冰墩墩到货, 商家发布通知订阅者小明
// index.js
// 订阅器模型
let Dep = {
chientList: {}, // 容器列表
// 添加订阅 key键 fn为商品库 可以订阅多个商品
listen: function (key, fn) {
// 判断有没有小明的订阅库,没有就建立订阅容器,有的话把商品添加进去
// if (!this.chientList[key]) {
// this.chientList[key] = []
// }
// this.chientList[key].push(fn)
// 简化代码 短路表达式
(this.chientList[key] || (this.chientList[key] = [])).push(fn)
},
// 发布 数据变化 通知订阅者
trigger: function () {
// 使用数组的原型方法,把arguments类数组 转为数组
let key = Array.prototype.shift.call(arguments),
fns = this.chientList[key];
// 如果没有这个人,或者没有关注商品就不再执行通知
if (!fns || fns.length == 0) {
return false
}
for (let i = 0, fn; fn = fns[i++];) {
// 绑定this
fn.apply(this, arguments)
}
}
}
// 数据劫持 data劫持的数据 tag目标元素 目标的key 选择器
let dataHi = function ({ data, tag, datakey, selector }) {
let value = '',
el = document.querySelector(selector); // 获取dom元素
// 结合v-model原理
Object.defineProperty(data, datakey, {
// 取值
get: function () {
console.log('取值');
return value;
},
// 设置值
set: function (val) {
console.log('设置值');
value = val
// 发布
Dep.trigger(tag, val)
}
})
// 订阅
Dep.listen(tag, function (text) {
el.innerHTML = text
})
}
<!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>vue2响应式原理</title>
</head>
<body>
<div id="app">
<p>one: <span class="one"></span></p>
<p>two: <span class="two"></span></p>
</div>
<script src="./index.js"></script>
<script>
let obj = {}
dataHi({
data: obj,
tag: 'view-1',
datakey: 'one',
selector: '.one'
})
dataHi({
data: obj,
tag: 'view-2',
datakey: 'two',
selector: '.two'
})
obj.one = '1111111111'
obj.two = '2222222222'
</script>
</body>
</html>