javascript基础修炼(9)——MVVM中双向数据绑定的基本原理

开发者的javascript造诣取决于对【动态】和【异步】这两个词的理解水平。

javascript基础修炼(9)——MVVM中双向数据绑定的基本原理

一. 概述 1.1 MVVM模型

javascript基础修炼(9)——MVVM中双向数据绑定的基本原理

MVVM模型是前端单页面应用中非常重要的模型之一,也是Single Page Application的底层思想,如果你也因为自己学习的速度拼不过开发框架版本迭代的速度,或许也应该从更高的抽象层次去理解现代前端开发,因为其实最核心的经典思想几乎都是不怎么变的。关于MVVM的文章已经非常多了,本文不再赘述。

笔者之前听过一种很形象的描述觉得有必要提一下,Model可以想象成HTML代码,ViewModel可以想象成浏览器,而View可以想象成我们最终看到的页面, 那么各个层次所扮演的角色和所需要处理的逻辑就比较清晰了。

1.2 数据绑定

数据绑定,就是将视图层表现和模型层的数据绑定在一起,关于MVVM中的数据绑定,涉及两个基本概念单向数据绑定双向数据绑定,其实两者并没有绝对的优劣,只是适用场景不同,现×××发框架都是同时支持两种形式的。

双向数据绑定由Angularjs1.x发展起来,在表单等用户体验高度依赖于即时反馈的场景中非常便利,但并不是所有场景下都适用的,Angularjs中也可以通过ng-bind=":expr"的形式来实现单向绑定;在Flux数据流架构的影响下,更加易于追踪和管理的单向数据流思想出现了,各主流框架也进行了实现(例如redux,vuex),在单向数据绑定的框架中,开发者仍然可以在需要的地方监听变化来手动实现双向绑定。

关于Angularjs1.x中如何通过脏检查机制来实现双向数据绑定和管理,可以参见《构建自己的AngularJS,第一部分:Scope和Digest》一文,讲述得非常详细。

二. 基于数据劫持的绑定 2.1 Vue2.0源码的学习困惑

javascript基础修炼(9)——MVVM中双向数据绑定的基本原理

Vue2.0版本中的双向数据绑定,很多开发者都知道是通过劫持属性的get/set方法来实现的,上图已经展示了双向数据绑定的代码框架,分析源码的文章也非常多,许多文章都将重点放在了发布订阅模式的实现上,笔者自己阅读时有两大困扰点:

第一,即使通过defineProperty劫持了属性的get/set方法,不知道数据模型和页面之间又是如何联系起来的。(很多文章都是顺带一提而没有详述,实际上这部分对于整体理解MVVM数据流非常重要)

第二,Vue2.0在实现发布订阅模式的时候,使用了一个Dep类作为订阅器来管理发布订阅行为,从代码的角度讲这样做是很好的实践,它可以将订阅者管理(例如避免重复订阅)这种与业务无关的代码解耦出来,符合单一职责的开发原则。但这样做对于理清代码逻辑而言会造成困扰,让发布-订阅相关的代码段变得模糊,实际上将Dep类与发布者类合并在一起,绑定原理会更加清晰,而在代码迭代中,考虑到更多更复杂的情况时,即使你是框架的设计者,也会很自然地选择将Dep抽象成一个独立的类。

如果你也在阅读博文的时候出现同样的困惑,强烈建议读完本篇后自己动手实现一个MVVM的双向绑定,你会发现很多时候你不理解一些代码,是因为你不知道作者面对了怎样的实际问题

2.2 从标签开始的代码推演

ps:下文提及的观察者类和发布者类是指同一个类。

2.2.1 示例代码

我们先来写几个包含自定义指令的标签:

<div> <input type="text" d-model="myname"> <br> 输入的是:<span d-bind="myname"></span> <br> <button d-click="alarm()">广播报警</button> </div> <script> var options = { el:'app', data:{ myname:'僵尸' }, methods:{ alarm:function (node,event) { window.alert(`一大波【${this.data.myname}】正在靠近!`); } } } //初始化 var vm = new Dash(options); </script>

需要实现的功能就如同你在所有框架中见到的那样:标签的值通过d-model指令和数据模型中的myname进行双向绑定,标签的值通过d-bind指令从myname单向获取,标签的点击响应通过d-click绑定数据模型中的alarm()方法。初始化所用到的方法已经提供好了,假如我们要在一个叫做Dash的MVVM框架中实现数据绑定,那么第一步要做的,是模板解析。 2.2.2 模板解析

DOM标签自身是一个树形结构,所以需要从最外层的

为起点以递归的方式来进行解析。

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

转载注明出处:https://www.heiqu.com/wpxwsd.html