Backbone vs Ext JS 4 MVC

导读

最近一段时间,我在研究移动WebApp应用开发,想在设计WebApp前端JS构架时,使用MVC分层技术,经过一段时间的技术选型,最终确定使用Backbone JS作为底层基础MVC框架。在使用Backbone写示例时,总是觉得非常怪,但又说不出怪在哪,所以,就想通过Backbone与Ext JS 4 MVC的对比,来发现Backbone的缺点与优化点。PS:由于我在做Desktop前端JS开发时,十分青睐Ext JS这一类的框架,Ext JS 4 MVC是我认为在所有框架中做得最好的。

 

特性对比

在对比两个MVC框架之前,必须理解四个十分重要的特性:

  • UI Bindings:[UI 绑定] 我想说的不仅仅是模板,而是想谈一种在底层模型出现变化时,视图层能够自动刷新的方法。一旦您用过了支持 UI Binding 的框架(例如Ext)就很难放手回头了。
  • Composed Views:[组件化视图] 与所有的软件开发者一样,我也喜欢编写模块化、可重用的代码。基于这样的原因,当给 UI 编程的时候,我喜欢使用视图的方法来开发(个人更偏好在模板层时使用),当然这样也就需要拥有足够丰富的视图组件来支持。
  • Web Presentation Layer:[web 表示层] 我们在编写 web 程序时想要 Native 风格的组件,但是也没有理由来为一个 web 框架来创建它自己的布局管理器。HTML 和 CSS 是目前解决样式与布局的最好的方法,框架也应该以这一点为核心。
  • Play Nicely With Others:[兼容,友好] 不得不承认jQuery是十分犀利的。我不喜欢那种绑定着一个定制的jQuery副本的框架,而推荐直接使用jQuery。

下面是两个框架对于四种特性支持程度的对比

 

实例对比

咱们先看一个简单的小例子,分别使用Ext JS与Backbone实现。这个例子也是Ext JS 4官方源码中的一个例子,参见http://dev.sencha.com/deploy/ext-4.1.0-gpl/examples/app/simple/simple.html

对Ext JS 4 MVC不熟悉的同学,可以阅读文章ExtJS 4 MVC架构讲解,这篇文章对Ext JS 4 MVC讲解得很透彻。

 

Ext JS 4 MVC例子

1、目录结构。


2、定义Application。你可以把app当作是一个应用入口,app包含应用的全局配置,同时也负责维护模型、视图、控制器的引用。Ext.app.Application本身也是继承自Ext.app.Controller,具体参见源码与官方文档。

Ext.application({
    name: 'AM',

    // automatically create an instance of AM.view.Viewport
    autoCreateViewport: true,

    controllers: [
        'Users'
    ]
}); 


3、定义Viewport。Viewport中定义了app被加载时的初始视图。

Ext.define('AM.view.Viewport', {
    extend: 'Ext.container.Viewport',

    layout: 'fit',
    items: [{
        xtype: 'userlist'
    }]
});

 
4、定义控制器。Controller是Model与View的粘合剂,Controller的control()函数使用ComponentQuery表达式设置组件视图的事件监听,这样就很好的将视图的控制逻辑与View本身分离,达到View重用的目的,当View是由组件构成时,组件的重用就显得很重要。不熟悉ComponentQuery请参见官方文档。

Ext.define('AM.controller.Users', {
    extend: 'Ext.app.Controller',

    stores: ['Users'],

    models: ['User'],

    views: ['user.Edit', 'user.List'],

    refs: [
        {
            ref: 'usersPanel',
            selector: 'panel'
        }
    ],

    init: function() {
        this.control({
            'viewport > userlist dataview': {
                itemdblclick: this.editUser
            },
            'useredit button[action=save]': {
                click: this.updateUser
            }
        });
    },

    editUser: function(grid, record) {
        var edit = Ext.create('AM.view.user.Edit').show();

        edit.down('form').loadRecord(record);
    },

    updateUser: function(button) {
        var win    = button.up('window'),
            form   = win.down('form'),
            record = form.getRecord(),
            values = form.getValues();

        record.set(values);
        win.close();
        this.getUsersStore().sync();
    }
});

 
5、Model和View。在此略过代码部分,对于不熟悉Ext的同学,参见官方的源码及例子。Ext JS的Model、Store和View实现了UI Binding,当Model数据发生变化时自动完成View刷新。在上面的例子中,有一行代码record.set(values);,Record就是一个Model实例,当record被赋值时视图被刷新,这部分代码在ExtJS 4 MVC架构讲解文中有详细描述。

 

