Vue-双向数据绑定原理

789 阅读1分钟

引言

大家都知道Vue双向数据绑定就是指v-model指令,而v-model的本质就是input、value的语法糖,语法糖就是方便我们代码编写,那么它底层又是怎样实现的呢?本篇将会以不同的vue版本为切入点,进行模拟实现。

 vue2.0-Object.definedProperty

<input type="text" id='inp'>
    <div id='view'></div>
    <script>
        const input = document.getElementById('inp');
        const view = document.getElementById('view');

        let data = {
            // name: 'view'
            valueObj:{
                name:'view'
            }
        }

        function update() { //更新视图
            view.innerText = data.valueObj.name;
        }

        input.oninput = function () { //更新数据 
            data.valueObj.name = this.value
        }

        function observerData(obj) {
            if (!obj || typeof obj != 'object') return obj; //容错 + 递归出口

            Object.keys(obj).forEach(key => {
                definedRective(obj, key, obj[key]);
            })
        }

        observerData(data);

        function definedRective(obj, key, val) {

            observerData(val); //深层数据递归处理

            Object.defineProperty(obj, key, {
                get() {
                    return val;
                },
                set(newVal) {
                    if (val === newVal) return; //优化性能
                    val = newVal;
                    update();
                }
            })
        }
    </script>

缺点

  1. **不能直接监控数组,而是间接重写Array.prototype上的数组方法(就是vue中常常听见的数组变异方法)比如push、unshfit...属性,监听数组原型上的这些方法,进而实现更新
    **
  2. 如果被监听对象在执行监听之后又重新添加了属性,这些属性值则无法监听到

vue3.0-Proxy&Reflect

  let oProxy = new Proxy(data, {
            get(target, key, receiver) {
                console.log(1)
                return Reflect.get(target, key);
            },
            set(target, key, newValue, receiver) {
                console.log(1)
                return Reflect.set(target, key, newValue)
            }
     });

说明

**ES6的Proxy&Reflect完美解决了ES5Object.definedProperty()缺点(上面已经指出),但是浏览器不能直接兼容,只能间接通过babel语言降级,因此这里只给出关键代码大家了解一下即可。
**