Javascript MVC框架Backbone.js详解


Posted in Javascript onSeptember 18, 2014

随着JavaScript程序变得越来越复杂,往往需要一个团队协作开发,这时代码的模块化和组织规范就变得异常重要了。MVC模式就是代码组织的经典模式。

(……MVC介绍。)

(1)Model

Model表示数据层,也就是程序需要的数据源,通常使用JSON格式表示。

(2)View

View表示表现层,也就是用户界面,对于网页来说,就是用户看到的网页HTML代码。

(3)Controller

Controller表示控制层,用来对原始数据(Model)进行加工,传送到View。

由于网页编程不同于客户端编程,在MVC的基础上,JavaScript社区产生了各种变体框架MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)等等,有人就把所有这一类框架的各种模式统称为MV*。

框架的优点在于合理组织代码、便于团队合作和未来的维护,缺点在于有一定的学习成本,且限制你只能采取它的写法。

Backbone的加载

<script src="/javascripts/lib/jquery.js"></script>

<script src="/javascripts/lib/underscore.js"></script>

<script src="/javascripts/lib/backbone.js"></script>

<script src="/javascripts/jst.js"></script>

<script src="/javascripts/router.js"></script>

<script src="/javascripts/init.js"></script>

Backbone.View

基本用法

Backbone.View方法用于定义视图类。

var AppView = Backbone.View.extend({

  render: function(){

    $('main').append('<h1>一级标题</h1>');

  }

});

上面代码通过Backbone.View的extend方法,定义了一个视图类AppView。该类内部有一个render方法,用于将视图放置在网页上。

使用的时候,需要先新建视图类的实例,然后通过实例,调用render方法,从而让视图在网页上显示。

var appView = new AppView();

appView.render();

上面代码新建视图类AppView的实例appView,然后调用appView.render,网页上就会显示指定的内容。

新建视图实例时,通常需要指定Model。

var document = new Document({

  model: doc

});

initialize方法

视图还可以定义initialize方法,生成实例的时候,会自动调用该方法对实例初始化。

var AppView = Backbone.View.extend({

  initialize: function(){

    this.render();

  },

  render: function(){

    $('main').append('<h1>一级标题</h1>');

  }

});

var appView = new AppView();

上面代码定义了initialize方法之后,就省去了生成实例后,手动调用appView.render()的步骤。

el属性,$el属性

除了直接在render方法中,指定“视图”所绑定的网页元素,还可以用视图的el属性指定网页元素。

var AppView = Backbone.View.extend({

  el: $('main'),

  render: function(){

    this.$el.append('<h1>一级标题</h1>');

  }

});

上面的代码与render方法直接绑定网页元素,效果完全一样。上面代码中,除了el属性,还是$el属性,前者代表指定的DOM元素,后者则表示该DOM元素对应的jQuery对象。

tagName属性,className属性

如果不指定el属性,也可以通过tagName属性和className属性指定。

var Document = Backbone.View.extend({

  tagName: "li",

  className: "document",

  render: function() {

   // ...

  }

});

template方法

视图的template属性用来指定网页模板。

var AppView = Backbone.View.extend({

      template: _.template("<h3>Hello <%= who %><h3>"),

});

上面代码中,underscore函数库的template函数,接受一个模板字符串作为参数,返回对应的模板函数。有了这个模板函数,只要提供具体的值,就能生成网页代码。
var AppView = Backbone.View.extend({

      el: $('#container'),

      template: _.template("<h3>Hello <%= who %><h3>"),

      initialize: function(){

        this.render();

      },

      render: function(){

        this.$el.html(this.template({who: 'world!'}));

      }

});

上面代码的render就调用了template方法,从而生成具体的网页代码。

实际应用中,一般将模板放在script标签中,为了防止浏览器按照JavaScript代码解析,type属性设为text/template。

<script type="text/template" data-name="templateName">

    <!-- template contents goes here -->

</script>

可以使用下面的代码编译模板。
window.templates = {};

var $sources = $('script[type="text/template"]');

