数据发生改变,界面发生更新并不是理所当然的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}
{{message}}
{{message}}
{{name}}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'aaa'
name: 'bbb'
}
})
</script>
</body>
</html>上面输出message的数据在浏览器上,思考两个问题:
1、app.message修改数据,vue内部是如何监听到message数据发生改变的?
这里vue内部使用到了Object.defineProperty方法。这个方法是如何作用的呢?
首先在定义两个变量message和name时,data会将它们传入vue内部,传入后,vue内部会拿到一个对象obj:
const obj = {
message: 'aaa',
name: 'bbb'
}之后vue对obj进行遍历,拿到obj中的每一个key,同时也可以拿到每一个key所对应的值:
Object.keys(obj).forEach(key => {
let value = obj[key]
})这时就可以对值value的改变进行监听了,那是如何监听的呢,就使用到了Object.defineProperty方法。
Object.defineProperty方法需要传入三个参数,第一个参数是我们的对象,第二个参数是对象要定义的属性,
第三个参数应该是要定义的值,但在vue中是这样做的:
Object.defineProperty(obj, key, {
set(newValue){
console.log('监听' + key + '改变');
value = newValue
},
get(){
console.log('获取' + key + '对应的值')
return value
}
})这里对所有的属性全部重新进行了定义,这样一旦对一个属性进行重新赋值的时候,就会执行set方法,这样就可以对改变进行监听:
同样也可以监听到获取值的动作:
2、当数据发生改变时,vue是如何知道通知哪些人发生改变的
监听到属性改变时,vue就要告诉正在用该属性的元素发生改变,那么vue是如何知道哪些元素正在使用该属性呢?这里就涉及到对
<div id="app">
{{message}}
{{message}}
{{message}}
{{name}}
</div>进行解析,在解析时会获取到该元素的值,就会调用一次get方法,这样就会知道哪些元素对get进行了调用,对这些属性在vue内部进行重新的命名后就使用到了发布订阅者模式,也就是让这些元素对set方法进行订阅:
//发布者
class Dep {
constructor() {
this.subs = []
}
addSub(wather) {
this.subs.push(wather)
}
notify() {
this.subs.forEach(item => {
item.update()
})
}
}
//订阅者
class Watcher {
constructor(name) {
this.name = name;
}
update() {
console.log(this.name + 'update');
}
}
const dep = new Dep()
const w1 = new Watcher('张三')
dep.addSub(w1)
const w2 = new Watcher('李四')
dep.addSub(w2)
const w3 = new Watcher('王五')
dep.addSub(w3)
发布者中定义了一个subs数组保存订阅的对象,addSub方法用来将对象添加到subs数组中,notify方法遍历数组并通知所有的订阅者数据发生了改变;订阅者中对订阅者的名称进行保存,同时需要对自身数据进行更新。
这样我们在set方法中对dep对象调用它的notify方法时就会通知到所有使用name的元素数据发生了改变。



京公网安备 11010502036488号