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 相关文章推荐
jQuery随机切换图片的小例子
Apr 18 Javascript
JavaScript实现分页效果
Mar 28 Javascript
使用jQuery,Angular实现登录界面验证码详解
Apr 27 jQuery
详解vue axios中文文档
Sep 12 Javascript
js实现可以点击收缩或张开的悬浮窗
Sep 18 Javascript
利用vue + koa2 + mockjs模拟数据的方法教程
Nov 22 Javascript
使用JS获取SessionStorage的值
Jan 12 Javascript
关于node-bindings无法在Electron中使用的解决办法
Dec 18 Javascript
vue.js实现数据库的JSON数据输出渲染到html页面功能示例
Aug 03 Javascript
使用ThinkJs搭建微信中控服务的实现方法
Aug 08 Javascript
js 使用ajax设置和获取自定义header信息的方法小结
Mar 12 Javascript
ES11新增的这9个新特性,你都掌握了吗
Oct 15 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 array_push 数组函数
2009/12/26 PHP
url decode problem 解决方法
2011/12/26 PHP
JS异常处理try..catch语句的作用和实例
2014/05/05 PHP
PHP实现批量清空删除指定文件夹所有内容的方法
2017/05/30 PHP
jQuery 翻牌或百叶窗效果(内容三秒自动切换)
2012/06/14 Javascript
Javascript removeChild()删除节点及删除子节点的方法
2015/12/27 Javascript
基于BootStrap Metronic开发框架经验小结【一】框架总览及菜单模块的处理
2016/05/12 Javascript
jQuery时间日期三级联动(推荐)
2016/11/27 Javascript
vue-cli webpack 开发环境跨域详解
2017/05/18 Javascript
详解node如何让一个端口同时支持https与http
2017/07/04 Javascript
jQuery实现简单的下拉菜单导航功能示例
2017/12/07 jQuery
JavaScript实现单例模式实例分享
2017/12/22 Javascript
webpack配置导致字体图标无法显示的解决方法
2018/03/06 Javascript
MVVM框架下实现分页功能示例
2018/06/14 Javascript
解决vue下载后台传过来的乱码流的问题
2020/12/05 Vue.js
[43:18]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.22
2019/09/05 DOTA
Python中使用logging模块打印log日志详解
2015/04/05 Python
快速排序的算法思想及Python版快速排序的实现示例
2016/07/02 Python
Python实现将数据框数据写入mongodb及mysql数据库的方法
2018/04/02 Python
python3+PyQt5使用数据库窗口视图
2018/04/24 Python
Python3.遍历某文件夹提取特定文件名的实例
2018/04/26 Python
Python 修改列表中的元素方法
2018/06/26 Python
如何在mac版pycharm选择python版本
2020/07/21 Python
会计专业应届生求职信
2013/11/24 职场文书
四川成都导游欢迎词
2014/01/18 职场文书
英文商务邀请信
2014/01/22 职场文书
秋季运动会广播稿
2014/02/22 职场文书
绿色环保标语
2014/06/12 职场文书
车贷收入证明范本
2014/09/14 职场文书
2015年城市管理工作总结
2015/05/23 职场文书
离婚上诉状范文
2015/05/23 职场文书
小学班级标语口号大全
2015/12/26 职场文书
加强党性修养心得体会
2016/01/21 职场文书
公司要求试用期员工提交“述职报告”,该怎么写?
2019/07/17 职场文书
Python 的 sum() Pythonic 的求和方法详细
2021/10/16 Python
【DOTA2】半决赛强强对话~ PSG LGD vs EHOME - DPC 2022 CN REGIONAL FINALS WINTER
2022/04/02 DOTA