双向绑定原理
首先,vue实现数据双向绑定的原理是:采用数据劫持结合发布者-订阅者模式,通过Object.defineProperty(obj,props)来劫持各个属性的setter和getter方法,在数据变动时发布消息给订阅者,触发相应的回调函数。当把一个普通object对象传给
Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为
getter/setter。
Object.defineProperty()
定义
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法
Object.defineProperty(obj, prop, descriptor)
参数介绍
参数 | 说明 |
---|---|
obj | 要定义属性的对象。 |
prop | 要定义或修改的属性的名称或 Symbol 。 |
descriptor | 要定义或修改的属性描述符。 |
实现思路
- 首先定义一个普通的劫持对象,也就是defineObj,通过Object.defineProperty()来劫持对象,同时添加好被劫持对象的setter和getter方法。在劫持对象被访问取值时触发getter方法,赋值值时触发setter方法
- 给页面的input添加一个监听方法,来监听input输入值的改变,当input输入改变时,将新值赋值给劫持对象,这个时候就会触发接触对象的setter方法。来改变视图模型的值。在我们直接访问劫持对象属性时,触发getter,直接返回被访问的值。并反应在视图模型中。
代码片段
<div class="body">
<label for="input">输入</label>
<input type="text" id="input">
<span>输出:</span><span id="output"></span>
</div>
<script>
/**
* 原生js实现vue数据双向绑定:
*
* 首先,vue实现数据双向绑定的原理是:采用数据劫持结合发布者-订阅者模式,通过Object.defineProperty(obj,props)来劫持各个属性的setter和getter方法,
* 在数据变动时发布消息给订阅者,触发相应的回调函数。
* 当把一个普通object对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,
* 用 Object.defineProperty() 将它们转为 getter/setter。
*
*
* Object.defineProperty()
*
* Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
* 语法:
* Object.defineProperty(obj, prop, descriptor)
* obj 要定义属性的对象。
* prop 要定义或修改的属性的名称或 Symbol 。
* descriptor 要定义或修改的属性描述符。
*
* 思路:
* 1、首先定义一个普通的劫持对象,也就是defineObj,通过Object.defineProperty()来劫持对象,同时添加好被劫持对象的setter和getter方法。
* 在劫持对象被访问取值时触发getter方法,赋值值时触发setter方法
* 2、给页面的input添加一个监听方法,来监听input输入值的改变,当input输入改变时,将新值赋值给劫持对象,这个时候就会触发接触对象的setter方法。
* 来改变视图模型的值。在我们直接访问劫持对象属性时,触发getter,直接返回被访问的值。并反应在视图模型中。
* */
let input = document.getElementById("input")
let output = document.getElementById("output")
//劫持对象
let defineObj = {}
input.addEventListener("input", function (e) {
let { value } = e.target
defineObj.value = value
})
Object.defineProperty(defineObj, "value", {
configurable: true,
enumerable: true,
set: function (nVal) {
value = nVal
input.value = nVal
output.innerHTML = nVal
},
get: function () {
return value
}
})
</script>