Backbone MVC例子

1、定义Model。Backbone的Model与Ext Model差不多,但是,Ext Model支持对象依赖关联,这个在特性复杂的企业应用中会比较有用,文章末尾会详细的解释对象依赖关联。Collection与Ext Store在概念上相似,但是,Collection仅仅是一个集合,而Store则是Ext非常重要的一个功能,它是Ext实现数据交互的重要中间件,功能非常强大,有兴趣的同学可以翻阅官方文档。

var User = Backbone.Model.extend({
    idAttribute: 'id',
    url: '../testdata'
});

var uer = new User();

var UserList = Backbone.Collection.extend({
    url: '../testdata',
    model: User
});

var users = new UserList();

 
2、定义View。Backbone的View可以结合JS模版引擎实现视图渲染,视图事件控制使用事件委托的方式,例子中,el对象绑定一个委托click事件,当点击tr时调用函数showProfile,具体View事件请参见Backbone官方源码。视图控制事件监听应该出现在Controller中,由于Backbone没有Controller的概念,所以视图控制事件监听在View中实现,与视图渲染混在一起,导致视图无法重用,没有达到MVC分层的目的。现在,我们换一种思路思考,把Backbone View看作是一个Controller,View仅仅使用是一个HTML模版,虽然有点牵强,但视乎也是MVC。Backbone在早期的版本是有Controller这个类,但在新版本将Controller重命名成Router,我想Backbone作者也意识到了这个问题的存在吧!

var HomeView = Backbone.View.extend({
    el: $('#mainview'),

    events: {
        'click tr': 'showProfile'
    },

    showList: function() {
        var html = ['<table>'];
        users.each(function(uer) {
            html.push('<tr>');
            html.push('<td>', uer.get('firstname'), '</td>');
            html.push('<td>', uer.get('lastname'), '</td>');
            html.push('</tr>');
        });
        html.push('</table>');
        this.$el.html(html.join(''));
    },

    showProfile: function() {
        this.$el.html('Hello, ' + uer.get('firstname') + ' ' + uer.get('lastname'));
    }
});

var home = new HomeView();

 
3、定义Router。Router是个好东西,可以监听地址栏hash改变,实现页面跳转的控制逻辑。这视乎和Controller有点关系,但又能不说Router是Controller,这也是Controller重命名成Router的一个原因。

var AppRouter = Backbone.Router.extend({
    routes: {
        'list': 'list',
        'profile/:id': 'getProfile'
    },

    getProfile: function(id) {
        uer.set('id', id);
        uer.fetch({
            type: 'POST',
            data: {
                id: id
            },
            success: function() {
                home.showProfile();
            }
        });
    },

    list: function() {
        users.fetch({
            type: 'POST',
            success: function() {
                home.showList();
            }
        });
    }
});

new AppRouter();

Backbone.history.start();  

 

总结

Ext JS 4 MVC是我认为非常完美的MVC框架之一,但是太依赖Ext的体系,很难从体系中剥离出来。


Backbone JS优点、缺点都比较明显:

  • 优点:小巧、轻便可以很容易的集成到应用中,Backbone MVC可以适用大部分的项目需求。
  • 缺点:Backbone是MVC的不完整实现,只实现了部分,功能比较弱。

我会考虑增加一些Backbone的功能,如Collection和Model的离线缓存,UI绑定数据改变自动渲染,在业务层封装出类似Ext的MVC,模版与组件化是视图渲染的两种主要方式。

 

扩展阅读------对象依赖关联

一个Model对象与其他Model对象存在依赖关系。定义两个Model:User、Post,User与Post的关系是一对多。
服务端响应JSON格式:

{
    id: 'user1',
    posts: [{
        id: 'post1',
        user_id: 'user1',
    }, {
        id: 'post2',
        user_id: 'user1',
    }, {
        id: 'post3',
        user_id: 'user1',
    }]
}

 
使用Ext JS 4定义Model:

Ext.define('Post', {
    extend: 'Ext.data.Model',
    fields: ['id', 'user_id'],
    belongsTo: 'User'
});

Ext.define('User', {
    extend: 'Ext.data.Model',
    fields: ['id'],
    hasMany: {model: 'Post', name: 'posts'}
});

 
数据访问:

User.load('user1', {
    success: function(user){
        user.posts().each(function(rec){
            console.log(rec.get('id'));
        });
    }
});

 

参考资料

 

posted on 2013-05-02 18:32  max12  阅读(551)  评论(0编辑  收藏  举报