$sources.each(function(index, el) {

    var $el = $(el);

    templates[$el.data('name')] = _.template($el.html());

});

events属性

events属性用于指定视图的事件及其对应的处理函数。

var Document = Backbone.View.extend({

  events: {

    "click .icon":          "open",

    "click .button.edit":   "openEditDialog",

    "click .button.delete": "destroy"

  }

});

上面代码中一个指定了三个CSS选择器的单击事件,及其对应的三个处理函数。

listento方法

listento方法用于为特定事件指定回调函数。

var Document = Backbone.View.extend({

  initialize: function() {

    this.listenTo(this.model, "change", this.render);

  }

});

上面代码为model的change事件,指定了回调函数为render。

remove方法

remove方法用于移除一个视图。

updateView: function() {

  view.remove();

  view.render();

};

子视图(subview)

在父视图中可以调用子视图。下面就是一种写法。

render : function (){

    this.$el.html(this.template());

    this.child = new Child();

    this.child.appendTo($.('.container-placeholder').render();

}

Backbone.Router

Router是Backbone提供的路由对象,用来将用户请求的网址与后端的处理函数一一对应。

首先,新定义一个Router类。

Router = Backbone.Router.extend({

    routes: {

    }

});

routes属性

Backbone.Router对象中,最重要的就是routes属性。它用来设置路径的处理方法。

routes属性是一个对象,它的每个成员就代表一个路径处理规则,键名为路径规则,键值为处理方法。

如果键名为空字符串,就代表根路径。

routes: {

        '': 'phonesIndex',

},

phonesIndex: function () {

        new PhonesIndexView({ el: 'section#main' });

}

星号代表任意路径,可以设置路径参数,捕获具体的路径值。
var AppRouter = Backbone.Router.extend({

    routes: {

        "*actions": "defaultRoute" 

    }

});

var app_router = new AppRouter;

app_router.on('route:defaultRoute', function(actions) {

    console.log(actions);

})

上面代码中,根路径后面的参数,都会被捕获,传入回调函数。

路径规则的写法。

var myrouter = Backbone.Router.extend({

  routes: {

    "help":                 "help",    

    "search/:query":        "search" 

  },

  help: function() {

    ...

  },

  search: function(query) {

    ...

  }

});

routes: {

  "help/:page":         "help",

  "download/*path":     "download",

  "folder/:name":       "openFolder",

  "folder/:name-:mode": "openFolder"

}

router.on("route:help", function(page) {

  ...

});

Backbone.history

设置了router以后,就可以启动应用程序。Backbone.history对象用来监控url的变化。

App = new Router();

$(document).ready(function () {

    Backbone.history.start({ pushState: true });

});

打开pushState方法。如果应用程序不在根目录,就需要指定根目录。
Backbone.history.start({pushState: true, root: "/public/search/"})

Backbone.Model

Model代表单个的对象实体。
var User = Backbone.Model.extend({

        defaults: {

            name: '',

            email: ''

        }

});

var user = new User();

上面代码使用extend方法,生成了一个User类,它代表model的模板。然后,使用new命令,生成一个Model的实例。defaults属性用来设置默认属性,上面代码表示user对象默认有name和email两个属性,它们的值都等于空字符串。

生成实例时,可以提供各个属性的具体值。

var user = new User ({

    id: 1,

    name: 'name',

    email: 'name@email.com'

});

上面代码在生成实例时,提供了各个属性的具体值。

idAttribute属性

Model实例必须有一个属性,作为区分其他实例的主键。这个属性的名称,由idAttribute属性设定,一般是设为id。

var Music = Backbone.Model.extend({ 

    idAttribute: 'id'

});

get方法

get方法用于返回Model实例的某个属性的值。

var user = new User({ name: "name", age: 24});

var age = user.get("age"); // 24

var name = user.get("name"); // "name"

set方法

set方法用于设置Model实例的某个属性的值。

var User = Backbone.Model.extend({

    buy: function(newCarsName){

        this.set({car: newCarsName });

    }

});

var user = new User({name: 'BMW',model:'i8',type:'car'});

user.buy('Porsche');

var car = user.get("car"); // ‘Porsche'

on方法

on方法用于监听对象的变化。

var user = new User({name: 'BMW',model:'i8'});

user.on("change:name", function(model){

    var name = model.get("name"); // "Porsche"

    console.log("Changed my car's name to " + name);

});

user.set({name: 'Porsche'}); 

// Changed my car's name to Porsche

上面代码中的on方法用于监听事件,“change:name”表示name属性发生变化。

urlroot属性

该属性用于指定服务器端对model进行操作的路径。

var User = Backbone.Model.extend({

    urlRoot: '/user'

});

上面代码指定,服务器对应该Model的路径为/user。

fetch事件

fetch事件用于从服务器取出Model。

var user = new User ({id: 1});

user.fetch({

    success: function (user){

        console.log(user.toJSON());

    }

})

上面代码中,user实例含有id属性(值为1),fetch方法使用HTTP动词GET,向网址“/user/1”发出请求,从服务器取出该实例。

save方法

save方法用于通知服务器新建或更新Model。

如果一个Model实例不含有id属性,则save方法将使用POST方法新建该实例。

var User = Backbone.Model.extend({

    urlRoot: '/user'

});

var user = new User ();

var userDetails = {

    name: 'name',

    email: 'name@email.com'

};

user.save(userDetails, {

    success: function (user) {

        console.log(user.toJSON());

    }

})

上面代码先在类中指定Model对应的网址是/user,然后新建一个实例,最后调用save方法。它有两个参数,第一个是实例对象的具体属性,第二个参数是一个回调函数对象,设定success事件(保存成功)的回调函数。具体来说,save方法会向/user发出一个POST请求,并将{name: ‘name', email: ‘name@email.com'}作为数据提供。

如果一个Model实例含有id属性,则save方法将使用PUT方法更新该实例。

var user = new User ({

    id: 1,

    name: '张三',

    email: 'name@email.com'

});

user.save({name: '李四'}, {

    success: function (model) {

        console.log(user.toJSON());

    }

});

上面代码中,对象实例含有id属性(值为1),save将使用PUT方法向网址“/user/1”发出请求,从而更新该实例。

destroy方法

destroy方法用于在服务器上删除该实例。

var user = new User ({

    id: 1,

    name: 'name',

    email: 'name@email.com'

});

user.destroy({

    success: function () {

       console.log('Destroyed');

    }

});

上面代码的destroy方法,将使用HTTP动词DELETE,向网址“/user/1”发出请求,删除对应的Model实例。

Backbone.Collection

Collection是同一类Model的集合,比如Model是动物,Collection就是动物园;Model是单个的人,Collection就是一家公司。

var Song = Backbone.Model.extend({});

var Album = Backbone.Collection.extend({

    model: Song

});

上面代码中,Song是Model,Album是Collection,而且Album有一个model属性等于Song,因此表明Album是Song的集合。

add方法,remove方法

Model的实例可以直接放入Collection的实例,也可以用add方法添加。

var song1 = new Song({ id: 1 ,name: "歌名1", artist: "张三" });

var song2 = new Music ({id: 2,name: "歌名2", artist: "李四" });

var myAlbum = new Album([song1, song2]);

var song3 = new Music({ id: 3, name: "歌名3",artist:"赵五" });

myAlbum.add(song3);

remove方法用于从Collection实例中移除一个Model实例。
myAlbum.remove(1);

上面代码表明,remove方法的参数是model实例的id属性。

get方法,set方法

get方法用于从Collection中获取指定id的Model实例。

myAlbum.get(2))

