基于proxy和Reflect简单实现vue3常用方法的数据劫持部分功能

本文介绍了如何在Vue3中模拟实现部分核心功能,如reactive、shallowReactive、readonly和ref,以及相应的辅助函数,展示了它们在数据劫持和读写权限控制中的应用。
摘要由CSDN通过智能技术生成

经过一段时间的学习,自己简单模拟实现了vue3中部分方法的功能

// 定义reactiveHandler处理对象
const reactiveHandler = {
  // 获取属性值
  get(target, prop) {
    if (prop === "_is_reactive") return true;
    console.log("拦截到了读取属性值", prop);
    return Reflect.get(target, prop);
  },
  // 修改属性值或者添加属性
  set(target, prop, value) {
    console.log("拦截到了修改属性", prop, value);
    return Reflect.set(target, prop, value);
  },
  // 删除属性
  deleteProperty(target, prop) {
    console.log("拦截到了删除属性", prop);
    return Reflect.deleteProperty(target, prop);
  },
};

// shallowReactive和reactive
function shallowReactive(target) {
  // 判断传入的参数是不是object类型
  if (target && typeof target === "object") {
    return new Proxy(target, reactiveHandler);
  } else {
    // 如果是基本类型,直接返回
    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);
  } else {
    // 如果是基本类型,直接返回
    return target;
  }
}

const readonlyHandler = {
  get(target, prop) {
    if (prop === "_is_readonly") return true;
    console.log("拦截到了读取数据", prop);
    return Reflect.get(target, prop);
  },
  set(target, prop, value) {
    console.warn("不能修改或添加数据,只能读取数据!");
    return true;
  },
  deleteProperty(target, prop) {
    console.warn("不能删除数据,只能读取数据!");
    return true;
  },
};

// shallowReadonly和readonly
function shallowReadonly(target) {
  if (target && typeof target === "object") {
    return new Proxy(target, readonlyHandler);
  } else {
    return target;
  }
}

function readonly(target) {
  if (target && typeof target === "object") {
    if (Array.isArray(target)) {
      target.forEach((item, index) => {
        target[index] = readonly(item);
      });
    } else {
      Object.keys(target).forEach((key) => {
        target[key] = readonly(target[key]);
      });
    }
    return new Proxy(target, readonlyHandler);
  } else {
    return target;
  }
}

// shallowRef和ref
function shallowRef(target) {
  return {
    _is_ref: true, //标识当前对象是ref对象
    _value: target,
    get value() {
      console.log("拦截到了读取数据");
      return this._value;
    },
    set value(val) {
      console.log("拦截到了修改数据");
      return (this._value = val);
    },
  };
}

function ref(target) {
  if (target && typeof target === "object") {
    target = reactive(target);
  }
  return {
    _is_ref: true, //标识当前对象是ref对象
    _value: target,
    get value() {
      console.log("拦截到了读取数据");
      return this._value;
    },
    set value(val) {
      console.log("拦截到了修改数据", val);
      this._value = val;
    },
  };
}

// isRef isReactive isReadonly isProxy
function isRef(obj) {
  return obj && obj._is_ref ? obj && obj._is_ref : false;
}

function isReactive(obj) {
  return obj && obj._is_reactive ? obj && obj._is_reactive : false;
}

function isReadonly(obj) {
  return obj && obj._is_readonly ? obj && obj._is_readonly : false;
}

function isProxy(obj) {
  return isReactive(obj) || isReadonly(obj);
}

下面为测试代码

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手搓vue3中常用api,只是实现劫持操作,页面刷新没有</title>
</head>

<body>

</body>
<script src="./index.js"></script>
<script type="text/javascript">
    console.log("-------------------测试shallowReactive--------------------");
    const proxyData1 = shallowReactive({
        name: "张三",
        car: {
            color: "red",
            type: ["奔驰", "宝马", "劳斯莱斯"]
        }
    })
    proxyData1.name += "~"  // 拦截到了读和写
    proxyData1.car.color = "blue"  // 只拦截到了读
    console.log(proxyData1.car.color);  // blue
    delete proxyData1.name  //拦截到了删除数据
    delete proxyData1.car.color  // 只拦截到了读取数据,删除数据拦截不到
    console.log(proxyData1.car); // {type: ["奔驰", "宝马", "劳斯莱斯"]}

    console.log("-------------------测试reactive--------------------");
    const proxyData2 = reactive({
        name: "张三",
        car: {
            color: "red",
            type: ["奔驰", "宝马", "劳斯莱斯"]
        }
    })
    proxyData2.name += "!"  // 拦截到了读和写
    proxyData2.car.type[0] = "特斯拉"  // 拦截到了读和写
    delete proxyData2.car.color  // 拦截到了读取和删除

    console.log("-------------------测试shallowReadonly--------------------");
    const proxyData3 = shallowReadonly({
        name: "小明",
        work: {
            address: "北京",
            money: 100000000
        }
    })
    proxyData3.name += "@"  // 只能读取数据
    console.log(proxyData3.name);  // 小明
    proxyData3.work.address = "保定"  //拦截到了读取数据,修改数据没有拦截到 
    console.log(proxyData3.work.address);  // 保定
    delete proxyData3.name  // 只能读取数据,不能删除数据
    delete proxyData3.work.money  //拦截到了读取数据,删除数据没有拦截到 
    console.log(proxyData3.work); // {address: "北京"}

    console.log("-------------------测试readonly--------------------");
    const proxyData4 = readonly({
        name: "小明",
        work: {
            address: "北京",
            money: 100000000
        }
    })
    proxyData4.name += "@"  // 只能读取数据
    console.log(proxyData4.name);  // 小明
    proxyData4.work.address = "保定"  //只能读取数据,不能修改数据
    console.log(proxyData4.work.address);  // 北京
    delete proxyData4.name  // 只能读取数据,不能删除数据
    delete proxyData4.work.money  //只能读取数据
    console.log(proxyData4.work); // {address: '北京', money: 100000000}

    console.log("-------------------测试shallowRef--------------------");
    const proxyData5 = shallowRef({
        name: "小强",
        car: {
            color: "red"
        }
    })
    console.log(proxyData5.value);  // 拦截到了读取数据
    proxyData5.value = "!"  // 拦截到了修改数据
    proxyData5.value.name = "小six"  // 拦截不到修改数据

    console.log("-------------------测试ref--------------------");
    const proxyData6 = ref({
        name: "老八",
        car: {
            type: "宝马"
        }
    })
    console.log(proxyData6.value.car); // 拦截到了读取数据
    proxyData6.value.car.type = "奔驰" // 拦截到了读取和修改数据

    console.log("-------------------测试isRef--------------------");
    console.log(isRef(ref({}))); // true
    console.log(isRef(readonly({}))); //false
    console.log(isRef(shallowReactive({}))); //false
    console.log(isRef(reactive({}))); //false
    console.log("-------------------测试isReactive--------------------");
    console.log(isReactive(reactive({}))); //true
    console.log(isReactive(readonly({})));  //false
    console.log(isReactive(shallowReadonly({}))); //false
    console.log(isReactive(ref({}))); //false
    console.log(isReactive(shallowReactive({})));  //true
    console.log("-------------------测试isReadonly--------------------");
    console.log(isReadonly(readonly({})));  //true
    console.log(isReadonly(shallowReadonly({})));  //true
    console.log(isReadonly(reactive({})));  // false
    console.log("-------------------测试isProxy--------------------");
    console.log(isProxy(readonly({})));  //true 
    console.log(isProxy(reactive({})));  //true
    console.log(isProxy(ref({})));  //false
</script>

</html>

经过测试达到预期效果

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值