vue3的响应式操作劫持
vue3响应式劫持操作主要用到了es6中的Proxy代理 与Reflect执行原有操作行为;
定义reactiveHandler处理对象 进行数据拦截
// 定义一个reactiveHandler处理对象
const reactiveHandler = {
// 获取属性值
get(target,prop){
const result = Reflect.get(target,prop);
console.log('拦截了读取数据',prop,result);
return result
},
// 修改属性值/添加属性
set(target,prop,value){
const result = Reflect.set(target,prop,value);
console.log('拦截了修改属性值或者是添加属性',prop,value);
return result
},
deleteProperty(target,prop){
const result = Reflect.deleteProperty(target,prop);
console.log('拦截了删除数据',prop);
return result
}
}
手写shallowReactive
// 定义一个shallowReactive函数,传入一个目标对象
function shallowReactive(target){
// 判断当前的目标对象是否是object类型(对象/数组)
if(target&&typeof target === 'object'){
return new Proxy(target,reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
手写reactive
function reactive(target){
// 判断当前的目标对象是否是object类型(对象/数组)
if(target&&typeof target === 'object'){
// 对数组或者对象中所有的数据进行reactive的递归处理
// 判断当前的数据是否是数组
if(Array.isArray(target)){
// 数组的数据进行遍历操作
target.forEach((item,index)=>{
target[index] = reactive(item)
})
}else{
// 判断当前的数据是否是对象
// 对象的数据也要进行遍历的操作
Object.keys(target).forEach((key)=>{
target[key] = reactive(target[key])
})
}
return new Proxy(target,reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
检验
const proxyUser1 = shallowReactive({
name: 'hhh',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// shallowReactive可以拦截读取数据
proxyUser1.name;
// shallowReactive可以拦截修改数据
proxyUser1.name = '黎明';
// shallowReactive可以拦截读取深层的数据 不可以拦截修改深层的数据
proxyUser1.schoolRecord.chinese = '66';
console.log('*********************################***********************');
const proxyUser2 = reactive({
name: 'zzz',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// reactive可以拦截读取数据
proxyUser2.name;
// reactive可以拦截修改数据
proxyUser2.name = '黎明';
// reactive可以拦截读取深层的数据 也可以拦截修改深层的数据
proxyUser2.schoolRecord.chinese = '66';
测试完整代码
index.js
/*
* @Descripttion:
* @version:
* @Author: HHH
* @Date: 2021-02-22 16:04:04
* @LastEditors: HHH
* @LastEditTime: 2021-02-22 16:43:33
*/
// 定义一个reactiveHandler处理对象
const reactiveHandler = {
// 获取属性值
get(target,prop){
const result = Reflect.get(target,prop);
console.log('拦截了读取数据',prop,result);
return result
},
// 修改属性值/添加属性
set(target,prop,value){
const result = Reflect.set(target,prop,value);
console.log('拦截了修改属性值或者是添加属性',prop,value);
return result
},
deleteProperty(target,prop){
const result = Reflect.deleteProperty(target,prop);
console.log('拦截了删除数据',prop);
return result
}
}
// 定义一个shallowReactive函数,传入一个目标对象
function shallowReactive(target){
// 判断当前的目标对象是否是object类型(对象/数组)
if(target&&typeof target === 'object'){
return new Proxy(target,reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
function reactive(target){
// 判断当前的目标对象是否是object类型(对象/数组)
if(target&&typeof target === 'object'){
// 对数组或者对象中所有的数据进行reactive的递归处理
// 判断当前的数据是否是数组
if(Array.isArray(target)){
// 数组的数据进行遍历操作
target.forEach((item,index)=>{
target[index] = reactive(item)
})
}else{
// 判断当前的数据是否是对象
// 对象的数据也要进行遍历的操作
Object.keys(target).forEach((key)=>{
target[key] = reactive(target[key])
})
}
return new Proxy(target,reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
index.html
<!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>
<script src="./index.js"></script>
</head>
<body>
<script type="text/javascript">
const proxyUser1 = shallowReactive({
name: 'hhh',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// shallowReactive可以拦截读取数据
proxyUser1.name;
// shallowReactive可以拦截修改数据
proxyUser1.name = '黎明';
// shallowReactive可以拦截读取深层的数据 不可以拦截修改深层的数据
proxyUser1.schoolRecord.chinese = '66';
console.log('*********************################***********************');
const proxyUser2 = reactive({
name: 'zzz',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// reactive可以拦截读取数据
proxyUser2.name;
// reactive可以拦截修改数据
proxyUser2.name = '黎明';
// reactive可以拦截读取深层的数据 也可以拦截修改深层的数据
proxyUser2.schoolRecord.chinese = '66';
</script>
</body>
</html>