zoukankan      html  css  js  c++  java
  • 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'));
            });
        }
    });

    参考资料

    原创文章,转载请注明出处http://www.cnblogs.com/zhangdaiping
  • 相关阅读:
    接口内容小结
    接口的静态方法与私有方法
    接口的默认方法
    发红包O
    抽象
    《大道至简》读后感
    重写
    继承中的二义性问题
    数学应用
    继承
  • 原文地址:https://www.cnblogs.com/zhangdaiping/p/3055132.html
Copyright © 2011-2022 走看看