现在的前端框架 如果没有个数据的双向/单向绑定,都不好意思说是一个新的框架,至于为什么需要这个功能,从jq或者原生js开始做项目的前端工作者,应该是深有体会。
以下也是个人对vue的双向绑定原理的一些浅薄认识,当然 再vue框架的真正实现上,比我分析的要复杂的多。主要是来了解思想
首先看下下面这段主要代码:
let data = {price:5,quantity:2}; let target = null; // 一个抽象出来的dep类 class Dep { constructor () { this.subscribers = []; // 每次调用类时,都会将这个属性更新 } depend() { // 当 target存在 并且没有被订阅 if(target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } // 循环更新被存储的函数/属性 notify() { this.subscribers.forEach(sub => sub()) } } // 循环data的所有属性 Object.keys(data).forEach(key => { let internalValue = data[key]; // 每个属性获得一个依赖实例 const dep = new Dep(); // 对当前data属性描述符 get与set进行数据拦截,进行获取/设置新的data属性值 Object.defineProperty(data,key, { get() { dep.depend() // 存储一个当前我们需要进行双向数据绑定数据/函数。 return internalValue; } set(newValue) { internalValue = newValue; dep.notify(); // 重新更新一个存储的函数。 } }) }) // 一个只有当企图使用数据双向绑定时才会触发的函数。 function watcher(myFunc) { target = myFunc; target(); target = null; } watcher(() => { data.total = data.price * data.quantity; })
首先我们来解释一下 我们的vue项目 所有的函数或者是某个被用来做双向数据绑定的值都是绑定在 data 上的,也就是 data.property
1:dep 一个用来进行数据双向绑定的类,
a: constructor: 绑定属性,每次进来需要相应双向绑定时 都将目标属性进行重置,用来进行之后的操作。
b: depend: 这个解释为依赖,可以理解为将目标函数(属性 比如data.name),推进一个全局的存储阵列中。
c: notify:这个可以解释为更新页面被绑定的数据 执行这个函数,可以将重新设置/输入的属性 发生视图上的变化。
2:obeject.defiepropoerty() 这个js api接口是实现当数据发生改变时 拦截数据(属性)的。
该api方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
// 语法: Object.defineProperty(obj, prop, descriptor)
obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性。
返回值是:被传递给函数的对象。
简单的描述:
该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...in
或 Object.keys
方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty()
添加的属性值是不可修改的。
如果您能看懂上面的代码运行模式 那么就可以看懂下面的这幅图了,基本思想就是这样。