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 相关文章推荐
解决Extjs 4 Panel作为Window组件的子组件时出现双重边框问题
Jan 11 Javascript
E3 tree 1.6在Firefox下显示问题的修复方法
Jan 30 Javascript
JS实现切换标签页效果实例代码
Nov 01 Javascript
JavaScript实现url地址自动检测并添加URL链接示例代码
Nov 12 Javascript
jquery.map()方法的使用详解
Jul 09 Javascript
分享使用AngularJS创建应用的5个框架
Dec 05 Javascript
无缝滚动的简单实现代码(推荐)
Jun 07 Javascript
JSP基于Bootstrap分页显示实例解析
Jun 12 Javascript
AngularJS $injector 依赖注入详解
Sep 14 Javascript
Vue自定义过滤器格式化数字三位加一逗号实现代码
Mar 23 Javascript
javascript面向对象三大特征之继承实例详解
Jul 24 Javascript
JavaScript this关键字的深入详解
Jan 14 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
php高级编程-函数-郑阿奇
2011/07/04 PHP
php中get_defined_constants函数用法实例分析
2015/05/12 PHP
PHP CURL 多线程操作代码实例
2015/05/13 PHP
php支持中文字符串分割的函数
2015/05/28 PHP
laravel 5.1下php artisan migrate的使用注意事项总结
2017/06/07 PHP
PHP array_reduce()函数的应用解析
2018/10/28 PHP
URI、URL和URN之间的区别与联系
2006/12/20 Javascript
放弃用你的InnerHTML来输出HTML吧 jQuery Tmpl不详细讲解
2013/04/20 Javascript
script标签属性用type还是language
2015/01/21 Javascript
javascript模拟评分控件实现方法
2015/05/13 Javascript
Bootstrap教程JS插件滚动监听学习笔记分享
2016/05/18 Javascript
Google 地图API Map()构造器详解
2016/08/06 Javascript
JavaScript中cookie工具函数封装的示例代码
2016/10/11 Javascript
js获取css的各种样式并且设置他们的方法
2017/08/22 Javascript
angular指令笔记ng-options的使用方法
2017/09/18 Javascript
vuejs router history 配置到iis的方法
2018/09/20 Javascript
Python切片用法实例教程
2014/09/08 Python
python中的全局变量用法分析
2015/06/09 Python
使用rst2pdf实现将sphinx生成PDF
2016/06/07 Python
Python实现拷贝多个文件到同一目录的方法
2016/09/19 Python
Python自然语言处理之词干,词形与最大匹配算法代码详解
2017/11/16 Python
python 实现一次性在文件中写入多行的方法
2019/01/28 Python
python3.5安装python3-tk详解
2019/04/26 Python
Python操作SQLite数据库过程解析
2019/09/02 Python
Selenium python时间控件输入问题解决方案
2020/07/22 Python
HTML5样式控制示例代码
2013/11/27 HTML / CSS
Bergfreunde丹麦:登山装备网上零售商
2017/02/26 全球购物
Coggles美国/加拿大:高级国际时装零售商
2018/10/23 全球购物
商场开业庆典策划方案
2014/06/02 职场文书
学校运动会广播稿范文
2014/10/02 职场文书
公司经营目标责任书
2015/01/29 职场文书
2015年秋季运动会前导词
2015/07/20 职场文书
2016年度继续教育学习心得体会
2016/01/19 职场文书
公务员廉洁从政心得体会
2016/01/19 职场文书
《火烧云》教学反思
2016/02/23 职场文书
vue项目proxyTable配置和部署服务器
2022/04/14 Vue.js