通过 Proxy 实现数据双向绑定

前言

用过 Vue 的人都知道 Vue 有双向绑定的功能,Vue 2 是通过 Object.defineProperty 实现的双向绑定,但是到 Vue3 中,便使用的 Proxy 进行双向绑定。今天就记录一下如何通过 Proxy 实现数据双向绑定。

defineProperty 缺陷

defineProperty 的作用是在一个对象上定义属性或者修改已有的属性。defineProperty 与 Proxy 相比,其缺点在于:

  1. 无法监听数组的变化;
  2. 只能劫持对象的属性,无法劫持一个完整的对象。

defineProperty 语法为:Object.defineProperty(obj, prop, desc)
第一个参数表示源对象;第二个参数表示对象的属性,第三个参数表示对该属性的描述。

let obj= {}
Object.defineProperty(obj, 'text', {
   value: '我是一段文本',
   writable: true, // 是否可以改变,
   configurable:false,//是否可配置
   enumerable:false //是否可枚举
})

defineProperty 双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="text" id="input">
<div id="text"></div>
</body>
<script>
    var input = document.getElementById("input");
    var text = document.getElementById("text");
    var obj = {};
    Object.defineProperty(obj,'text',{
        get:function () {
            console.log('get');
        },
        set:function (val) {
            console.log(val);
            input.value = val;
            text.innerText = val;         
        }
    })
    input.addEventListener('keyup',function (e) {
        obj.text = e.target.value;
    })
</script>
</html>

Proxy 语法

Proxy 是代理的意思,是 ES6 的新语法,与 defineProperty 类似,都是对对象进行一层拦截。但 Proxy 修复了 defineProperty 的问题。可以劫持完整的对象。以下为基础用法。

   var obj = {};
   var obj1 = new Proxy(obj,{
        get:function (target,key,receiver) {
            console.log(target);
            return Reflect.get(target,key,receiver);
        },
        set:function (target,key,val,receiver) {
            console.log(target);
            return Reflect.set(target,key,val,receiver);
        },
        has:function(target, key){
            return Reflect.has(target, key);
        }
    })

以上是通过 Proxy 创建了一个具有拦截功能的 obj 对象。其中 Reflect 也是 ES6 的新语法,为操作对象而提供的 API, 起作用主要有:

  1. 将 Object 对象的一些明显属于语言内部的方法放到Reflect对象上;
  2. 修改 Object 方法返回的结果,使其变得更合理。如:Object.defineProperty(obj, name, desc)在无法定义属性的时候会报错,而Reflect.defineProperty(obj, name, desc)则会返回false;
  3. 让 Object 的操作都变成函数行为。如 Object 的命令式:name in obj和delete obj[name] 则与 Reflect.has(obj, name)、Reflect.deleteProperty(obj, name)相等;
  4. Reflect 对象的方法与 Proxy 对象的方法一一对应,只要 Proxy 对象上有的方法在 Reflect 上也能找到。

Proxy 双向绑定

利用 Proxy 的拦截功能,可以在对象的 set 方法上将值同时赋值给 input 和对应的 div。然后在 keyup 事件内给该对象的属性进行赋值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="text" id="input">
<div id="text"></div>
</body>
<script>
    var input = document.getElementById("input");
    var text = document.getElementById("text");
    var obj = {};
    var obj1 = new Proxy(obj,{
        get:function (target,key,receiver) {
            return Reflect.get(target,key,receiver);
        },
        set:function (target,key,val,receiver) {
            if(key === 'text '){
              input.value = val;
              text.innerText = val;
            }     
            return Reflect.set(target,key,val,receiver);
        }
    })
    input.addEventListener('keyup',function (e) {
        obj1.text = e.target.value;
    })
</script>
</html>
发布了252 篇原创文章 · 获赞 2360 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/weixin_44135121/article/details/103324425