vue3的响应式操作劫持
vue3响应式劫持操作主要用到了es6中的Proxy代理 与Reflect执行原有操作行为;
因为当参数为数组或者对象时 ref相当于reactive;所以要定义reactive;
定义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
}
}
手写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
}
手写shallowRef
function shallowRef(target) {
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
手写ref
// 定义一个ref函数
function ref(target) {
target = reactive(target);
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
检验
const proxyUser1 = shallowRef({
name: 'hhh',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// shallowRef 可以读取数据
console.log(proxyUser1.value);
console.log('********************************************');
// 不可以 劫持修改深层数据
proxyUser1.value.name = '哈哈';
console.log('********************************************');
// shallowRef 可以修改浅层数据
proxyUser1.value = '哈哈';
console.log('*********************################***********************');
const proxyUser2 = ref({
name: 'zzz',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// ref 可以读取数据
console.log(proxyUser2.value);
console.log('********************************************');
// 可以 劫持修改深层数据
proxyUser2.value.name = '哈哈';
console.log('********************************************');
// ref 可以修改浅层数据
proxyUser2.value = '哈哈';
测试完整代码
index.js
/*
* @Descripttion:
* @version:
* @Author: HHH
* @Date: 2021-02-22 17:12:08
* @LastEditors: HHH
* @LastEditTime: 2021-02-23 11:24:59
*/
// 定义一个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
}
}
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
}
// 定义一个sallowRef函数
function shallowRef(target) {
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
// 定义一个ref函数
function ref(target) {
target = reactive(target);
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
index.html
<!--
* @Descripttion:
* @version:
* @Author: HHH
* @Date: 2021-02-22 16:04:16
* @LastEditors: HHH
* @LastEditTime: 2021-02-23 11:24:44
-->
<!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 = shallowRef({
name: 'hhh',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// shallowRef 可以读取数据
console.log(proxyUser1.value);
console.log('********************************************');
// 不可以 劫持修改深层数据
proxyUser1.value.name = '哈哈';
console.log('********************************************');
// shallowRef 可以修改浅层数据
proxyUser1.value = '哈哈';
console.log('*********************################***********************');
const proxyUser2 = ref({
name: 'zzz',
schoolRecord: {
chinese: '88',
english: "59",
math: '99'
}
})
// ref 可以读取数据
console.log(proxyUser2.value);
console.log('********************************************');
// 可以 劫持修改深层数据
proxyUser2.value.name = '哈哈';
console.log('********************************************');
// ref 可以修改浅层数据
proxyUser2.value = '哈哈';
</script>
</body>
</html>