7

对于前端,有时候需要实现视图层和数据层的双向绑定(two-way-binding), 例如当前流行的各种框架和类库:Vue.jsAngular.jsReact.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的介绍。

如果使用jQuery实现起来更加简单明了。
传送门在此

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

参考资料:

javascript实现数据双向绑定的三种方式

谈谈JavaScript中的双向数据绑定

非常简单的js双向数据绑定框架(三)


大轰
111 声望3 粉丝

Show me the code.