双向绑定

218 阅读2分钟

这是我参与更文挑战的第7天,活动详情查看:更文挑战

简单的双向绑定

主要用的方法就是Object.defineProperties

The Object.defineProperties() method defines new or modifies existing properties directly on an object, returning the object.

这个方法可以直接添加或修改对象存在的属性值,这些属性值包括:

  • configurable

    默认为 false

    true 当且仅当该属性描述符的类型可以被改变并且该属性可以从对应对象中删除。

  • enumerable

    默认为 false

    true 当且仅当在枚举相应对象上的属性时该属性显现。

  • value

    默认为 undefined

    与属性关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。

  • writeable

    默认为 false

    true当且仅当与该属性相关联的值可以用assignment operator改变时。

  • get

    默认为 undefined

    作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。

  • set

    默认为 undefined

    作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。

主要原理

就是通过设定对象的get和set属性来实现组件之间的绑定效果。

<p>
    input1=><input type="text" id="input1">
</p>
<p>
    input2=><input type="text" id="input2">
</p>
<div>
    我每次比input1的值加1=><span id="span"></span>
</div>

当input1的值改变时触发set属性,input2的set也会执行,带动span内的值的变化。

var oInput1 = document.getElementById('input1');
var oInput2 = document.getElementById('input2');
var oSpan = document.getElementById('span');
var obj = {};
Object.defineProperties(obj, {
    val1: {
        configurable: true,
        get: function() {
            oInput1.value = 0;
            oInput2.value = 0;
            oSpan.innerHTML = 0;
            return 0
        },
        set: function(newValue) {
            oInput2.value = newValue;
            oSpan.innerHTML = Number(newValue) ? Number(newValue) : 0
        }
    },
    val2: {
        configurable: true,
        get: function() {
            oInput1.value = 0;
            oInput2.value = 0;
            oSpan.innerHTML = 0;
            return 0
        },
        set: function(newValue) {
            oInput1.value = newValue;
            oSpan.innerHTML = Number(newValue)+1;
        }
    }
})
oInput1.value = obj.val1;
oInput1.addEventListener('keyup', function() {
    obj.val1 = oInput1.value;
}, false)
oInput2.addEventListener('keyup', function() {
    obj.val2 = oInput2.value;
}, false)

Proxy双向绑定

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

Object.defineProperties有一定的缺陷:

  1. 数据量较大时会有性能影像
  2. 无法监听数组
  3. 只能监听定义时的属性,无法监听新增属性

但是es6新出的proxy完美解决此类问题。

proxy接收的参数

  • target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
  • handler 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

get 参数

  • target目标对象。
  • property被获取的属性名。
  • receiverProxy或者继承Proxy的对象

set 参数

  • target目标对象。
  • property将被设置的属性名或Symbol。
  • value新属性值。

Reflect

Reflect是一个内置的对象,它提供拦截JavaScript操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

例子

<input type="text" id="input" />
<div id="text"></div>
let input = document.getElementById("input");
let text = document.getElementById("text");
let obj = new Proxy({}, {
    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) {
    obj.text = e.target.value;
});