1.前言
我们在上一篇文章中说了Vue的响应式原理,使用Object.defineProperty,但是有一个问题,就是每次只能一个一个设置。而这篇文章就是为了说明如何使用侦听器让对象里的每个值都变成可观测的。
2.侦听器的实现
(1)创建一个Observe类,判断传入的值是数组还是对象(本篇文章值说明对象的逻辑,数组的逻辑有兴趣的同学可以自己实现下),如果是对象,使用自定义的walk方法,进行遍历,使用defineReactive方法,让每个属性都变成可观测的。
(2)在defineReactive方法中,判断传入的属性是否是对象,如果是就递归Observe,如果不是就执行Object.defineProperty进行数据劫持。
index.js:
export class Observe{
constructor(value){
this.value = value
if(Array.isArray(value)){
// 数组的逻辑
}else{
// 对象的逻辑
this.walk(value)
}
}
walk(obj){
const keys = Object.keys(obj)
for(let i = 0;i < keys.length;i++){
defineReactive(obj,keys[i])
}
}
}
// 循环,让每个属性都变成可观测的
function defineReactive(obj,key,val){
if(arguments.length === 2){
val = obj[key]
}
if(typeof val === 'object'){
// 递归
new Observe(val)
}
Object.defineProperty(obj,key,{
enumerable:true, // 可枚举
configurable:true, // 可删除
get(){
console.log(`${
key}被读取了`)
return val
},
set(newVal){
console.log(`${
key}属性被修改了,新值为${
newVal}`)
val = newVal
}
})
}
(3)使用
<!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>如何让数据可观测“”</title>
</head>
<body>
<h2>Vue侦听器原理解析——让每个属性都可以被观测(Observe类的实现)</h2>
<script type="module">
import {
Observe} from './observe.js'
let obj = new Observe({
name:'小明',
age:'18',
demo:{
a:'aaa',
b:'bbb'
}
})
console.log(obj.value.name)
obj.value.name = 25
console.log(obj.value.demo.a)
obj.value.demo.a = 'aaaaaaa'
</script>
</body>
</html>