• Backbone 47 0 1 发布

    Backbone.js是一个JavaScript MVC框架。本篇先简单的介绍一下Backbone.js的概念和导入方法。

    简介

    Backbone.js是一个JavaScript MVC框架,顾名思义,是一个旨在为Web应用程序提供架构骨干的库。通过在Web应用程序中使用Backbone.js提供的事件,模型,集合,视图和路由器等组件,可以为Web应用程序提供某种结构。

    (体系结构)

    下面的图描述了一个典型的Backbone应用的体系结构:

    (特点)

    轻量
    大小为6.3kb(压缩+ gzipped)已经被大量应用易于与其他库集成
    例如,对要使用的View库没有特别限制

    (依存)

    Backbone.js依存于以下库:

    Underscore.js(> = 1.4.3)或Lo-Dashjson2.jsjQuery(> = 1.7.0)或Zepto导入

    (index.html)

    <html> <head>   <title>Backbone Example</title> </head> <body>   <h1>Backbone Example</h1>  <script src="lib/js/jquery-1.9.1.js"> </script><script src="lib/js/json2.js"> </script><script src="lib/js/underscore.js"></script> <script src="lib/js/backbone.js"></script> <script src="js/app.js"></script> </body> </html>

    (app.js)

    (function(){ console.log("Hello Backbone!"); }());     

    (动作确认)


  • Backbone 52 0 1 发布

    Backbone模型包含应用程序的数据和与数据相关的逻辑处理,我们通过拓展Backbone.Model对象来创建模型:

    var app = app || {}; app.MenuModel = Backbone.Model.extend({}); 构造函数初始化

    当创建一个模型的新实例时,其构造函数,即initialize()方法会被调用:

    app.MenuModel = Backbone.Model.extend({ initialize: function() { console.log('Initialize the Model.'); } }); app.menu = new app.MenuModel(); 默认值

    创建Backbone模型时,Backbone允许我们为模型设置一组默认值,通过defaults属性即可设置;当实例化模型时,可传入一个参数对象,此对象即为模型的数据,传入参数值将覆盖所设置的默认值。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(JSON.parse(app.menu)); //{"title": "this is a menu", "name": "最近会话", "status": "inactive"} 属性操作

    Model.get()

    Model.get()方法用于访问模型的属性:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.get('status'));//inactive

    Model.set()

    Model.set()方法用于设置模型的一个或多个属性值:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.get('status'));//inactive app.menu.set({ status: 'active', title: 'menu' }); console.log(app.menu.get('status'));//active

    Model.attributes

    Backbone模型的attributes属性,是包含模型状态的一个内部散列表,使用Model.attributes可直接访问该模型所有数据,其通常以服务器返回的JSON对象数据形式存在:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.attributes); //Object {status: "inactive", title: "this is a menu", name: "最近会话"}

    注:强烈建议使用set方法更新模型attributes对象而不是直接修改attributes对象。

    Model.toJSON()

    Model.toJSON()方法返回模型attributes对象拷贝副本的JSON格式对象:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.toJSON()); //Object {status: "inactive", title: "this is a menu", name: "最近会话"} console.log(JSON.stringify(app.menu)); //{"status":"inactive","title":"this is a menu","name":"最近会话"}

    注:当给JSON.stringify()传递带toJSON()方法的对象时,其处理的是该对象执行toJSON()方法后返回的值,而不是原始传入的对象,如:

    var a = { data: { name: '惊鸿', title: 'sj' }, toJSON: function() { return 'sds'; } }; console.log(JSON.stringify(a));//"sds"
    模型id与cidid

    id是模型的特殊属性,可以是任意字符串(整型 id 或 UUID)。在属性中设置的 id 会被直接拷贝到model属性上。 也可以在集合(collections)中通过 id 获取特定model。

    idAttribute

    模型的唯一标识符,被储存在 id 属性下,可以通过设置Model的idAttribute与一个唯一值key对应,从而形成一个从该key到模型id的一个映射。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' }, idAttribute: 'idx', //形成从idx到id的映射 initialize: function() { } }); app.menu = new app.MenuModel({ idx: '001' }); console.log(app.menu.id);//001

    cid

    cid,即客户端id,是model创建时自动产生的唯一标识符。 客户端id在model尚未保存到服务器之前便存在,此时model可能仍不具有最终的id,但已经需要在用户界面可见。

    console.log(app.menu.cid);//c1或其他 模型变化监听

    通过监听模型上change事件,可以监测到模型的变化,既可以监听整个模型的改变,也可以监听模型单个属性的变化;通常在模型initialize()函数中添加监听器:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' }, initialize: function() { //监听模型变化 this.on('change', function(model) { console.log(model); console.log('模型已改变'); }); //监听模型单个属性变化 this.on('change:name', function(model) { console.log('菜单名已修改'); }); } }); app.menu = new app.MenuModel(); app.menu.set({ title: 'menu', status: 'inactive' }); console.log(app.menu.get('title'));//menu console.log(app.menu.get('status'));//inactive app.menu.set({ name: '常用联系人', }); console.log(app.menu.get('name'));//常用联系人 验证

    调用Model.validate()方法进行模型验证,在设置属性值之前对其进行验证,默认,在使用save()方法或调用set()方法时设置了{validate: true}参数以持久化数据模型均会触发验证;验证通过将不返回值,验证失败将触发"invalid"事件, 此方法返回一个错误值,并用此方法返回的值设置模型上的validationError属性,同时模型上的属性值不会持久化到服务器: app.MenuModel = Backbone.Model.extend({

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', //name: '最近会话', status: 'active' }, validate: function(attr) { if (attr.name == undefined ) { //返回错误值 return '菜单名不能为空'; } }, initialize: function() { //监听invalid事件 this.on('invalid', function(model, err) { console.log('title: ' + model.get('title'), '; error: ' + err); }); } }); app.menu = new app.MenuModel(); console.log((app.menu).toJSON()); //Object {title: "this is a menu", status: "active"} //set()方法且设置{validate: true}参数 app.menu.set({ title: 'menu', }, {validate: true}); console.log(app.menu.get('title'));//this is a menu //set()方法但不设置{validate: true}参数 app.menu.set({ title: 'menu', }); console.log(app.menu.get('title'));//menu

    注:validate函数接收的参数对象是在执行set()或save()方法后模型的值对象。

    声明: 本文转载自熊建刚的博客

  • Backbone 56 0 1 发布

    Backbone集合是模型的有序组合,通过拓展Backbone.Collection对象来创建集合:

    在创建集合时,通过model属性设置集合中的模型类型,实例化集合时,可以传入对象或数组,它们将被自动转换为通过model设置的模型类型。

    var app = app || {}; app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近联系人', status: 'active' }, idAttribute: 'idx' }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel }); app.menu = new app.MenuModel({ status: 'inactive', idx: '001' }); app.menus = new app.MenuCollection([app.menu]); console.log(app.menus.length); //1 初始化

    在创建集合时,可以设置initialize函数,在实例化集合时,将自动调用执行initialize函数:

    app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); app.menus = new app.MenuCollection([app.menu]);

    打印值如下:

    集合属性方法

    models
    此属性返回集合中模型数组:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); console.log(app.menus.models.length); //2

    toJSON()
    Collection.toJSON()方法返回集合中所有模型attributes对象拷贝副本的JSON格式对象数组:

    console.log(app.menus.toJSON());

    集合与模型

    Backbone.Collection对象允许我们通过多种方法对模型进行管理。

    添加/移除模型

    集合创建以后,可以使用add()和remove()方法添加或移除集合中的模型:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menu1 = new app.MenuModel({ name: '最近会话', status: 'active' }); var menu2 = new app.MenuModel({ name: '通讯录', status: 'inactive' }); var menu3 = new app..MenuModel({ name: '公告', status: 'inactive' }); app.menus = new app.MenuCollection([menu1, menu2]); console.log(app.menus);

    app.menus打印值如下:

    app.menus.add(menu3); console.log(app.menus.length);//3 app.menus.remove(menu2); console.log(app.menus.length);//2 检索模型

    get()
    调用collection.get()方法,传入一个id或者cid从集合中检索一个模型:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); var a = app.menus.get(1); var b = app.menus.get('c2'); console.log(a === b); //true

    at()
    调用collection.at()方法,传入模型在集合中的索引值,at始终根据模型在插入集合时的索引返回值:

    var a = app.menus.get(1); var c = app.menus.at(0); console.log(a === c); //true

    where()
    调用collection.where()方法,传入模型属性,返回符合的模型数组:

    var d = app.menus.where({name: '最近会话'}); console.log(d);

    打印值如下:

    findWhere()
    findWhere()方法与where()方法调用方式一样,只是findWhere()方法返回匹配传入属性的第一个模型,而不是返回一个模型数组:

    var d = app.menus.where({name: '最近会话'}); console.log(d); 重置刷新集合

    set()

    Backbone不仅支持添加或移除模型,还提供一次性更新整个集合:调用Collection.set()方法,接收一个模型数组,将执行更新集合所必要的添加、移除和更新操作。
    如果列表中的一个模型尚不在集合中,那么它将被添加; 如果模型已经在集合中,其属性将被合并; 并且如果集合包含不存在于列表中的任何模型,他们将被删除。 以上所有将触发相应的”add”, “remove”, 和 “change”事件。 返回集合中的模型。另外 可以设置选项:{add: false}, {remove: false}, 或 {merge: false},将相应操作禁用,实现自定义行为。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.set([ {id:1, name: '最近聊天'}, {id:3, name: '公告'} ]); console.log(app.menus.length); //2 console.log(app.menus);

    打印值如下:

    reset()
    调用Collection.reset()方法,可以重置整个集合:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log(cols, options.previousModels); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.reset([ {id:1, name: '最近聊天'} ]); console.log(app.menus.length); //1

    打印值如下:

    调用Collection.reset()方法不会触发add和remove事件,但会触发reset事件,我们可以通过传入空参数来清空集合;监听reset事件时可以从options.previousModels访问之前的模型数组。

    事件监听

    集合是模型的有序组合,在集合中添加或移除模型时会触发add或remove事件,我们可以监听这些事件,进行相应数据逻辑处理;同时,可以在集合的任意模型属性上绑定change事件,监听模型属性的变化。

    一般,事件监听在集合初始化时绑定,第一个参数为监听事件类型,第二个参数为监听回调,第三个参数为回调的上下文环境(可选),通常传入指向当前集合的this。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log('重置集合'); }, this); this.on('add', function(model) { console.log('添加模型,cid: ' + model.cid); }, this); this.on('change', function(model) { console.log('模型属性改变为: ' + model.get(name')); }); this.on('change:name', function(model) { console.log('模型name属性改变为: ' + model.get('name')); }); this.on('remove', function(model) { console.log('移除模型: ' + model.cid); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.set([ {id:1, name: '最近聊天'}, {id:3, name: '公告'} ]); app.menus.reset([ {id:1, name: '最近聊天'} ]); //logs: //模型name属性改变为: 最近聊天 //模型属性改变为: 最近聊天 //移除模型: c3 //添加模型,cid: c4 //重置集合

    Backbone事件除了上文的on()方法,还可以使用once()方法,与jQuery的once类似,监听回调只执行一次。

    声明: 本文转载自熊建刚的博客

  • Backbone 66 0 1 发布

    Backbone视图可以使用JavaScript模板,根据模型数据的逻辑处理向用户展示相应的界面。可以监听模型的change事件,并在回调函数绑定视图的render()方法,就可以在不重绘整个页面的情况下,更新视图。

    创建视图

    可以通过扩展Backbone.View对象创建一个视图:

    var app = app || {}; app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template('<li><%= title %></li>'); }, render: function() { this.$el.html(this.template()({title: "Menu List"})); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); console.log(app.menulist.$el);

    打印值如下:

    app.menulist.el:

    app.menulist.$el:

    初始化

    如果视图定义了initialize()初始化函数,在创建视图时,它将立即被调用。

    视图与模型

    创建视图时,可以通过传入model或collection属性和值,将某一模型或集合直接注册到视图中:

    var app = app || {}; app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template('<li><%= title %></li>'); }, render: function() { this.$el.html(this.template()({title: "Menu List"})); return this; }, initialize: function() { //console.log('视图初始化'); this.render(); $('body').append(this.$el); } }); app.menulist = new app.MenuListView({ collection: app.menus }); console.log(app.menulist.collection);

    打印如下:

    视图与DOM

    我们希望通过使用Backbone视图生成页面文档,将页面展示给用户,就必须将视图与DOM关联起来,通过操作视图改变DOM。

    Backbone提供两种方式关联视图和DOM:

    创建

    创建视图时创建一个新元素,然后将该元素插入至DOM。

    引用

    视图直接引用页面已经存在的元素。

    创建

    Backbone视图创建元素时只需要使用tagName、id、className属性。此Backbone视图对象的el属性是一个指向该元素的引用。

    tagName默认值为div。

    app.MenuListView = Backbone.View.extend({ tagName: 'ul', //元素标签类型,必选,未设置时默认为div className: 'menu-list', //元素class,可选 id: 'menus', //元素id,可选 initialize: function() { $('body').append(this.$el); } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); //logs: <ul id="menus" class="menu-list"></ul>

    引用
    可以为Backbone视图对象传入一个el属性,来匹配页面文档已存在的元素。

    app.MenuListView = Backbone.View.extend({ el: 'body', //值为CSS选择器 initialize: function() { } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); //logs: <body>...</body>

    我们也可以在创建视图时,为对象el属性设置值:

    app.menulist = <span class="hljs-keyword">new</span> app.MenuListView({el: <span class="hljs-string">'body'</span>});

    el属性值为CSS选择器,Backbone视图对象将根据此选择器匹配页面元素。

    视图属性与方法

    要深入理解Backbone视图,必须理解视图一些重要的属性和方法。

    el

    el是视图的一个核心属性,也是使用视图对象时必然会用到的一个属性。

    el是DOM元素的一个引用,所有视图都有其el属性。视图可以通过使用el构成它的元素内容,在触发浏览器最少次数重排和重绘的情况下,将所有内容一次性插入文档DOM。

    $el、$()

    对视图和DOM操作,经常要用到jQuery函数,Backbone通过为视图定义$el属性和$()函数,为我们操作视图和DOM提供了很多便利。视图的$el属性等价于$(View.el),$(selector)等价于$(View.el).find(selector)。

    setElement()
    Backbone提供setElement()方法,支持将现有Backbone视图应用于不同的DOM元素,调用该方法将创建一个缓存$el引用,并且将视图委托事件从旧元素移动到新元素。

    var MyView = Backbone.View.extend({ events: { click: function(e) { console.log(myView.$el.html()); } } }); var btn1 = $('<button>button 1</button>'); var btn2 = $('<button>button 2</button>'); //视图元素el是btn1 var myView = new MyView({el: btn1}); btn1.trigger('click'); //logs: button 1 //视图元素el指向btn2 myView.setElement(btn2); btn1.trigger('click'); btn2.trigger('click'); //logs: button 2 console.log(myView.$el.html);// button 2

    渲染模板-render()

    render()函数是一个可选函数,需要我们主动调用,通常我们在里面实现根据模型属性渲染视图模板,生成HTML标记;然后使用el或$el属性,将这些HTML标记设置为视图的el属性所引用的 DOM元素的HTML内容。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log('重置集合'); }, this); this.on('add', function(model) { console.log('添加模型,cid: ' + model.cid); }); this.on('change', function(model) { console.log('模型属性改变为: ' + model.get('name'), model); }); this.on('change:name', function(model) { console.log('模型name属性改变为: ' + model.get('name')); }); this.on('remove', function(model) { console.log('移除模型: ' + model.cid); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.MenuItemView = Backbone.View.extend({ tagName: 'li', className: 'menu-item', template: function() { return _.template('<a title="<%= title %>"><%= name %></a>'); }, render: function() { this.$el.html(this.template()(this.model.toJSON())); return this; } }); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template(''); }, render: function() { //遍历集合,集合中每个模型对应一个菜单项 _.each(this.collection.models, function(model) { //为每个集合模型,创建一个新菜单项视图实例 var menuItemView = new app.MenuItemView({model: model}); //在父视图-菜单列表视图中添加子菜单-菜单项视图 this.$el.append(menuItemView.render().el); }, this); console.log(this.el); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulistview = new app.MenuListView({ collection: app.menus });

    控制台打印值如下:

    页面效果如图:

    我们通常在render()函数底部返回this以开启链式调用,该视图可以在其他父视图里被重用。

    Events对象

    Backbone提供events对象支持我们通过设置在el下的自定义CSS选择器、事件类型和事件监听器,为DOM元素绑定事件。

    app.MenuItemView = Backbone.View.extend({ tagName: 'li', className: 'menu-item', events: { 'click .menu': 'openMenu', 'dblclick .menu': 'edit' }, template: function() { return _.template('<a class="menu" title="<%= title %>"><%= name %></a>'); }, render: function() { this.$el.html(this.template()(this.model.toJSON())); return this; }, initialize: function() { this.dbltimer = null; }, openMenu: function(e) { if (this.dbltimer) { clearTimeout(this.dbltimer); this.dbltimer = null; } this.dbltimer = setTimeout(function(){ console.log('opened'); },300); }, edit: function(e) { if (this.dbltimer) { clearTimeout(this.dbltimer); this.dbltimer = null; } console.log('edit'); } }); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template(''); }, render: function() { _.each(this.collection.models, function(model) { var menuItemView = new app.MenuItemView({model: model}); this.$el.append(menuItemView.render().el); }, this); // this.$el.html(this.template()({title: "Menu List"})); console.log(this.el); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulistview = new app.MenuListView({ collection: app.menus });

    若没有设置CSS选择器,则默认为el所引用DOM元素绑定事件。

    移除视图-remove()

    调用View.remove(),从DOM中移除一个视图。同时将调用stopListening来移除通过 listenTo绑定在视图上的所有事件。

    app.menulistview.remove();

    声明: 本文转载自熊建刚的博客

热门总结

  • Backbone 66 0 1 发布

    Backbone视图可以使用JavaScript模板,根据模型数据的逻辑处理向用户展示相应的界面。可以监听模型的change事件,并在回调函数绑定视图的render()方法,就可以在不重绘整个页面的情况下,更新视图。

    创建视图

    可以通过扩展Backbone.View对象创建一个视图:

    var app = app || {}; app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template('<li><%= title %></li>'); }, render: function() { this.$el.html(this.template()({title: "Menu List"})); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); console.log(app.menulist.$el);

    打印值如下:

    app.menulist.el:

    app.menulist.$el:

    初始化

    如果视图定义了initialize()初始化函数,在创建视图时,它将立即被调用。

    视图与模型

    创建视图时,可以通过传入model或collection属性和值,将某一模型或集合直接注册到视图中:

    var app = app || {}; app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template('<li><%= title %></li>'); }, render: function() { this.$el.html(this.template()({title: "Menu List"})); return this; }, initialize: function() { //console.log('视图初始化'); this.render(); $('body').append(this.$el); } }); app.menulist = new app.MenuListView({ collection: app.menus }); console.log(app.menulist.collection);

    打印如下:

    视图与DOM

    我们希望通过使用Backbone视图生成页面文档,将页面展示给用户,就必须将视图与DOM关联起来,通过操作视图改变DOM。

    Backbone提供两种方式关联视图和DOM:

    创建

    创建视图时创建一个新元素,然后将该元素插入至DOM。

    引用

    视图直接引用页面已经存在的元素。

    创建

    Backbone视图创建元素时只需要使用tagName、id、className属性。此Backbone视图对象的el属性是一个指向该元素的引用。

    tagName默认值为div。

    app.MenuListView = Backbone.View.extend({ tagName: 'ul', //元素标签类型,必选,未设置时默认为div className: 'menu-list', //元素class,可选 id: 'menus', //元素id,可选 initialize: function() { $('body').append(this.$el); } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); //logs: <ul id="menus" class="menu-list"></ul>

    引用
    可以为Backbone视图对象传入一个el属性,来匹配页面文档已存在的元素。

    app.MenuListView = Backbone.View.extend({ el: 'body', //值为CSS选择器 initialize: function() { } }); app.menulist = new app.MenuListView(); console.log(app.menulist.el); //logs: <body>...</body>

    我们也可以在创建视图时,为对象el属性设置值:

    app.menulist = <span class="hljs-keyword">new</span> app.MenuListView({el: <span class="hljs-string">'body'</span>});

    el属性值为CSS选择器,Backbone视图对象将根据此选择器匹配页面元素。

    视图属性与方法

    要深入理解Backbone视图,必须理解视图一些重要的属性和方法。

    el

    el是视图的一个核心属性,也是使用视图对象时必然会用到的一个属性。

    el是DOM元素的一个引用,所有视图都有其el属性。视图可以通过使用el构成它的元素内容,在触发浏览器最少次数重排和重绘的情况下,将所有内容一次性插入文档DOM。

    $el、$()

    对视图和DOM操作,经常要用到jQuery函数,Backbone通过为视图定义$el属性和$()函数,为我们操作视图和DOM提供了很多便利。视图的$el属性等价于$(View.el),$(selector)等价于$(View.el).find(selector)。

    setElement()
    Backbone提供setElement()方法,支持将现有Backbone视图应用于不同的DOM元素,调用该方法将创建一个缓存$el引用,并且将视图委托事件从旧元素移动到新元素。

    var MyView = Backbone.View.extend({ events: { click: function(e) { console.log(myView.$el.html()); } } }); var btn1 = $('<button>button 1</button>'); var btn2 = $('<button>button 2</button>'); //视图元素el是btn1 var myView = new MyView({el: btn1}); btn1.trigger('click'); //logs: button 1 //视图元素el指向btn2 myView.setElement(btn2); btn1.trigger('click'); btn2.trigger('click'); //logs: button 2 console.log(myView.$el.html);// button 2

    渲染模板-render()

    render()函数是一个可选函数,需要我们主动调用,通常我们在里面实现根据模型属性渲染视图模板,生成HTML标记;然后使用el或$el属性,将这些HTML标记设置为视图的el属性所引用的 DOM元素的HTML内容。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log('重置集合'); }, this); this.on('add', function(model) { console.log('添加模型,cid: ' + model.cid); }); this.on('change', function(model) { console.log('模型属性改变为: ' + model.get('name'), model); }); this.on('change:name', function(model) { console.log('模型name属性改变为: ' + model.get('name')); }); this.on('remove', function(model) { console.log('移除模型: ' + model.cid); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.MenuItemView = Backbone.View.extend({ tagName: 'li', className: 'menu-item', template: function() { return _.template('<a title="<%= title %>"><%= name %></a>'); }, render: function() { this.$el.html(this.template()(this.model.toJSON())); return this; } }); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template(''); }, render: function() { //遍历集合,集合中每个模型对应一个菜单项 _.each(this.collection.models, function(model) { //为每个集合模型,创建一个新菜单项视图实例 var menuItemView = new app.MenuItemView({model: model}); //在父视图-菜单列表视图中添加子菜单-菜单项视图 this.$el.append(menuItemView.render().el); }, this); console.log(this.el); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulistview = new app.MenuListView({ collection: app.menus });

    控制台打印值如下:

    页面效果如图:

    我们通常在render()函数底部返回this以开启链式调用,该视图可以在其他父视图里被重用。

    Events对象

    Backbone提供events对象支持我们通过设置在el下的自定义CSS选择器、事件类型和事件监听器,为DOM元素绑定事件。

    app.MenuItemView = Backbone.View.extend({ tagName: 'li', className: 'menu-item', events: { 'click .menu': 'openMenu', 'dblclick .menu': 'edit' }, template: function() { return _.template('<a class="menu" title="<%= title %>"><%= name %></a>'); }, render: function() { this.$el.html(this.template()(this.model.toJSON())); return this; }, initialize: function() { this.dbltimer = null; }, openMenu: function(e) { if (this.dbltimer) { clearTimeout(this.dbltimer); this.dbltimer = null; } this.dbltimer = setTimeout(function(){ console.log('opened'); },300); }, edit: function(e) { if (this.dbltimer) { clearTimeout(this.dbltimer); this.dbltimer = null; } console.log('edit'); } }); app.MenuListView = Backbone.View.extend({ tagName: 'ul', className: 'menu-list', template: function() { return _.template(''); }, render: function() { _.each(this.collection.models, function(model) { var menuItemView = new app.MenuItemView({model: model}); this.$el.append(menuItemView.render().el); }, this); // this.$el.html(this.template()({title: "Menu List"})); console.log(this.el); return this; }, initialize: function() { this.render(); $('body').append(this.$el); } }); app.menulistview = new app.MenuListView({ collection: app.menus });

    若没有设置CSS选择器,则默认为el所引用DOM元素绑定事件。

    移除视图-remove()

    调用View.remove(),从DOM中移除一个视图。同时将调用stopListening来移除通过 listenTo绑定在视图上的所有事件。

    app.menulistview.remove();

    声明: 本文转载自熊建刚的博客

  • Backbone 56 0 1 发布

    Backbone集合是模型的有序组合,通过拓展Backbone.Collection对象来创建集合:

    在创建集合时,通过model属性设置集合中的模型类型,实例化集合时,可以传入对象或数组,它们将被自动转换为通过model设置的模型类型。

    var app = app || {}; app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近联系人', status: 'active' }, idAttribute: 'idx' }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel }); app.menu = new app.MenuModel({ status: 'inactive', idx: '001' }); app.menus = new app.MenuCollection([app.menu]); console.log(app.menus.length); //1 初始化

    在创建集合时,可以设置initialize函数,在实例化集合时,将自动调用执行initialize函数:

    app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); app.menus = new app.MenuCollection([app.menu]);

    打印值如下:

    集合属性方法

    models
    此属性返回集合中模型数组:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); console.log(app.menus.models.length); //2

    toJSON()
    Collection.toJSON()方法返回集合中所有模型attributes对象拷贝副本的JSON格式对象数组:

    console.log(app.menus.toJSON());

    集合与模型

    Backbone.Collection对象允许我们通过多种方法对模型进行管理。

    添加/移除模型

    集合创建以后,可以使用add()和remove()方法添加或移除集合中的模型:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menu1 = new app.MenuModel({ name: '最近会话', status: 'active' }); var menu2 = new app.MenuModel({ name: '通讯录', status: 'inactive' }); var menu3 = new app..MenuModel({ name: '公告', status: 'inactive' }); app.menus = new app.MenuCollection([menu1, menu2]); console.log(app.menus);

    app.menus打印值如下:

    app.menus.add(menu3); console.log(app.menus.length);//3 app.menus.remove(menu2); console.log(app.menus.length);//2 检索模型

    get()
    调用collection.get()方法,传入一个id或者cid从集合中检索一个模型:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); var a = app.menus.get(1); var b = app.menus.get('c2'); console.log(a === b); //true

    at()
    调用collection.at()方法,传入模型在集合中的索引值,at始终根据模型在插入集合时的索引返回值:

    var a = app.menus.get(1); var c = app.menus.at(0); console.log(a === c); //true

    where()
    调用collection.where()方法,传入模型属性,返回符合的模型数组:

    var d = app.menus.where({name: '最近会话'}); console.log(d);

    打印值如下:

    findWhere()
    findWhere()方法与where()方法调用方式一样,只是findWhere()方法返回匹配传入属性的第一个模型,而不是返回一个模型数组:

    var d = app.menus.where({name: '最近会话'}); console.log(d); 重置刷新集合

    set()

    Backbone不仅支持添加或移除模型,还提供一次性更新整个集合:调用Collection.set()方法,接收一个模型数组,将执行更新集合所必要的添加、移除和更新操作。
    如果列表中的一个模型尚不在集合中,那么它将被添加; 如果模型已经在集合中,其属性将被合并; 并且如果集合包含不存在于列表中的任何模型,他们将被删除。 以上所有将触发相应的”add”, “remove”, 和 “change”事件。 返回集合中的模型。另外 可以设置选项:{add: false}, {remove: false}, 或 {merge: false},将相应操作禁用,实现自定义行为。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.set([ {id:1, name: '最近聊天'}, {id:3, name: '公告'} ]); console.log(app.menus.length); //2 console.log(app.menus);

    打印值如下:

    reset()
    调用Collection.reset()方法,可以重置整个集合:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log(cols, options.previousModels); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.reset([ {id:1, name: '最近聊天'} ]); console.log(app.menus.length); //1

    打印值如下:

    调用Collection.reset()方法不会触发add和remove事件,但会触发reset事件,我们可以通过传入空参数来清空集合;监听reset事件时可以从options.previousModels访问之前的模型数组。

    事件监听

    集合是模型的有序组合,在集合中添加或移除模型时会触发add或remove事件,我们可以监听这些事件,进行相应数据逻辑处理;同时,可以在集合的任意模型属性上绑定change事件,监听模型属性的变化。

    一般,事件监听在集合初始化时绑定,第一个参数为监听事件类型,第二个参数为监听回调,第三个参数为回调的上下文环境(可选),通常传入指向当前集合的this。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', status: 'inactive' } }); app.MenuCollection = Backbone.Collection.extend({ model: app.MenuModel, initialize: function() { console.log('集合初始化成功'); this.on('reset', function(cols, options) { console.log('重置集合'); }, this); this.on('add', function(model) { console.log('添加模型,cid: ' + model.cid); }, this); this.on('change', function(model) { console.log('模型属性改变为: ' + model.get(name')); }); this.on('change:name', function(model) { console.log('模型name属性改变为: ' + model.get('name')); }); this.on('remove', function(model) { console.log('移除模型: ' + model.cid); }); } }); var menus = [ { id: 1, name: '最近会话', status: 'active' }, { id: 2, name: '通讯录', status: 'inactive' } ] app.menus = new app.MenuCollection(menus); app.menus.set([ {id:1, name: '最近聊天'}, {id:3, name: '公告'} ]); app.menus.reset([ {id:1, name: '最近聊天'} ]); //logs: //模型name属性改变为: 最近聊天 //模型属性改变为: 最近聊天 //移除模型: c3 //添加模型,cid: c4 //重置集合

    Backbone事件除了上文的on()方法,还可以使用once()方法,与jQuery的once类似,监听回调只执行一次。

    声明: 本文转载自熊建刚的博客

  • Backbone 52 0 1 发布

    Backbone模型包含应用程序的数据和与数据相关的逻辑处理,我们通过拓展Backbone.Model对象来创建模型:

    var app = app || {}; app.MenuModel = Backbone.Model.extend({}); 构造函数初始化

    当创建一个模型的新实例时,其构造函数,即initialize()方法会被调用:

    app.MenuModel = Backbone.Model.extend({ initialize: function() { console.log('Initialize the Model.'); } }); app.menu = new app.MenuModel(); 默认值

    创建Backbone模型时,Backbone允许我们为模型设置一组默认值,通过defaults属性即可设置;当实例化模型时,可传入一个参数对象,此对象即为模型的数据,传入参数值将覆盖所设置的默认值。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(JSON.parse(app.menu)); //{"title": "this is a menu", "name": "最近会话", "status": "inactive"} 属性操作

    Model.get()

    Model.get()方法用于访问模型的属性:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.get('status'));//inactive

    Model.set()

    Model.set()方法用于设置模型的一个或多个属性值:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.get('status'));//inactive app.menu.set({ status: 'active', title: 'menu' }); console.log(app.menu.get('status'));//active

    Model.attributes

    Backbone模型的attributes属性,是包含模型状态的一个内部散列表,使用Model.attributes可直接访问该模型所有数据,其通常以服务器返回的JSON对象数据形式存在:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.attributes); //Object {status: "inactive", title: "this is a menu", name: "最近会话"}

    注:强烈建议使用set方法更新模型attributes对象而不是直接修改attributes对象。

    Model.toJSON()

    Model.toJSON()方法返回模型attributes对象拷贝副本的JSON格式对象:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' } }); app.menu = new app.MenuModel({ status: 'inactive' }); console.log(app.menu.toJSON()); //Object {status: "inactive", title: "this is a menu", name: "最近会话"} console.log(JSON.stringify(app.menu)); //{"status":"inactive","title":"this is a menu","name":"最近会话"}

    注:当给JSON.stringify()传递带toJSON()方法的对象时,其处理的是该对象执行toJSON()方法后返回的值,而不是原始传入的对象,如:

    var a = { data: { name: '惊鸿', title: 'sj' }, toJSON: function() { return 'sds'; } }; console.log(JSON.stringify(a));//"sds"
    模型id与cidid

    id是模型的特殊属性,可以是任意字符串(整型 id 或 UUID)。在属性中设置的 id 会被直接拷贝到model属性上。 也可以在集合(collections)中通过 id 获取特定model。

    idAttribute

    模型的唯一标识符,被储存在 id 属性下,可以通过设置Model的idAttribute与一个唯一值key对应,从而形成一个从该key到模型id的一个映射。

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' }, idAttribute: 'idx', //形成从idx到id的映射 initialize: function() { } }); app.menu = new app.MenuModel({ idx: '001' }); console.log(app.menu.id);//001

    cid

    cid,即客户端id,是model创建时自动产生的唯一标识符。 客户端id在model尚未保存到服务器之前便存在,此时model可能仍不具有最终的id,但已经需要在用户界面可见。

    console.log(app.menu.cid);//c1或其他 模型变化监听

    通过监听模型上change事件,可以监测到模型的变化,既可以监听整个模型的改变,也可以监听模型单个属性的变化;通常在模型initialize()函数中添加监听器:

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', name: '最近会话', status: 'active' }, initialize: function() { //监听模型变化 this.on('change', function(model) { console.log(model); console.log('模型已改变'); }); //监听模型单个属性变化 this.on('change:name', function(model) { console.log('菜单名已修改'); }); } }); app.menu = new app.MenuModel(); app.menu.set({ title: 'menu', status: 'inactive' }); console.log(app.menu.get('title'));//menu console.log(app.menu.get('status'));//inactive app.menu.set({ name: '常用联系人', }); console.log(app.menu.get('name'));//常用联系人 验证

    调用Model.validate()方法进行模型验证,在设置属性值之前对其进行验证,默认,在使用save()方法或调用set()方法时设置了{validate: true}参数以持久化数据模型均会触发验证;验证通过将不返回值,验证失败将触发"invalid"事件, 此方法返回一个错误值,并用此方法返回的值设置模型上的validationError属性,同时模型上的属性值不会持久化到服务器: app.MenuModel = Backbone.Model.extend({

    app.MenuModel = Backbone.Model.extend({ defaults: { title: 'this is a menu', //name: '最近会话', status: 'active' }, validate: function(attr) { if (attr.name == undefined ) { //返回错误值 return '菜单名不能为空'; } }, initialize: function() { //监听invalid事件 this.on('invalid', function(model, err) { console.log('title: ' + model.get('title'), '; error: ' + err); }); } }); app.menu = new app.MenuModel(); console.log((app.menu).toJSON()); //Object {title: "this is a menu", status: "active"} //set()方法且设置{validate: true}参数 app.menu.set({ title: 'menu', }, {validate: true}); console.log(app.menu.get('title'));//this is a menu //set()方法但不设置{validate: true}参数 app.menu.set({ title: 'menu', }); console.log(app.menu.get('title'));//menu

    注:validate函数接收的参数对象是在执行set()或save()方法后模型的值对象。

    声明: 本文转载自熊建刚的博客

  • Backbone 47 0 1 发布

    Backbone.js是一个JavaScript MVC框架。本篇先简单的介绍一下Backbone.js的概念和导入方法。

    简介

    Backbone.js是一个JavaScript MVC框架,顾名思义,是一个旨在为Web应用程序提供架构骨干的库。通过在Web应用程序中使用Backbone.js提供的事件,模型,集合,视图和路由器等组件,可以为Web应用程序提供某种结构。

    (体系结构)

    下面的图描述了一个典型的Backbone应用的体系结构:

    (特点)

    轻量
    大小为6.3kb(压缩+ gzipped)已经被大量应用易于与其他库集成
    例如,对要使用的View库没有特别限制

    (依存)

    Backbone.js依存于以下库:

    Underscore.js(> = 1.4.3)或Lo-Dashjson2.jsjQuery(> = 1.7.0)或Zepto导入

    (index.html)

    <html> <head>   <title>Backbone Example</title> </head> <body>   <h1>Backbone Example</h1>  <script src="lib/js/jquery-1.9.1.js"> </script><script src="lib/js/json2.js"> </script><script src="lib/js/underscore.js"></script> <script src="lib/js/backbone.js"></script> <script src="js/app.js"></script> </body> </html>

    (app.js)

    (function(){ console.log("Hello Backbone!"); }());     

    (动作确认)