对于前端,有时候需要实现视图层和数据层的双向绑定(two-way-binding), 例如当前流行的各种框架和类库:Vue.js、Angular.js、React.js。 然而,他们最原始的实现方式其实都相对比较简单,只不过是后来随着各种Bug的出现,才一如滚雪球般地被不断优化和壮大。
所以,不要畏惧,多多学习并摄取它们的精华。
这里, 我也希望通过简单的思路让你对数据的双向绑定有个大概了解,然后去看各种MVVM框架中对于数据双向绑定的实现才不会一头雾水。
先复习个知识点
Nodes 和 Elements 的区别
Element继承了Node,而Element是众多Node类型中的其中一个, nodeType === 1, 所以,属于Node的属性可以用于Element,但Element的属性无法用于Node,听起来好拗口,看一下代码吧.
<div class="demo">
<p>大</p>
<p>轰</p>
</div>
var el = document.querySelector('.demo');
// true
console.log(el.children[0] instanceof Node);
// true
console.log(el.children[0] instanceof Element);
// true
console.log(el.childNodes[0] instanceof Node);
// false
console.log(el.childNodes[0] instanceof Element);
// undefined
console.log(typeof el.childNodes[0].children);
// object
console.log(typeof el.childNodes[0].childNodes);
什么是数据和视图的双向绑定?
双向绑定对于理解Flux等架构所提倡的单向数据流特性有很好的帮助, 简单点说,就是将数据的变化绑定到UI, 同时UI的变化又和数据同步。这样一来,假如你是全站Ajax,你不用去管数据对UI的影响,同时也不用去管UI变化造成的数据变化,统一了数据操作的入口,非常方便维护。(不知道这样理解对不对, 望指正)
总而言之,双向数据绑定的底层实现大概有两种:
1、手动绑定,同时使用dirty check去循环监听。(Angular.js为代表)
2、前端数据劫持。(使用defineProperty, Vue.js貌似就是使用这种)
手动绑定 循环监听触发 (一)
这种方法的实现类似**订阅者模式**,实现思路是通过DOM的*keydown* *keyup*
*keypress* *change*等事件触发*dirty check*(当然你也可以用setTimeout),
然后循环监听并将value写入某实例变量里面,同时更新DOM。
若是有时间,推荐去看一下Angular.js文档中关于digest / $watch的介绍。
https://jsfiddle.net/fondadam/sdxhhoLx/2/embedded/js,html,result
前端数据劫持 (二)
第三种方法则是Vue.js
等框架使用的数据劫持方式。基本思路是使用Object.defineProperty
对数据对象做属性get和set的监听,当有数据读取和赋值操作时则调用节点的指令,这样使用最通用的=等号赋值就可以触发了。
https://jsfiddle.net/fondadam/a4qhp06s/embedded/js,html,result
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。