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的TreePanel中的应用
Oct 16 Javascript
JavaScript中的细节分析
Jun 30 Javascript
javascript:void(0)的问题使用探讨
Apr 10 Javascript
两个多选select(multiple左右)添加、删除选项和取值实例
May 12 Javascript
js判断某个方法是否存在实例代码
Jan 10 Javascript
JavaScript 学习笔记之变量及其作用域
Jan 14 Javascript
JS实现先显示大图后自动收起显示小图的广告代码
Sep 04 Javascript
javascript实现PC网页里的拖拽效果
Mar 14 Javascript
Vue.js学习之过滤器详解
Jan 22 Javascript
极简主义法编写JavaScript类
Nov 02 Javascript
解决Linux无法正常安装与卸载Node.js的方法
Jan 19 Javascript
Javascript生成器(Generator)的介绍与使用
Jan 31 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
php5中类的学习
2008/03/28 PHP
php 文件上传代码(限制jpg文件)
2010/01/05 PHP
分割GBK中文遭遇乱码的解决方法
2013/08/09 PHP
PHP实现即时输出、实时输出内容方法
2015/05/27 PHP
微信支付PHP SDK之微信公众号支付代码详解
2015/12/09 PHP
如何写php守护进程(Daemon)
2015/12/30 PHP
php通过curl添加cookie伪造登陆抓取数据的方法
2016/04/02 PHP
JS操作XML中DTD介绍及使用方法分析
2019/07/04 PHP
jquery 应用代码 方便的排序功能
2010/02/06 Javascript
javascript 打开页面window.location和window.open的区别
2010/03/17 Javascript
JavaScript的document对象和window对象详解
2010/12/30 Javascript
FF火狐下获取一个元素同类型的相邻元素实现代码
2012/12/15 Javascript
JavaScript中的noscript元素属性位置及作用介绍
2013/04/11 Javascript
js函数在frame中的相互调用详解
2014/03/03 Javascript
利用jquery操作Radio方法小结
2014/10/20 Javascript
jQuery弹出遮罩层效果完整示例
2016/09/13 Javascript
jQuery视差滚动效果网页实现方法经验总结
2016/09/29 Javascript
JavaScript 中 avalon绑定属性总结
2016/10/19 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
2017/01/10 Javascript
BootStrap 弹出层代码
2017/02/09 Javascript
百度地图JavascriptApi Marker平滑移动及车头指向行径方向
2017/03/13 Javascript
vue-cli webpack 引入jquery的方法
2018/01/10 jQuery
JavaScript如何对图片进行黑白化
2018/04/10 Javascript
微信小程序实现发送模板消息功能示例【通过openid推送消息给用户】
2019/05/05 Javascript
JavaScript HTML DOM元素 节点操作汇总
2019/07/29 Javascript
详解node登录接口之密码错误限制次数(含代码)
2019/10/25 Javascript
原生js实现随机点名
2020/07/05 Javascript
python 递归深度优先搜索与广度优先搜索算法模拟实现
2018/10/22 Python
python SVM 线性分类模型的实现
2019/07/19 Python
Python中lru_cache的使用和实现详解
2021/01/25 Python
学校师德承诺书
2014/05/23 职场文书
领导个人查摆剖析材料
2014/10/29 职场文书
HTML5页面音频自动播放的实现方式
2021/06/21 HTML / CSS
navicat 连接Ubuntu虚拟机的mysql的操作方法
2022/04/02 MySQL
mapstruct的用法之qualifiedByName示例详解
2022/04/06 Java/Android
Golang map映射的用法
2022/04/22 Golang