首页 > 代码库 > MVVM框架对比

MVVM框架对比

MVVM框架对比

  • MVC和MVP简介
  • MVVM
  • Vue.js、Angular.js、Ember、Backbone等框架对比
  • 双向绑定原理
  • Virtual DOM

前端由于发展比较迅速,框架的更新迭代也比较快,从最初的 backbone.js 到后来的Ember、Knockout、Angular.js, 再到现在的Vue.js、React。

MVC和MVP简介

技术分享

  • 视图(view):用户界面
  • 控制器(controller):业务逻辑
  • 模型(model):数据保存

通信方式如下:

  1. view传送指令到controller
  2. controller完成业务逻辑后,model改变状态
  3. model将新的数据发送到view,用户得到反馈

MVC在前端中的典型实践 Backbone

技术分享

MVP

  • MVP模式将controller改名为Presenter,同时改变了通信方向

技术分享

  1. 各部分之间的通信,都是双向的。
  2. view与model不发生联系,都通过presenter传递。
  3. view非常薄,不部署任何业务逻辑,被称为被动视图,所有逻辑都部署在Presenter。

MVVM

技术分享

  • 唯一的区别是MVVM采用了双向数据绑定,view的变动自动反映在view-model。Vue.js、Angular、Ember都采用这种模式;

每一个框架的诞生都是为了解决客观存在的问题,所以架构是对客观不足的妥协。

那么这么多MVVM框架的诞生是为了解决什么问题?

  • 如何处理数据的更新和界面的更新。

Vue.js、Angular、Ember、Backbone 对比

功能

作为构建应用的基础,框架必须具备一些重要的功能,比如,视图绑定、双向绑定、筛选、可计算属性、脏属性、表单验证等等

功能 Vue Angular Backbone Ember
可观察对象(observable) y y y y
路由(routing) y y y y
视图绑定(view binding) y y - y
双向绑定(two way binding) y y - y
部分视图(partial view) y y - y
筛选列表视图(filtered list view) y y - y
  • 可观察对象:可以被监听是否发生变化的对象
  • 路由
  • 视图绑定:在视图中使用可观察对象,让视图随着可观察对象的变化而自动刷新
  • 双向绑定
  • 部分视图:包含其他视图的视图
  • 筛选列表视图:用于显示根据某些条件筛选出来的对象视图

灵活性

有时候,框架配合一些现成的插件和库来使用,可能要比使用框架原生同类功能效果更好,而这种插件和库几乎遍地都是(不下数百个),又各有特色。因此,能够把这些库和插件整合到MVC框架中也非常重要。

Backbone是其中最灵活的一个框架,因为它的约定和主张最少。使用Backbone需要你自己作出很多决定。

Ember、Angular、Vue.js 也都还算灵活,可有时候你会发现,就算不喜欢它们的某些实现方法,你也只能默默忍受。 这是在选择Ember或Angular时必须考虑的。

上手难度

Vue.js
上手比较容易,官方文档比较清晰。专注于MVVM的ViewModel层,实际的DOM封装和输出格式都被抽象为了Directives和Filters。

Angular 4.0
一开始会让人大呼过瘾,因为可以利用它干好多意想不到的事,而且学习难度不高。乍一看让人觉得很简单。可是,进了门之后,你会发现后面的路还很长。应该说这个框架比较复杂,而且有不少标新立异之处。想看着它的文档上手并不现实,因为Angular制造的概念很多,而文档中的例子又很少。

Backbone

Backbone的基本概念非常容易理解。但很快你会发现它对怎么更好地组织代码并没有太多主张。为此,你得观摩或阅读一些教程,才能知道在Backbone中怎么编码最好。而且,你会发现在有了Backbone的基础上,还得再找一个库(比如Marionette或Thorax)跟它配合才能得心应手。正因为如此,我不认为Backbone是个容易上手的框架。

Ember

Ember的上手难度与Angular有一拼,我认为学习Ember比学习Angular总体上容易一些,但它要求你一开始就要先搞懂一批基本概念。而Angular呢,一开始不需要这么费劲也能做一些让人兴奋不已的事儿。Ember缺少这种前期兴奋点。

社区支持

能轻易找到参考资料和专家帮忙吗?

Backbone的社区很大,这是人所共知的事实。关于Backbone的教程也几乎汗牛充栋,StackOverflow和IRC社区非常热闹。

Angular和Ember社区也相当大,教程什么的同样不少,StackOverflow和IRC也很热闹,但还是比不上Backbone。

Vue的社区比较一般,可能是由于框架还处于发展阶段,还未达到上述几个框架的稳定和成熟。

有没有插件或库构成的生态系统?

Backbone的选择是最多的,可用插件俯拾皆是,这一点让其他框架都望尘莫及。Angular的生态圈加上Angular UI还是很令人瞩目的。我觉得Ember的下游生态虽然欠发达,但Ember本身很受欢迎, 所以前景十分乐观。

