`
icekiller110
  • 浏览: 69330 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Backbone使用经验分享

阅读更多

本文不讨论Backbone(一下简称BN)的优缺点,已经认为你在使用BN或者想使用BN。

 

这是我在项目中的使用经验拿出来和大家分享讨论:

(为了保密,以下的代码不是项目中的真是代码,单纯为了举例说明)

 

1. 项目组织结构。

前端使用的ROR,后端是纯RESTFul接口。

 

目录:

MyProject  根路径

    public 公共资源路径

css 层叠样式表库

img 图片库

js JavaScript库

    app.js 实例的初始化文件,项目入口文件

    models.js 原型类库

    views.js 视图类库

    collections.js 集合类库

    router.js 路由类库

    common.js 公共JS库

    views 视图实例库

system 系统管理模块

    users.js 用户管理视图

    roles.js 角色管理视图

        chart 展示图管理模块

        pies.js 饼图管理模块

template 模版库

    system ...

users.html 用户管理使用模版

roles.html 角色管理使用模版

    chart ...

pies.html 饼图展示模版

    common.html 公共展示模版

 

上面仅展示了JSMVC相关的目录结构。蓝色为目录,绿色是文件。

 

其中视图的js和模版分别进行了模块化,创建了对应的目录结构(system和chart)

 

2. Backbone 本身没有模块化,这是我们不太爽,因为如果你对用用户和角色都有CRUD的操作,你为了避免命名冲突就要使用addUser、addRole、editUser、editRole...这当然不爽了,那么我们自己实现模块化。

 

对Model模块化:

 

 

// public/js/models.js
var company = (function(c){
    c.model.system = (function(s){
        s.User = Backbone.Model.extend();
        s.Role = Backbone.Model.extend();

        return s;
    })(c.model.system || {})
    
    return c;
})(company || {});

 

 

对Collection模块化:

 

 

// public/js/collections.js
var company = (function(c){
    c.coll.system = (function(s){
        s.Users = Backbone.Collection.extend({
            url: '/users',
            model: c.system.User
        });

        s.Roles = Backbone.Collection.extend({
            url: '/roles',
            model: c.system.Role
        });

        return s;
    })(c.coll.system || {})
    
    return c;
})(company || {});
 

 

对View类的模块化:

如果是列表视图一般不用创建多个,因为都是在页面的同一地方进行展示,所以使用统一的视图,然后覆盖其render方法即可。

 

对页面的模块化:

 

 

// public/js/views/system/users.js
var company = (function(c){
    c.view.system = c.view.system || {}
    c.view.system.user = {
        list: function(){};
        add: function(){};
        edit: function(id){};
        del: function(ids){};
    };
    return c;
})(company || {});

// public/js/views/system/roles.js
var company = (function(c){
    c.view.system = c.view.system || {}
    c.view.system.role = {
        list: function(){};
        add: function(){};
        edit: function(id){};
        del: function(ids){};
    };
    return c;
})(company || {});
 

 

对Router的模块化:

 

 

// public/js/router.js
var company = (function(c){
    c.router = (function(r){
        r.Base = Backbone.Router.extend({
            routes: {
                "system": "changeToSystem",
                "chart": "changeToChart"
            },
            changeToSystem: function(){},
            changeToChart: function(){}
        });

        r.base = new r.Base();
        return r;
    })(c.router || {})

    var SystemRouterAndSystemView = (function(rs, vs){
        rs.User = Backbone.Router.extend({
            routes: {
                "system/users": "index",
                "system/users/add": "add",
                "system/users/edit/:id": "edit",
                "system/users/del/:ids": "del"
            },
            index: function(){
                vs.user.list();
            },
            add: function(){
                vs.user.add();
            },
            edit: function(id){
                vs.user.edit(id);
            },
            del: function(ids){
                vs.user.del(ids);
            }
        });

        rs.Role = Backbone.Router.extend({
            routes: {
                "system/roles": "index",
                "system/roles/add": "add",
                "system/roles/edit/:id": "edit",
                "system/roles/del/:ids": "del"
            },
            index: function(){
                vs.role.list();
            },
            add: function(){
                vs.role.add();
            },
            edit: function(id){
                vs.role.edit(id);
            },
            del: function(ids){
                vs.role.del(ids);
            }
        });

        s.user = new s.User();
        s.role = new s.Role();
        return [rs, vs];
    })(c.router.system || {}, c.view.system || {})
    c.router.system = SystemRouterAndSystemView[0];
    c.view.system = SystemRouterAndSystemView[1];

    Backbone.history.start();
    // route to first page
    c.router.base.navigate('system', true);

    return c;
})(company || {});
 

 

这样就完成的我们的项目的模块化改造,你已经看见在router中调用的是c.view.system.user.add()和c.view.system.role.add(),此function分别再两个js中,方法名都是add,这样我们的代码清爽多了,也不用在考虑命名冲突的问题了。

 

3. 谈一谈app.js的使用,我的app.js

 

 

var company = (function(c){
    c.view.topMenu = new c.view.TopMenu().render();
    c.view.secondMenu = new c.view.SecondMenu();
    c.view.toolMenu = new c.view.ToolMenu();
    c.view.mainTitleView = new c.view.MainTitle();
    c.view.mainSearchView = new c.view.MainSearch();
    c.view.mainOperationsView = new c.view.MainOperation();
    c.view.mainContentView = new c.view.MainContent().render();
    
    c.initMenusAndTools = function(currentTopMenu){
        // overwrite view of secondMenu   
        c.view.secondMenusView.menus.reset();
        _(currentTopMenu.children).each(function(menu){
            c.view.secondMenusView.menus.add(new c.Menu(menu));
        })

        // overwrite view of  toolMenu
        c.view.toolMenu.collection.reset();
        _(currentTopMenu.toolbar).each(function(menu){
            c.view.toolMenu.collection.add(new c.model.Menu(menu));
        })
    }
    
    return c;
})(company || {});

 

可以看得出来我对页面的基本框架的视图进行的默认的初始化,包括顶级菜单,二级菜单,工具栏,搜索栏,操作按钮集,重要内容显示区。这样只要修改相应的数据,对视图的部分进行修改就可以了。

initMenusAndTools是再模块切换(从system模块切换到chart模块)的时候初始化二级菜单和工具栏用的。

 

创建菜单的数据对象(JSON)。

 

 

// gloabal var for modularization
company = {}
company.model = {}
company.view = {} 
company.coll = {}
company.router = {}

company.menus = [
    {title: 'User', clazz: 'focus', action: '#user',
     children: [
        {title: '用户管理', clazz: 'user', action: '#system/users'},
        {title: '角色管理', clazz: 'role', action: '#system/roles'}
     ],
     toolbar: [
        {title: '新建用户', clazz: 'newUser', action: 'javascript:void(0)'},
        {title: '新建角色', clazz: 'newRole', action: 'javascript:void(0)'}
     ]
    },
    {title: 'Chart', clazz: '', action: '#chart'}
]

 

4. 再说一下项目中的公共组件。

 

    // useage: new c.DisposableView({el: el, model: obj}).render('templateId');
    c.DisposableView = Backbone.View.extend({
        render: function(templateId, callback){
            var template = _.template($('#' + templateId).html());
            
            // The obj can be a native object or a instanceof Backbone.Model.
            $(this.el).html(template({obj: _(this.model).nativeObj()}));
            if(callback) callback();
            return this;
        }
    })

 

这个一次性视图,根据指定的模版和对象来展现视图,为那些只适用一次的,仅仅用来展示的功能提供的。例如我们经常用的添加用户和添加角色等和业务相关的视图。

 

顺便说一下上面的nativeObj,这是我自定义的使用underscore的mixin整合的方法,目的就是将Backbone的model实例转换成js的本地对象,如果已经是本地对象则直接返回,代码如下:

 

    _.mixin({nativeObj: nativeObj});
    
    // if the object is Backbone.Model's instance and then change it to Native Object.
    // if the object is Native and then return it.
    function nativeObj(obj){
        if(_(obj).isNull() || !_(obj).isObject()) return;
        return (obj instanceof Backbone.Model) ? obj.toJSON() : obj;
    }

 

5. 还有因为目前项目还没有使用requireJS,所有js的加载顺序要注意。

 

......

 

写了一大堆,更像是个人的总结,当然还没有结束,因为我也是刚开始用Backbone.js,以后还会进行更新。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics