MVVM(Model-View-ViewModel)是在MVC(Model-View-Control)模式之后引出的新的开发模式,他与MVC模式一样用于把视图(界面)和数据进行解耦,不同的是采用ViewModel来完成数据与视图的双向绑定,通过自动化的方式承担大部分数据工作,来解决由于界面复杂化和快速迭代带来的问题。它的技术模型如下图所示
如上图所示ViewModel主要职责包含如下几方面
1、完成数据到界面的自动化展示拼装而不需要像原来的模式一样编写独立的模板例如
上述代码中通过在DOM对象中设定data-bind属性,使用MVVM.ViewModel完成了DOM对象与数据的自动关联,开发人员不必把部分单独制作一个模版也不需要使用双引号和加号进行拼装,一切都是自动执行。 再复杂一点,例如
上述代码中通过在DOM对象中通过控制器for和mvvm-scope实现的了
根据数据的条数进行复制拼装。这里可以清楚的体现出JS开发人员不再需要单独编写模板,而是直接把数据与网页中的DOM对象进行拼装。这种方式我们称之为DOM模版。他的最大优势就是静态界面制作人员输出的静态页面即可直接用于界面数据展现。解耦了界面(View)与数据(Model),使界面在不断迭代调整时不会引起JS开发人员的重复返工。
2、其次完成界面与数据的双向绑定,即用户的输入自动变更数据对象中的属性,同时数据对象中数据的变更也会自动影响界面上展示内容的变化,这部分也不需要开发人员进行过多代码编写,大部分场景下可以自动化完成。其实上一个范例中如果数据产生变化时,界面也会自动进行重构,实现了数据向界面的绑定。而界面控件向数据的绑定也是一样的,我们可以参考如下范例
上述代码中,我们使用value控制器完成了Model对象数据和input的双向绑定。由于Model有默认值,因此界面初始显示时会自动在编辑框中显示默认内容,当用户在编辑框中进行修改后,会自动变更Model中的数据。这就实现了Model和输入控件间的双向绑定。span随着输入框内容的变化而变化可以反映出数据的自动同步。
从上述代码还可以带来一个附加的好处,传统我们需要完成DOM元素数据读写时,需要使用选择器来获取DOM对象例如$(“input”) $(“#btn”) $(“.btn”)等,然后再向对象赋值或读取,但当View改变时,例如input换成了textarea、类的名字产生了变化、元素的ID产生了变化,我们都需要在JS侧修改代码。但采用上述上述方式后,数据的映射不再在JS侧体现,而是配置在DOM元素属性中,因此元素的名字、类等的变化都不会影响ViewModel和Model侧代码。
3、用户交互行为的处理,例如用户点击按钮、选择元素等。这部分一般需要人工进行开发,但ViewModel提供标准模式,可以保证交互事件处理模式的统一,也可以保证代码的可复用性。我们常见开发模式中关于一个界面中的事件处理是比较分散的,事件接口定义等根据开发人员不同也会产生比较大的差异,ViewModel提供events属性来整合其所对应的View范围内的操作事件,使代码更统一、规范、易阅读。例如
上述代码中,我们为ViewModel指定其所映射的View为DOM的#app-han元素,在ViewModel中我们为events属性添加了对应#btn元素的tap事件的处理函数。这里需要注意,#btn是#app-han的一个子元素,如果在#app-han外面也有同名的#btn元素,这个元素是不会触发点击事件的。因此可以理解为#app-han就是ViewModel内部代码所设定的作用域。在为tap #btn定义的处理函数中,因为我们使用value:firstName和value:lastName实现了数据与DOM元素的双向绑定,因此我们可以直接从ViewModel的model属性中获取到我们在input中输入的数据,而不需要再使用$(“input”).val()硬代码获取数据。
比较传统开发模式和MVVM模式的区别,我们可以看出使用MVVM模式带来了最直观的几种价值
1、开发人员解脱了大量的硬编码来完成界面元素与数据之间的读写操作。解耦了View(HTML)和Model(JSON data)之间的强关联。我们可以在调整View时不影响Model,也可以在Model变化时不影响View,数据的关联通过ViewModel自动实现。
2、MVVM可以使用字符串模版也可以使用DOM模版,但不可否认DOM模版是最能够保证视图(HTML)可测试性的方案。我们可以直接对静态界面制作人员输出的HTML界面进行验证,确认其是否与UI效果图保持一致。因为使用DOM模版方式后,界面不再像传统开发模式一样,需要JS侧人员进行HTML层次的代码调整,转换为JS可以使用的模版,然后拼装再显示在界面上,DOM模版可以使JS侧代码不再会对界面的拼装产生直接影响。同时我们也可以对ViewModel编写独立的测试用例,解决以前界面逻辑需要大量人工测试的问题。
3、代码的复用性提高,因为我们在开发时把相对于View的事件逻辑处理进行了规范化统一化开发。因此可以很方便的在不同应用项目中重用这部分操作逻辑。
4、静态页面开发人员和JS代码开发人员工作分离,使各岗位人员更关注于本身的工作,不再需要处理各种相互影响产生的问题。