文件大小

Vue和Angular是唯二不需要其他库就能使用的,其他几个框架都需要依赖。
Backbone至少需要 Underscore 和 Zepto。虽然在Underscore中可以使用最小的模板来渲染视图,但多数情况下,还要借助更好的模板引擎,比如 Mustache 。
Ember 需要 jQuery 和 Handlebars。

Vue Angular Backbone Ember
18kb 80kb 61kb 269kb

成熟度

这个框架成熟吗,经过实际检验了吗,有多少网站在用它呢?

使用Backbone的网站不计其数。最近两年,它的核心代码没怎么改过,这是成熟的一个重要标志。

Ember已经不是新框架了,但它的重大变更还是经常有,前几月刚刚稳定下来。因此,目前还不能说它是个成熟的框架。

Angular似乎比Ember更稳定,验证的示例也更多,但不能与Backbone相提并论。

Vue 属于一个新项目,2014-3-20 发布的0.10.0 Release Candidate版本。

双向绑定

this.showLoading = false
this.cmsData = http://www.mamicode.com/data
this.showDownload = data.template.isDownload
this.topBar.displaySharebutton = data.displaySharebutton
this.topBar.title = data.template.title

双向绑定的基本原理是通过属性的读写器来实现。

function Person() {
var name = ”;
var friends = [];
Object.defineProperty(this, ‘name’, {
get: function () {
console.log(‘get!’)
return name;
},
set: function (value) {
name = value;
friends.push(name)
}
});
this.getFriends = function() {
return friends;
};
}

Virtual DOM

最近一两年前端最火的技术莫过于ReactJS,即便你没用过也该听过,ReactJS由业界顶尖的互联网公司facebook提出,其本身有很多先进的设计思路,比如页面UI组件化、虚拟DOM等。

为什么需要虚拟DOM?

DOM是很慢的,其元素非常庞大,页面的性能问题鲜有由JS引起的,大部分都是由DOM操作引起的。如果对前端工作进行抽象的话,主要就是维护状态和更新视图;而更新视图和维护状态都需要DOM操作。其实近年来,前端的框架主要发展方向就是解放DOM操作的复杂性。

理解虚拟DOM

虚拟的DOM的核心思想是:对复杂的文档DOM结构,提供一种方便的工具,进行最小化地DOM操作。这句话,也许过于抽象,却基本概况了虚拟DOM的设计思想。

  1. 提供一种方便的工具,使得开发效率得到保证;
  2. 保证最小化的DOM操作,使得执行效率得到保证;

//设置虚拟dom的相关属性
var VElement = function(tagName, props, children) {
    //保证只能通过如下方式调用:new VElement
    if (!(this instanceof VElement)) {
        return new VElement(tagName, props, children);
    }

    //可以通过只传递tagName和children参数
    if (util.isArray(props)) {
        children = props;
        props = {};
    }
    this.tagName = tagName;
    this.props = props || {};
    this.children = children || [];
    this.key = props ? props.key : void 666;
    var count = 0;
    util.each(this.children, function(child, i) {
        if (child instanceof VElement) {
            count += child.count;
        } else {
            children[i] = ‘‘ + child;
        }
        count++;
    });
    this.count = count;
};

通过VElement,我们可以很简单地用js表示DOM结构。


var vdom = VElement(‘div‘, { ‘id‘: ‘container‘ }, [
VElement(‘h1‘, { style: ‘color:red‘ }, [‘simple virtual dom‘]),
VElement(‘p‘, [‘hello world‘]),
VElement(‘ul‘, [VElement(‘li‘, [‘item #1‘]), VElement(‘li‘, [‘item #2‘])])
]);

上面的javascript代码可以表示如下DOM结构:

<div id="container">
<h1 style="color:red">simple virtual dom</h1>
<p>hello world</p>
<ul>
<li>item #1</li>
<li>item #2</li>
</ul>
</div>

比对两棵DOM树的差异

技术分享

在用JS对象表示DOM结构后,当页面状态发生变化而需要操作DOM时,我们可以先通过虚拟DOM计算出对真实DOM的最小修改量,然后再修改真实DOM结构(因为真实DOM的操作代价太大)。

  1. 如何比较两棵DOM树
    function diff(oldTree, newTree) {
    //节点的遍历顺序
    var index = 0;
    //在遍历过程中记录节点的差异
    var patches = {};
    //深度优先遍历两棵树
    dfsWalk(oldTree, newTree, index, patches);
    return patches;
    }
  2. 如何记录节点之间的差异
  3. 对真实DOM进行最小化修改

针对DOM的处理,可分为:

  • 修改节点属性 PROPS
  • 修改节点文本内容 TEXT
  • 替换原有节点 REPLACE
  • 调整子节点,包括移动、删除 REORDER
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    MVVM框架对比