vue2与vue3双向数据绑定原理实现及区别

793 阅读1分钟

吹牛之前先摆哈NBA,大威少这赛季的投篮是真的铁,下图比喻得栩栩如生...... 然后今天北京时间2022/5/13 热火4-276人(数字人),三弟(登哥)持续低迷14中2将数字人全队带去钓鱼了,正式出局季后赛......

好了,进入正题,

微信图片_20211229170551.jpg

vue2的双向数据绑定是利用ES5的一个API Object.definePropert() 对数据进行劫持,结合发布订阅模式的方式来实现的。

vue3中使用了ES6的Proxy这个API来对数据代理。

两者区别:Object.definePropert() 只能监听某个属性,不能对全对象监听。 而Proxy 可以省去for in、Object.keys()等操作来提升效率(直接绑定整个对象即可), 也可以监听数组,不用再去单独的对数组做特异性操作,它可以检测到数组内部数据的变化。

vue2/vue3原理实现:

   <html>
        <head>
                <meta charset="utf-8" />
                <title></title>
        </head>
        <body>
            <input type="text" id="inputVue2" /> vue2输入的值为:<span id="outVue2"></span><br />
            <input type="text" id="inputVue3" /> vue3输入的值为:<span id="outVue3"></span>
        </body>
   </html>
   <script type="text/javascript">
    //vue2双向绑定实现原理
    const data = {// 定义一个对象
        age: 10
    };
    var val = data.age;
    var inputVue2 = document.querySelector('#inputVue2');
    var outVue2 = document.querySelector('#outVue2');
    // 遍历对象 实现对对象的属性进行劫持
    Object.keys(data).forEach(key => {//这里也可以用for in
        Object.defineProperty(data, key, {
            // 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中
            enumerable: true,
            // 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除
            configurable: true,
            // 一个给属性提供 getter 的方法
            get: () => {
                return val;
            },
            // 一个给属性提供 setter 的方法
            set: (newVal) => {
                // 当属性值发生变化时我们可以进行额外操作 如调用监听器
                if (newVal === val) { // 如果未发生变化 不做其他操作
                    return;
                }
                outVue2.innerHTML = newVal
                console.log(`vue2触发视图更新函数${newVal}`);
            },
        })
    })
    inputVue2.addEventListener('input', e => data.age = e.target.value)


    //vue3双向绑定实现原理
    let obj = { // 源数据对象
        sex: '女',
        height: 168
    }
    var inputVue3 = document.querySelector('#inputVue3');
    var outVue3 = document.querySelector('#outVue3');
    let proxy = new Proxy(obj, {
        get: (target, prop, receiver) => {
                return prop in target ? target[prop] : 0
        },
        // input事件触发进行劫持,触发update方法
        set: (target, prop, value, receiver) => {
                target[prop] = value
                console.log(`vue3触发视图更新函数${value}`);
                update(value)
        }
    })
    // update方法用于同步dom更新
    const update = (value) => {
        outVue3.innerHTML = value
        inputVue3.value = value
    }
    // 监听input数据变化,并修改proxy的值
    inputVue3.addEventListener('input', e => proxy.text = e.target.value)
</script>