美文网首页
Vue 响应式 / 双向数据绑定

Vue 响应式 / 双向数据绑定

作者: 行走的蛋白质 | 来源:发表于2020-12-08 18:57 被阅读0次

    一、关于双向数据绑定

    • 数据模型和视图之间的双向绑定

    • Vue 中的 MVVM

    • 通常,我们需要编写代码,将从服务器获取的数据进行“渲染”,展现到视图上。每当数据有变更时,我们会再次进行渲染,从而更新视图,使得视图与数据保持一致。也就是:


      model-view.png
    • 而另一方面,页面也会通过用户的交互,产生状态、数据的变化,这个时候,我们则编写代码,将视图对数据的更新同步到数据,以致于同步到后台服务器。也就是:


      view-model.png
    双向数据绑定
    • 当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化;可以这样说用户在视图上的修改会自动同步到数据模型中去,数据模型也是同样的变化


      model-view-mode.png
    • 双向数据绑定的优点:无需和单向数据绑定那样进行 CRUD(Create,Retrieve,Update,Delete)操作,双向数据绑定最常应用在就表单上,这样当用户在前端页面完成输入后,不用任何操作,我们就已经拿到了用户输入好的数据,并放到数据模型中了

    二、双向数据绑定的实现

    v-model 实现双向数据绑定
    • v-model 是一个 value 绑定加 input 事件回调的语法糖
    <input v-model="something">
    // 等价于
    <input
      v-bind:value="something"
      v-on:input="something = $event.target.value">
    

    三、双向数据绑定的原理

    • Object.defineProperty()
      方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
    • Proxy
      对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
    • Reflect
      是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的
    2.0 版
    <div>
        <input type="text" id="userName" name="">
        <br>
        <span id="view"></span>
    </div>
    
    <script type="text/javascript">
        let defineObject = {
            userInfo: {
                userName: '',
                password: '123456'
            }
        }
        let input = document.getElementById('userName')
        let view = document.getElementById('view')
    
        // 更新视图
        function update() {
            view.innerText = defineObject.userInfo.userName
        }
        //更新数据
        input.oninput = function () { 
            defineObject.userInfo.userName = this.value
        }
    
        observerData(defineObject)
    
        // 属性循环绑定
        function observerData(target) {
            if(!target || typeof target !== 'object') return target;
    
            Object.keys(target).forEach(item => {
                bindProps(target, item, target[item])
            })
        }
    
        // 属性绑定监听
        function bindProps(target, prop, value) {
            observerData(value) // 循环绑定
    
            Object.defineProperty(target, prop, {
                get() {
                    console.log('getProp: ', value)
                    return value
                },
                set(newValue) {
                    console.log('setProp: ', newValue)
                    if(newValue  === value) return
    
                    value = newValue
                    update()
                }
            })
        }
    </script>
    
    • 缺点:
      • 在 Vue 中,Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。 为了解决这个问题,经过 vue 内部处理后可以使用以下几种方法来监听数组 push() pop() shift() unshift() splice() sort() reverse()
      • Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 里,是通过递归以及遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象,不管是对操作性还是性能都会有一个很大的提升
    3.0版
        let defineObject = {
            userInfo: {
                userName: '',
                password: '123456'
            }
        }
        let input = document.getElementById('userName')
        let view = document.getElementById('view')
    
        // 更新视图
        function update(newValue) {
            view.innerText = newValue
        }
        //更新数据
        input.oninput = function () { 
            newProxy.userName = this.value
        }
    
        let newProxy = new Proxy(defineObject, {
            get(target, key, receiver) {
                console.log('getProp: ', target[key])
                return Reflect.get(target, key);
            },
            set(target, key, newValue, receiver) {
                console.log('setProp: ', target[key])
                if(key === 'userName') {
                    update(newValue)
                }
                return Reflect.set(target, key, newValue)
            }
        });
    

    三、思考的问题

    1、Vue 为什么不能检测数组变动

    相关文章

      网友评论

          本文标题:Vue 响应式 / 双向数据绑定

          本文链接:https://www.haomeiwen.com/subject/eigtgktx.html