js实现简单的双向绑定

利用Object.defineProperty实现简单的input双向绑定

<!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>practice</title>
</head>
<body>
    <input id="input" type="text">
    <div id="box"></div>
    <script>
        let input = document.getElementById("input");
        let box = document.getElementById("box");
        let value = {};
        
        let name;
        Object.defineProperty(value,"name",{
            get:()=>{
                return name;
            },
            set:(val)=>{
                console.log(val);
                name = val;
                box.innerHTML = val;
                if(input.value!=val){
                    input.value = val
                }
            }
        })

        input.addEventListener('input',(e)=>{
            console.log(e.target.value);
            value.name = e.target.value;
        })

        value.name = "wmm";

    </script>
</body>
</html>

最终效果

原理是,通过Object.defineProperty对对象的getter和setter进行拦截,在setter的时候对数据进行绑定处理,从而监听数据实时变化。

vue2.0中也是利用Object.defineProperty实现的双向绑定

但是后面es6新增了Proxy代理,相比较Object.defineProperty而言,Proxy可以一次性监听所有对象的属性,而Object.defineProperty则需要通过遍历才可以实现这一点,如下

 let value = {
            age: "18",
            name: "wmm",
        };
        let name = value.name;
        let age = value.age;
        Object.keys(value).forEach((key) => {
            Object.defineProperty(value, key, {
                get: () => {
                    return key == 'age' ? age : name
                },
                set: (val) => {
                    console.log(val);
                    if(key=='age'){
                        age = val;
                    }else if(key=='name'){
                        name = val;
                    }
                }
            })
        })
        console.log(value.name);
        value.name = "wmm123";
        console.log(value.name);

而且Object.defineProperty无法监听新增加的属性,也无法相应数组的相关方法如push等,在vue中通过重写数组原型链的方式,来监听push、shift、pop等操作;

 const arrayProto = Array.prototype;
        const newArrayProto = Object.create(arrayProto);
        const methods = ['pop', 'shift', 'unshift', 'sort', 'reverse', 'splice', 'push'];
        methods.forEach(method => {
            newArrayProto[method] = function () {
                arrayProto[method].call(this, ...arguments);
            }
            Object.defineProperty(newArrayProto, method, {
                get() {

                },
                set() {

                }
            })

        })

既然proxy这么好,下面放个用法

  • get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

  • set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

 let value = {
            age: "18",
            name: "wmm",
        };
        // let name = value.name;
        // let age = value.age;

        value = new Proxy(value, {
            //  target:目标对象  property:属性名
            get(target, property, recevier) {
                console.log("target", target);
                console.log("property", property);
                return Reflect.get(target, property, recevier);
            },
            //  obj:目标对象  prop:属性名 value:属性值
            set(obj, prop, value,recevier) {
                console.log("obj", obj);
                console.log("prop", prop);
                console.log("value", value);
                return Reflect.set(obj, prop , value, recevier);
            }
        })
        value.name = "wmm122"
        console.log(value);
        console.log(value.name);
        console.log(value);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我好爱吃草莓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值