用vue的伙伴应该都知道vue的特点就是数据驱动,不用真的去操作dom,这里面就是用到了Object里面的一个方法
Object.defineProperty(data, datakey, {
get() {
},
set(val) {
}
})
每次面试都会被问到,除了这个方法,vue的响应式还用了订阅发布的模式,那么订阅和发布又是怎么实现的呢,下面我写一个最简单基础的一个订阅发布
// 创建订阅发布方法
let Dep = {
// 定义一个存放订阅方法的属性
sublist: {},
// 订阅方法 需要接受两个参数 一个是订阅者的信息,一个是他的执行方法
subscript: function (key, fn) {
// 这里用vue中用的比较多的短路运算 把传过来的方法存起来
(this.sublist[key] || (this.sublist[key] = [])).push(fn)
},
// 发布方法
release: function () {
let key = Array.prototype.shift.call(arguments)
let fns = this.sublist[key]
// 判断是否有方法
if (!fns || fns.length === 0) {
return false
}
// 有的话就循环调用,把当前的this传过去
for (let index = 0, fn; fn = fns[index++];) {
fn.apply(this, arguments)
}
}
}
订阅发布的方法写好,我们还需要进行数据劫持,这样才能实现数据响应,当然想要数据劫持,就需用到上面讲的Object的方法了。
// 数据监听 接受四个参数 data:需要监听的对象,tag:监听的目标,datakey:监听的key,selector:元素属性
let setdata = function ({ data, tag, datakey, selector }) {
// 创建一个存值的参数
let value = '';
// 获取元素
let el = document.querySelector(selector);
// vue2的数据劫持方法
Object.defineProperty(data, datakey, {
get() {
return value
},
set(val) {
value = val
// 设置新的值后要调用发布方法,通知订阅者,把目标对象和新的值传过去
Dep.release(tag,val)
}
})
// 在第一次的时候,数据还没被监听,此时应该调用订阅方法进行订阅,后续数据变化才能被发布方法通知,从而进行数据改变,所以在此要进行订阅方法调用
Dep.subscript(tag,(text)=>{
el.innerHTML=text
})
}
最简单的一个vue2响应式代码就完成了,下面我们来用它
<!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 class="box1"></div>
<div class="box2"></div>
// 引入刚才写的代码
<script src="./dep.js"></script>
<script>
let obj={}
setdata({
data:obj,
tag:'view-1',
datakey:'one',
selector:'.box1'
})
setdata({
data:obj,
tag:'view-2',
datakey:'two',
selector:'.box2'
})
obj.one='我是第一'
obj.two='我是第二'
</script>
</body>
</html>
运行上面的代码,我们可以发现,我们不用在html中直接写内容,也可以显示出来,我们只需要在js中拿到对应的唯一标识datakey就可以修改对应标签的内容