vue如何实现双向数据绑定

本文介绍了几种数据绑定实现方式,重点分析了Vue双向数据绑定原理。Vue采用数据劫持结合发布者 - 订阅者模式,通过Object.defineProperty()劫持属性的setter和getter,在数据变动时通知订阅者。还给出了实现双向绑定的例子,以及相关代码功能说明。
几种数据绑定实现方式

发布者-订阅者模式(backbone.js)

脏检查(angular.js)

数据劫持(vue.js)
在这里插入图片描述

本文主要讲述vue双向数据绑定原理分析:

vue.js采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

在这里插入图片描述
Object.defineProperty 方法提供了一种直接的方式来定义对象属性或者修改已有对象属性。其方法原型如下,Object.defineProperty(obj, prop, descriptor)

  • obj :待修改的对象
  • prop :带修改的属性名称
  • descriptor :待修改属性的相关描述
<script>
    var obj = {}
    var returnVal = ""
    // 利用defineProperty去劫持更新
    // 第三个参数  数据描述  存取器的描述
    Object.defineProperty(obj, "age", {
        get:function () {
            return returnVal
        },
        set:function (newValue) {
            returnVal = newValue
             
        }
    })
</script>

对象obj获取属性key的值时,会触发上面的get方法,得到的是变量returnVal的值,然后当重新设置key的值时,触发set方法,会将变量returnVal的值改变为设置的值,如此就实现了一个简单的双向绑定:改变returnVal,obj.age得到的值也会改变,重新设置obj.age,returnVal一样会随之改变。

例子

实现随文本框输入文字的变化,txtspan 中会同步显示相同的文字内容;在js或控制台显式的修改 obj 中 name 的值,视图会相应更新。这样就实现了 model => view 以及 view => model 的双向绑定。

<script type="text/javascript" src="MyVue.js"></script>
<body>
    <div id="app">
        <input type="text" id="txt"></input>
        输入:<span id="txtspan"></span>
    </div>
</body>

当我们在输入框输入数据的时候,触发 keyup 事件,获取键盘的value 并赋值给 vm 实例的 name 属性。

var txt = document.getElementById("txt")
var txtspan = document.getElementById("txtspan")
var vm = new MyVue({
    el: "#app",
    data: {
        count: 0,
        name: "Cassie",
        age: 18
    }
})
txt.addEventListener("keyup", function (e) {
    vm._data.name = e.target.value
})
// 接受set的值
function callBack (val) {
    txtspan.innerHTML = val

}

MyVue.js

将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。

  • Observer:监听数据和数据变化通知订阅者的功能
  • defineReactive:利用了Object.defineProperty()这个方法来劫持了vm实例对象的属性的读写权,使读写vm实例的属性转成读写了vm._data的属性值
// 数据监听
function Observer (value) {
    if (!value || (typeof value !== 'Object')) {
        return
    }
    // 获取data所有属性
    Object.keys(value).forEach((key) => {
        // 拦截
        defineReactive(value, key, value[key])
    })
}
// 拦截数据
function defineReactive (obj, key, val) {
    Object.defineProperty(obj, key, {
        get: function () {
            return val
        },
        set: function (newValue) {
            if (newValue === val) {
                return
            }
            val = newValue
            callBack(val)
        }
    })
}
function MyVue (options) {
    this._data = options.data
    Observer(this._data)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

callmeCassie

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

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

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

打赏作者

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

抵扣说明:

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

余额充值