vue双向数据绑定原理
1.发布订阅者模式
//dep收集订阅者,并通知订阅者调用相关函数
class Dep {
constructor() {
this.sub=[]
}
//收集依赖
addSub(watcher) {
this.sub.push(watcher)
}
//通知订阅者
notify() {
this.sub.forEach((watcher) => {
watcher.update()
})
}
}
//订阅者
class Watcher {
constructor(cd) {
this.cd=cd
}
update() {
this.cd()
}
}
//相关的订阅者
//订阅者1
let w1 = new Watcher(() => {
console.log('1');
})
//订阅者2
let w2 = new Watcher(() => {
console.log('2');
})
let dep = new Dep()
//收集依赖
dep.addSub(w1)
dep.addSub(w2)
//当vue察觉到data被赋值时就会调用notify函数,通知订阅者更新数据
dep.notify()
那么vue是如何监听到赋值的了?
通过defineProperty进行数据劫持
// vue 如何监听到数据赋值操作的了?通过给每个定义属性设置监听器,那么dep通知订阅者应该在set()函数里
//当监听到数据变化时,dep就会立即通知相关订阅者更新dom
// (new watcher(() => {
// 这里应该传递 一个更新dom的操作
// }))
let obj = {
age:"12"
}
Object.defineProperty(obj, 'name', {
enumerable: true, //是否可以被循环
configurable: true,//是否可以被配置 delete
get() { //getter
console.log('我被调用了');
},
set() { //setter
console.log('我不是ls');
}
})
obj.name='jj'
//打印:我不是ls
3.vue内部数据劫持详解
<script>
const vm= new vue({
el:'#app',
data:{
name:'ls',
obj:{
age:19
}
}
})
console.log(vm);
</script>
class vue {
constructor(options) {
this.$data = options.data,
observe(this.$data)
}
}
//定义数据拦截函数
function observe(data) {
Object.keys(data).forEach((key) => {
let value = data[key]
//如果含有子对象,递归遍历
if (typeof value === 'object') {
observe(value)
} else {
Object.defineProperty(data, key, {
enumerable: true,
configurable:true,
set(newVal) {
return newVal
},
get() {
return value
}
})
}
})
}
但以上如果重新给obj赋值:vm.$data.obj={sex:1}
obj里的sex是没有set() 和get()的
所以我们应该在set()在调用一下observe()
4.vue如何将数据编译到模板上的?
本文来自博客园,作者:Kira的学习笔记,转载请注明原文链接:https://www.cnblogs.com/kira2022/p/16128100.html