fetch方法

fetch方法用于从服务器取出Collection数据。

var songs = new Backbone.Collection;

songs.url = '/songs';

songs.fetch();

Backbone.events
var obj = {};

_.extend(obj, Backbone.Events);

obj.on("show-message", function(msg) {

    $('#display').text(msg);

});

obj.trigger("show-message", "Hello World");
Javascript 相关文章推荐
一些技巧性实用js代码小结
Oct 14 Javascript
jQuery EasyUI 中文API Button使用实例
Apr 14 Javascript
JavaScript NaN和Infinity特殊值 [译]
Sep 20 Javascript
JS获取图片实际宽高及根据图片大小进行自适应
Aug 11 Javascript
在页面加载完成后通过jquery给多个span赋值
May 21 Javascript
jQuery提示效果代码分享
Nov 20 Javascript
js如何打印object对象
Oct 16 Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
Dec 29 Javascript
JavaScript实现网页头部进度条刷新
Apr 16 Javascript
Vue数据双向绑定底层实现原理
Nov 22 Javascript
node.js使用net模块创建服务器和客户端示例【基于TCP协议】
Feb 14 Javascript
vue中使用vue-print.js实现多页打印
Mar 05 Javascript
JS回调函数的应用简单实例
Sep 17 #Javascript
js实现在同一窗口浏览图片
Sep 17 #Javascript
js实现获取焦点后光标在字符串后
Sep 17 #Javascript
在JavaScript中构建ArrayList示例代码
Sep 17 #Javascript
取得元素的左和上偏移量的方法
Sep 17 #Javascript
JS实现OCX控件的事件响应示例
Sep 17 #Javascript
javascript快速排序算法详解
Sep 17 #Javascript
You might like
利用Memcached在php下实现session机制 替换PHP的原生session支持
2010/08/21 PHP
PHP面试常用算法(推荐)
2016/07/22 PHP
jquery 实现上下滚动效果示例代码
2013/08/09 Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
2015/01/28 Javascript
使用Node.js配合Nginx实现高负载网络
2015/06/28 Javascript
基于iscroll.js实现下拉刷新和上拉加载效果
2016/11/28 Javascript
使用vue实现点击按钮滑出面板的实现代码
2017/01/10 Javascript
JavaScript中的子窗口与父窗口的互相调用问题
2017/02/08 Javascript
Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的写法
2017/06/29 Javascript
JS实现简单短信验证码界面
2017/08/07 Javascript
对于js垃圾回收机制的理解
2017/09/14 Javascript
vue 项目打包通过命令修改 vue-router 模式 修改 API 接口前缀
2018/06/13 Javascript
详解JavaScript类型判断的四种方法
2020/10/21 Javascript
[02:51]DOTA2英雄基础教程 风暴之灵
2013/12/23 DOTA
[01:42]DOTA2 – 虚无之灵
2019/08/25 DOTA
python实现dict版图遍历示例
2014/02/19 Python
用Python的Tornado框架结合memcached页面改善博客性能
2015/04/24 Python
尝试用最短的Python代码来实现服务器和代理服务器
2016/06/23 Python
详解Django的CSRF认证实现
2018/10/09 Python
详解Python 调用C# dll库最简方法
2019/06/20 Python
django之静态文件 django 2.0 在网页中显示图片的例子
2019/07/28 Python
Python3.6+selenium2.53.6自动化测试_读取excel文件的方法
2019/09/06 Python
django 读取图片到页面实例
2020/03/27 Python
ASOS英国官网:英国在线时装和化妆品零售商
2017/05/19 全球购物
Otel.com:折扣酒店预订
2017/08/24 全球购物
美国最大的烧烤架和户外生活用品专业零售商:Barbeques Galore
2021/01/09 全球购物
优秀团队获奖感言
2014/02/19 职场文书
党员一句话承诺大全
2014/03/28 职场文书
另类冲刺标语
2014/06/24 职场文书
旷课检讨书500字
2014/10/14 职场文书
商务司机岗位职责
2015/04/10 职场文书
文员岗位职责范本
2015/04/16 职场文书
2015年教育实习工作总结
2015/04/24 职场文书
2019森林防火宣传标语大全!
2019/07/03 职场文书
聊聊Python String型列表求最值的问题
2022/01/18 Python
Android实现图片九宫格
2022/06/28 Java/Android