MVVM 双向绑定的实现代码(2)

// Dirty detection let elems = [document.getElementById('el'), document.getElementById('input')] let data = { value: 'hello' } // 定义 Directive let directive = { text: function(text) { this.innerHTML = text }, value: function(value) { this.setAttribute('value', value) this.value = value } } // 脏数据循环检测 function digest(elems) { for (let elem of elems) { if (elem.directive === undefined) { elem.directive = {} } for (let attr of elem.attributes) { if (attr.nodeName.indexOf('q-event') >= 0) { let dataKey = elem.getAttribute('q-bind') || undefined // 进行脏数据检测,如果数据改变,则重新执行命令 if (elem.directive[attr.nodeValue] !== data[dataKey]) { directive[attr.nodeValue].call(elem, data[dataKey]) elem.directive[attr.nodeValue] = data[dataKey] } } } } } // 数据监听 function $digest(value) { let list = document.querySelectorAll('[q-bind=' + value + ']') digest(list) } // View 绑定监听 elems[1].addEventListener('keyup', function(e) { data.value = e.target.value $digest(e.target.getAttribute('q-bind')) }, false) // -------- 程序执行 ------- $digest('value') setTimeout(() => { data.value = "Hello world" $digest('value') }, 1000);

总结

上面只是简单地实现了双向绑定,但实际上一个完整的 MVVM 框架要考虑很多东西。在上面的实现中数据劫持的方法更新View 是使用了 Scan 函数,但实际的实现中(比如 Vue)是使用了发布订阅的模式。它只会去更新那些与该 Model 数据绑定的元素,而不会去扫描所有元素。而在脏数据检测中,它去找到了所有绑定的元素,然后判断数据是否发生变化,这种方式只有一定的性能开销的。

参考

现代前端技术解析

代码下载:https://github.com/OreChou/twowaybinding

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/67550813cc27d23bc64f48c2ba1b4eb1.html