vue是一个很是优秀的框架,其优秀的双向绑定原理,mvvm模型,组件,路由解析器等,很是的灵活方便,也使开发者可以着重于数据处理,让开发者更清晰的设计本身的业务。html
双向绑定,就是数据变化的时候,自动触发视图的变化。vue
咱们都理解,vue2.0中,双向绑定的核心为Object.defineProperty(obj, prop, descriptor)
,方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象git
参数obj
为要在其上定义属性的对象。
参数prop
为要定义或修改的属性的名称。
参数descriptor
为将被定义或修改的属性描述符。
github
返回被传递给函数的对象。
浏览器
咱们能够新建一个项目,用来模拟及学习vue
双向绑定的相关内容框架
+ vue相关 + |- 双向绑定原理 + |- js + |- myVue.js + |- index.html
修改index.html中的内容,引入本身建立的myVue.js。mvvm
+ <!DOCTYPE html> + <html lang="en"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Document</title> + </head> + <body> + + <script src="./js/myVue.js"></script> + </body> + </html>
编辑myVue.js
的内容,来尝试一下Object.defineProperty(obj, prop, descriptor)
这个APIide
+ var data = { + a: 1 + } + Object.defineProperty(data, 'a', {// 为data中的a进行拦截,读取a的时候返回本身新建的_a的值,设置a的值的时候,设置到_a上。这样,开发者对a的操做,都会映射到咱们新建的虚拟的_a变量上 + configurable: true, // 是否容许删除属性,默认true + enumerable: true, // 是否容许遍历,默认true + get: function () { + console.log('我被读取了,返回了_a的值', this._a) + return this._a + }, + set(value) { + // this.a = value; + this._a = value; + console.log('我被设置了,被设置的值为', this._a, '并放进了a的对象中') + } + })
在浏览器中,打开页面,并查看控制台,对data.a
进行操做函数
data.a myVue.js:8 我被读取了,返回了_a的值 undefined undefined —————————————————————————————————————————————————————————————————————————————— data.a = 10 myVue.js:14 我被设置了,被设置的值为 10 并放进了a的对象中 10 —————————————————————————————————————————————————————————————————————————————— data.a myVue.js:8 我被读取了,返回了_a的值 10 10
能够看到,咱们对data.a进行的操做,实际改变的变量是咱们已经拦截的_a
变量。
目前出现的问题是,第一次读取的时候,这个值没有被设置上,在下面来模拟解决方案post
声明概念_
开头的变量一版为私有变量,外部没法访问,可是咱们如今在控制台中输入并修改私有变量data._a
data._a 10 —————————————————————————————————————————————————————————————————————————————— data._a = 20 20 —————————————————————————————————————————————————————————————————————————————— data._a 20 —————————————————————————————————————————————————————————————————————————————— data.a myVue.js:8 我被读取了,返回了_a的值 20 20
却能够拿到私有变量中的_a
的值,也能够进行无拦截的修改,这显然是咱们所不但愿的
因此咱们能够为Object.defineProperty(obj, prop, descriptor)
来进行封装一次,把咱们理解的_a
变成一个私有变量
修改myVue.js
的内容为以下内容,
var data = { a: 1 } myDefineProperty(data, 'a') function myDefineProperty(obj,key){//对Object.defineProperty进行一次拦截,使外界没法访问私有变量value var value = obj[key]; Object.defineProperty(obj,key,{// 为data增长 configurable: true, // 是否容许删除属性,默认true enumerable: true, // 是否容许遍历,默认true get: function () { console.log('我被读取了,返回了value的值', value) return value }, set(newValue) { value = newValue; console.log('我被设置了,被设置的值为', newValue, '并放进了value的对象中') } }) }
而后再查看控制台
data._a undefined —————————————————————————————————————————————————————————————————————————————— data.value undefined —————————————————————————————————————————————————————————————————————————————— data.a myVue.js:12 我被读取了,返回了value的值 1 1 ——————————————————————————————————————————————————————————————————————————————
开发者就没法自行操做咱们设计的私有变量value的内容了
自此,咱们解决了,对一个对象属性的拦截,而且阻止了用户对咱们设计的私有变量进行操做
咱们知道了拦截属性以后,那么就进一步来实现,一个简单的双向绑定
咱们修改一下index.html
中的内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> + <input type="text" @change='changeIpt'> + <p id='changeValue'></p> </head> <body> <script src="./js/myVue.js"></script> </body> </html>
并在myVue.js
中,在set中添加双向绑定的操做
var data = { a: 1 } myDefineProperty(data, 'a') + var ipt = document.getElementById('ipt'); + ipt.oninput = function(e){ + data.a = e.target.value + } function myDefineProperty(obj,key){ var value = obj[key]; Object.defineProperty(obj,key,{// 为data增长 configurable: true, // 是否容许删除属性,默认true enumerable: true, // 是否容许遍历,默认true get: function () { console.log('我被读取了,返回了value的值', value) return value }, set(newValue) { value = newValue; + document.getElementById('iptValue').innerText = newValue; + ipt.value = newValue; console.log('我被设置了,被设置的值为', newValue, '并放进了value的对象中') } }) }
而后咱们在input
框里输入内容,便表现出了双向绑定的能力。
记得打开控制台哦!~下方为录制的屏幕,可能没法正常显示,能够点击上方demo来查看
以为好的话,能够给个人 github点个star
哦