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 相关文章推荐
网页开发中的容易忽略的问题 javascript HTML中的table
Apr 15 Javascript
jQuery EasyUI中对表格进行编辑的实现代码
Jun 10 Javascript
Jquery easyui 实现动态树
Nov 17 Javascript
jQuery实现移动端手机商城购物车功能
Sep 24 Javascript
js print打印网页指定区域内容的简单实例
Nov 01 Javascript
Angularjs之filter过滤器(推荐)
Nov 27 Javascript
浅谈js中几种实用的跨域方法原理详解
Dec 02 Javascript
JavaScript实现格式化字符串函数String.format
Dec 16 Javascript
layer.confirm取消按钮绑定事件的方法
Aug 17 Javascript
angular2组件中定时刷新并清除定时器的实例讲解
Aug 31 Javascript
微信小程序swiper实现滑动放大缩小效果
Nov 15 Javascript
Vue Router 实现动态路由和常见问题及解决方法
Mar 06 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中使用cookie来保存用户登录信息的实现代码
2012/03/08 PHP
CI框架在CLI下执行占用内存过大问题的解决方法
2014/06/17 PHP
图解找出PHP配置文件php.ini的路径的方法
2014/08/20 PHP
PHP多进程编程实例
2014/10/15 PHP
php mongodb操作类 带几个简单的例子
2016/08/25 PHP
PHP实现的多维数组去重操作示例
2018/07/21 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
2019/11/21 PHP
javascript fullscreen全屏实现代码
2009/04/09 Javascript
Javascript 错误处理的几种方法
2009/06/13 Javascript
jQuery实现的感应鼠标悬停图片色彩渐显效果
2015/03/03 Javascript
JavaScript设计模式开发中组合模式的使用教程
2016/05/18 Javascript
JS从数组中随机取出几个数组元素的方法
2016/08/02 Javascript
jquery实现手机端单店铺购物车结算删除功能
2017/02/22 Javascript
详解angular2封装material2对话框组件
2017/03/03 Javascript
vue2.0中goods选购栏滚动算法的实现代码
2017/05/17 Javascript
JS实现加载时锁定HTML页面元素的方法
2017/06/24 Javascript
深入理解Vue 单向数据流的原理
2017/11/09 Javascript
vue项目中公用footer组件底部位置的适配问题
2018/05/10 Javascript
在vue-cli创建的项目中使用sass操作
2020/08/10 Javascript
[01:16:28]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第二场 2月23日
2021/03/11 DOTA
用Python实现web端用户登录和注册功能的教程
2015/04/30 Python
Python运行报错UnicodeDecodeError的解决方法
2016/06/07 Python
详解用python实现简单的遗传算法
2018/01/02 Python
python去除拼音声调字母,替换为字母的方法
2018/11/28 Python
对Python中实现两个数的值交换的集中方法详解
2019/01/11 Python
对Django 中request.get和request.post的区别详解
2019/08/12 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
在Django中自定义filter并在template中的使用详解
2020/05/19 Python
python3.7调试的实例方法
2020/07/21 Python
python 利用Pyinstaller打包Web项目
2020/10/23 Python
乡镇干部十八大感言
2014/02/17 职场文书
《小猪家的桃花树》教学反思
2014/04/11 职场文书
优秀三好学生事迹材料
2014/08/31 职场文书
井冈山红色之旅感想
2014/10/07 职场文书
欧元符号 €
2022/02/17 杂记
win11开机发生死循环重启怎么办?win11开机发生死循环重启解决方法
2022/08/05 数码科技