>

js中的事件机制

- 编辑:正版管家婆马报彩图 -

js中的事件机制

事件模型及其规律 Backbone.伊夫nts正是事件完结的着力,它能够让对象具备事件本事

长远剖判JavaScript框架Backbone.js中的事件机制,javascriptbackbone

事件模型及其规律 Backbone.Events正是事件达成的着力,它能够让对象具有事件手艺

var Events = Backbone.Events = { .. }

对象通过listenTo侦听别的对象,通过trigger触发事件。能够脱离Backbone的MVC,在自定义的对象上行使事件

var model = _.extend({},Backbone.Events);
var view = _.extend({},Backbone.Events);
view.listenTo(model,'custom_event',function(){ alert('catch the event') });
model.trigger('custom_event');

实行理并了结果:

图片 1

Backbone的Model和View等骨干类,都以继续自Backbone.伊芙nts的。比如Backbone.Model:

var Events = Backbone.Events = { .. }

var Model = Backbone.Model = function(attributes, options) {
 ...
};

_.extend(Model.prototype, Events, { ... })

从常理上讲,事件是这么工作的:

被侦听的对象保险一个事件数组_event,其余对象在调用listenTo时,会将事件名与回调维护到行列中:

图片 2

七个事件名可以对应三个回调,对于被侦听者来讲,只略知一叁遍调的留存,并不知器材体是哪位指标在侦听它。当被侦听者调用trigger(name)时,会遍历_event,选用同名的平地风波,并将其下部全部的回调都实行三次。

亟需格外注意的是,Backbone的listenTo完结,除了使被侦听者维护对侦听者的援引外,还使侦听者也维护了被侦听者。那是为了在适宜的时候,侦听者能够一边中止侦听。由此,即使是循环援引,不过利用Backbone的适用的主意能够很好的护卫,不会有标题,在后头的内存败露部分将看到。

除此以外,有的时候只希望事件在绑定后,当回调产生后,就接触绑定。那在局地对公私模块的援引时很有用。listenToOnce能够形成那或多或少

与服务器同步数据 backbone暗许完毕了一套与RESTful风格的服务端同步模型的机制,那套机制不仅可以够缓慢化解开辟职员的专门的工作量,并且能够使模型变得进一步健壮(在各样极度下还是可以保持数据一致性)。可是,要真正发挥这么些功用,一个与之同盟的服务端达成是很入眼的。为了注脚难点,如果服务端有如下REST风格的接口:

  • GET /resources 获取资源列表
  • POST /resources 创制一个能源,重临能源的满贯或局地字段
  • GET /resources/{id} 获取有个别id的能源详细的情况,重临能源的方方面面或一些字段
  • DELETE /resources/{id} 删除某些能源
  • PUT /resources/{id} 更新有些能源的整整字段,再次来到财富的成套或部分字段
  • PATCH /resources/{id} 更新有些能源的一部分字段,重返能源的百分百或局地字段

backbone会使用到地方那么些HTTP方法的地方重大有以下多少个:

  • Model.save() 逻辑上,依照当前那几个model的是否持有id来决断相应利用POST如故PUT,假若model未有id,表示是新的模型,将应用POST,将模型的字段全体交付到/resources;纵然model具备id,表示是已经存在的模型,将采用PUT,将模型的整整字段提交到/resources/{id}。当传入options包括patch:true的时候,save会发生PATCH。
  • Model.destroy() 会发生DELETE,指标url为/resources/{id},倘使当前model不带有id时,不会与服务端同步,因为那时候backbone以为model在服务端尚荒诞不经,没有供给删除
  • Model.fetch() 会产生GET,目的url为/resources/{id},并将赢得的性质更新model。
  • Collection.fetch() 会发生GET,指标url为/resources,并对回到的数组中的每种对象,自动实例化model
  • Collection.create() 实际将调用Model.save

options参数存在于地点任何五个主意的参数列表中,通过options能够修改backbone和ajax须要的部分行为,能够使用的options包罗:

  • wait: 能够内定是还是不是等待服务端的回到结果再立异model。默许情形下不等待
  • url: 能够覆盖掉backbone暗中认可使用的url格式
  • attrs: 能够钦定保存到服务端的字段有哪些,协作options.patch能够发生PATCH对模型举香港行政局地更新
  • patch: 钦赐使用一些更新的REST接口
  • data: 会被直接传送给jquery的ajax中的data,能够覆盖backbone全体的对上传的数量调控的行为
  • 任何: options中的任何参数都将平昔传送给jquery的ajax,作为其options

backbone通过Model的urlRoot属性也许是Collection的url属性得知具体的服务端接口地址,以便发起ajax。在Model的url私下认可完毕中,Model除了会旁观urlRoot,第二选项会是Model所在Collection的url,全数一时只须求在Collection里面书写url就能够了。

Backbone会依照与服务端要拓宽什么品种的操作,决定是或不是要增多id在url后边,以下代码是Model的暗中同意url完结:

url: function () {
 var base =
 _.result(this, 'urlRoot') ||
 _.result(this.collection, 'url') ||
 urlError();
 if (this.isNew()) return base;
 return base.replace(/([^/])$/, '$1/') + encodeURIComponent(this.id);
},

中间的正则式/([^/])$/是个很抢眼的拍卖,它消除了url最终是或不是包蕴'/'的不明确性。

其一正则相称的是行末的非/字符,那样,像/resources那样的对象会相称s,然后replace中选拔分组编号$1捕获了s,将s替换为s/,那样就自动抬高了缺点和失误的/;而当/resources/那样指标却一点办法也想不出来同盟到结果,也就无需替换了。
Model和Collection的关系
在backbone中,即使一类的模子实例的确是在二个凑合里面,也并不曾强制须要选择集结类。但是接纳集结有一对附加的益处,那些好处包罗:

url继承 Model属于Collection后,能够承继Collection的url属性。Collection沿用了underscore百分之八十的集聚和数组操作,使得会集操作特别方便:

// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
'lastIndexOf', 'isEmpty', 'chain', 'sample'];
Backbone巧妙的使用下面的代码将这些方法附加到Collection中:

// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function (method) {
 Collection.prototype[method] = function () {
 var args = slice.call(arguments); //将参数数组转化成真正的数组
 args.unshift(this.models);  //将Collection真正用来维护集合的数组,作为第一个个参数
 return _[method].apply(_, args); //使用apply调用underscore的方法
 };
});

电动侦听和转化集结中的Model事件 会面能够自行侦听并转载集结中的成分的事件,还大概有局地平地风波集合会做相应的极度规管理,这么些事件满含:

destroy 侦听到成分的destroy事件后,会自动将成分从集结中移除,并吸引remove事件
change:id 侦听到成分的id属性被change后,自动更新内部对model的引用关系
自动模型构造 应用Collection的fetch,可以加载服务端数据集结,与此同一时间,能够活动创制连锁的Model实例,并调用构造方法

要素重复剖断 Collection会依据Model的idAttribute钦命的独一键,来决断成分是还是不是再一次,暗许情状下独一键是id,能够重写idAttribute来覆盖。当元素重复的时候,可以选用是撤消重复成分,依然合併二种因素,暗中认可是甩掉的

模型转化 有时候从REST接口得到的多寡并无法一心满意分界面包车型大巴管理供给,能够经过Model.parse可能Collection.parse方法,在实例化Backbone对象前,对数据开展预管理。大要上,Model.parse用来对回到的单个对象举行质量的拍卖,而Collection.parse用来对回到的集合举办管理,日常是过滤掉不要求的多少。举个例子:

//只挑选type=1的book
var Books = Backbone.Collection.extend({
 parse:function(models,options){
 return _.filter(models , function(model){
  return model.type == 1;
 })
 }
})


//为Book对象添加url属性,以便渲染
var Book = Backbone.Model.extend({
 parse: function(model,options){
 return _.extend(model,{ url : '/books/' + model.id });
 }
})

透过Collection的fetch,自动实例化的Model,其parse也会被调用。

模型的暗中同意值 Model能够透过设置defaults属性来设置暗许值,那很有用。因为,无论是模型依然集结,fetch数据都以异步的,而频仍视图的渲染确实很恐怕在数额来临前就开展了,若无默许值的话,一些行使了模版引擎的视图,在渲染的时候也许会出错。比如underscore自带的视图引擎,由于应用with(){}语法,会因为对象缺乏属性而报错。

视图的el Backbone的视图对象拾叁分简答,对于开拓者来讲,仅仅关注一个el属性即可。el属性能够通过三种路子提交,优先级从高到低:

  • 实例化View的时候,传递el
  • 在类中申明el
  • 实例化View的时候传出tagName
  • 在类中注明tagName
  • 以上都未曾的气象下利用默许的'div'

到底什么样挑选,取决于以下几点:

  • 诚如而言,要是模块是公用模块,在类中不提供el,而是让外界在实例化的时候传出,那样能够保证国有的View的独立性,不至于依赖已经存在的DOM成分
  • tagName一般对于自成类别的View有用,比如table中的某行tr,ul中的有些li
  • 多少DOM事件必需在html存在的情形下工夫绑定成功,举个例子blur,对于这种View,只好选用已经存在的html

视图类还应该有多少个属性能够导出,由外界开始化,它们是:

// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];

内部存款和储蓄器泄漏 事件机制得以很好的拉动代码维护的方便人民群众,然则由于事件绑定会使对象之间的引用变得复杂和混乱,轻易导致内部存款和储蓄器泄漏。下边包车型地铁写法就能够导致内部存款和储蓄器泄漏:

var Task = Backbone.Model.extend({})

var TaskView = Backbone.View.extend({
 tagName: 'tr',
 template: _.template('<td><%= id %></td><td><%= summary %></td><td><%= description %></td>'),
 initialize: function(){
 this.listenTo(this.model,'change',this.render);
 },
 render: function(){
 this.$el.html( this.template( this.model.toJSON() ) );
 return this;
 }
})

var TaskCollection = Backbone.Collection.extend({
 url: 'http://api.test.clippererm.com/api/testtasks',
 model: Task,
 comparator: 'summary'
})

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 },
 render: function(){
 var _this = this;

 //简单粗暴的将DOM清空
 //在sort事件触发的render调用时,之前实例化的TaskView对象会泄漏
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

使用上边包车型客车测验代码,并构成Chrome的堆内部存储器快速照相来申明:

var tasks = null;
var tasklist = null;

$(function () {
 // body...
 $('#start').click(function(){
 tasks = new TaskCollection();
 tasklist = new TaskCollectionView({
  collection : tasks,
  el: '#tasklist'
 })

 tasklist.render();
 tasks.fetch();
 })

 $('#refresh').click(function(){
 tasks.fetch({ reset : true });
 })

 $('#sort').click(function(){
 //将侦听sort放在这里,避免第一次加载数据后的自动排序,触发的sort事件,以至于混淆
 tasklist.listenToOnce(tasks,'sort',tasklist.render);
 tasks.sort();
 })
})

点击开首,使用Chrome的'Profile'下的'Take Heap Snapshot'功效,查看当前堆内存意况,使用child类型过滤,能够看来Backbone对象实例一共有十一个(1+1+4+4):

图片 3

由此用child过滤,因为大家的类承袭自Backbone的类别,而后续使用了重写原型的点子,Backbone在此伏彼起时,使用的变量名字为child,最后,child被重回出来了
点击排序后,再次抓取快速照相,能够看到实例个数形成了十五个,那是因为,在render进度中,再创办了4个新的TaskView,而在此之前的4个TaskView并不曾自由(之所以是4个是因为记录的条数是4)

图片 4

再也点击排序,再一次抓取快速照相,实例数又增添了4个,变成了19个!

图片 5

那么,为啥历次排序后,从前的TaskView不可能释放吧。因为TaskView的实例都会侦听model,导致model对新成立的TaskView的实例存在引用,所以旧的TaskView不恐怕删除,再次创下办了新的,导致内部存款和储蓄器不断回涨。并且由于援用存在于change事件的回调队列里,model每一次触发change都会通知旧的TaskView实例,导致推行比相当多失效的代码。那么怎么样改进呢?

修改TaskCollectionView:

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 //初始化一个view数组以跟踪创建的view
 this.views =[]
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 //将新创建的view保存起来
 this.views.push(view);
 },
 render: function(){
 var _this = this;

 //遍历views数组,并对每个view调用Backbone的remove
 _.each(this.views,function(view){
  view.remove().off();
 })

 //清空views数组,此时旧的view就变成没有任何被引用的不可达对象了
 //垃圾回收器会回收它们
 this.views =[];
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

Backbone的View有二个remove方法,那些方法除了剔除View所涉及的DOM对象,还只怕会阻断事件侦听,它通过在listenTo方法时记录下来的那个被侦听对象(上文事件规律中提到),来使那么些被侦听的对象删除对和睦的援用。在remove内部选取事件基类的stopListening完结那么些动作。
上边包车型客车代码应用一个views数组来追踪新创立的TaskView对象,并在render的时候,依次调用那一个视图对象的remove,然后清空数组,那样那个TaskView对象就能够收获释放。並且,除了调用remove,还调用了off,把视图对象或许的被外表的侦听也断开。

事件驱动模块 自定义事件:自定义事件比较符合多个人合营开荒,因为大家领略,函数名假如相同的话,那么前边的函数会覆盖前边的,而事件在绑定的情景下是不会被遮住的。

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4';
 },
 initialization : function(){ //初始化构造函数
  this.on('change',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>

事件绑定 除了那些之外,我们还足以自定义要绑定的被更换的数据类型:

object.on(event, callback, [context])

绑定贰个回调函数到三个目的上, 当事件触发时实行回调函数 :

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4',
  age : 21;
 },
 initialization : function(){ //初始化构造函数
  this.on('change:age',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>
listenTo
<script type="text/javascript">
 $(function(){
 var Mod = Backbone.Model.extend({
  defaults : {
  name : 'trigkit4'
  }
 });
 var V = Backbone.View.extend({
  initialize : function(){
  this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
  },
  show : function(model){
  $('body').append('<div>' + model.get('name') + '</div>');
  }
 });

 var m = new Mod;
 var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
 m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了 
 });
</script>

istenTo

<script type="text/javascript">
 $(function(){
  var Mod = Backbone.Model.extend({
   defaults : {
    name : 'trigkit4'
   }
  });
  var V = Backbone.View.extend({
   initialize : function(){
    this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
   },
   show : function(model){
    $('body').append('<div>' + model.get('name') + '</div>');
   }
  });

  var m = new Mod;
  var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
  m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了  
 });
</script>

模型群集器 Backbone.Collection
会合是模型的静止组合,大家能够在汇集上绑定 "change" 事件,进而当集结中的模型产生变化时收获通报,集结也得以监听 "add" 和 “remove" 事件, 从服务器更新,并能使用 Underscore.js 提供的章程

路由与野史管理

<script type="text/javascript">
  var Workspace = Backbone.Router.extend({
    routes: {
      "help":         "help",
      "search/:query":      "search",
      "search/:query/p:page":"    search"
    },

    help : function(){
      alert(123);
    },

    search : function(query,page){
      alert(345);
    }
  });

  var w = new Workspace;

  Backbone.history.start();//backbone通过hash值找到对应的回调函数
</script>
事件委托
  <script type="text/javascript">
    $(function(){
      var V = Backbone.View.extend({
        el : $('body'),
        //对events进行集体操作
        events : {
          "click input" : "hello", 
          "mouseover li" : "world"
        },
        hello : function(){
          alert(1234);
        },
        world : function(){
          alert(123)
        }
      });
      var view = new V;
    });
  </script>
<body>
  <imput type = "button" value = "hwx" />
  <ul>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
  </ul>
</body>

事件委托 格式:事件 + 空格 + 由何人来触发 : 对应的回调函数

var Events = Backbone.Events = { .. }

您或然感兴趣的稿子:

  • 轻易领悟Backbone.js的Model模型以及View视图的源码
  • Backbone.js框架中简易的View视图编写学习笔记
  • 解说JavaScript的Backbone.js框架的MVC结构划设想计观念
  • 轻量级javascript 框架Backbone使用指南
  • Backbone.js的有个别应用技巧
  • Backbone.js 0.9.2 源码注释汉语翻译版
  • Backbone.js的Hello World程序实例
  • Backbone.js中的集合详解
  • Javascript MVC框架Backbone.js详解
  • JavaScript的Backbone.js框架的有个别应用建议整理

事件模型及其规律 Backbone.Events就是事件完成的中坚,它能够让对象具备事件能...

指标通过listenTo侦听别的对象,通过trigger触发事件。能够脱离Backbone的MVC,在自定义的目标上利用事件

var model = _.extend({},Backbone.Events);
var view = _.extend({},Backbone.Events);
view.listenTo(model,'custom_event',function(){ alert('catch the event') });
model.trigger('custom_event');

实行结果:

图片 6

Backbone的Model和View等大旨类,都以继续自Backbone.伊芙nts的。举例Backbone.Model:

var Events = Backbone.Events = { .. }

var Model = Backbone.Model = function(attributes, options) {
 ...
};

_.extend(Model.prototype, Events, { ... })

从常理上讲,事件是这样职业的:

被侦听的对象保险一个风云数组_event,其余对象在调用listenTo时,会将事件名与回调维护到行列中:

图片 7

一个风浪名能够对应多个回调,对于被侦听者来讲,只晓得回调的留存,并不知器具体是哪位目的在侦听它。当被侦听者调用trigger(name)时,会遍历_event,选拔同名的平地风波,并将其下部全部的回调都推行贰回。

亟待额外注意的是,Backbone的listenTo完结,除了使被侦听者维护对侦听者的引用外,还使侦听者也保险了被侦听者。那是为了在适当的时候,侦听者能够一边中止侦听。由此,即使是循环引用,不过利用Backbone的适宜的办法能够很好的护卫,不会有标题,在末端的内存败露部分将看到。

其余,有的时候只期待事件在绑定后,当回调发生后,就接触绑定。那在局地对国有模块的引用时很有用。listenToOnce能够达成那或多或少

与服务器同步数据 backbone私下认可实现了一套与RESTful风格的服务端同步模型的建制,那套机制不只能缓慢消除开荒人士的专业量,何况能够使模型变得尤其健壮(在各类特别下还是可以保持数据一致性)。然则,要实在发挥那些成效,一个与之合营的服务端达成是很主要的。为了表明难题,要是服务端有如下REST风格的接口:

  • GET /resources 获取财富列表
  • POST /resources 成立一个财富,再次来到能源的万事或局地字段
  • GET /resources/{id} 获取有些id的能源实际情况,再次来到能源的全方位或一些字段
  • DELETE /resources/{id} 删除有个别财富
  • PUT /resources/{id} 更新有些财富的一切字段,再次来到能源的全数或一些字段
  • PATCH /resources/{id} 更新某些能源的局地字段,重返能源的整套或部分字段

backbone会使用到上面这一个HTTP方法的地点根本有以下多少个:

  • Model.save() 逻辑上,根据当前以此model的是还是不是享有id来剖断应该运用POST照旧PUT,借使model未有id,表示是新的模型,将运用POST,将模型的字段全部交由到/resources;如果model具备id,表示是现已存在的模型,将采用PUT,将模型的全体字段提交到/resources/{id}。当传入options饱含patch:true的时候,save会产生PATCH。
  • Model.destroy() 会爆发DELETE,目的url为/resources/{id},即便当前model不含有id时,不会与服务端同步,因为那时backbone以为model在服务端尚不真实,无需删除
  • Model.fetch() 会发生GET,目的url为/resources/{id},并将赢得的个性更新model。
  • Collection.fetch() 会发生GET,目的url为/resources,并对回到的数组中的每一种对象,自动实例化model
  • Collection.create() 实际将调用Model.save

options参数存在于地方任何八个办法的参数列表中,通过options能够修改backbone和ajax乞求的一部分作为,能够行使的options包含:

  • wait: 能够钦命是不是等待服务端的回来结果再革新model。暗中认可情状下不等待
  • url: 能够覆盖掉backbone暗中认可使用的url格式
  • attrs: 能够内定保存到服务端的字段有怎么着,协作options.patch能够生出PATCH对模型进行部分更新
  • patch: 内定使用部分更新的REST接口
  • data: 会被一向传送给jquery的ajax中的data,能够覆盖backbone全数的对上传的数额调节的一坐一起
  • 别的: options中的任何参数都将直接传送给jquery的ajax,作为其options

backbone通过Model的urlRoot属性只怕是Collection的url属性得知具体的服务端接口地址,以便发起ajax。在Model的url默许完毕中,Model除了会侦察urlRoot,第二摘取会是Model所在Collection的url,全体有的时候只要求在Collection里面书写url就足以了。

Backbone会依据与服务端要开展哪些项目标操作,决定是不是要加多id在url后边,以下代码是Model的默许url完成:

url: function () {
 var base =
 _.result(this, 'urlRoot') ||
 _.result(this.collection, 'url') ||
 urlError();
 if (this.isNew()) return base;
 return base.replace(/([^/])$/, '$1/') + encodeURIComponent(this.id);
},

里头的正则式/([^/])$/是个很好看妙的拍卖,它化解了url最后是或不是含有'/'的不显明性。

以此正则相称的是行末的非/字符,那样,像/resources那样的靶子会相称s,然后replace中使用分组编号$1捕获了s,将s替换为s/,那样就机关抬高了缺点和失误的/;而当/resources/那样目的却无能为力合营到结果,也就没有须求替换了。
Model和Collection的关系
在backbone中,固然一类的模型实例的确是在贰个成团里面,也并未有强制供给使用集结类。可是利用群集有局地相当的补益,这么些低价包蕴:

url继承 Model属于Collection后,能够继续Collection的url属性。Collection沿用了underscore八成的聚合和数组操作,使得集合操作非常方便:

// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
'lastIndexOf', 'isEmpty', 'chain', 'sample'];
Backbone巧妙的使用下面的代码将这些方法附加到Collection中:

// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function (method) {
 Collection.prototype[method] = function () {
 var args = slice.call(arguments); //将参数数组转化成真正的数组
 args.unshift(this.models);  //将Collection真正用来维护集合的数组,作为第一个个参数
 return _[method].apply(_, args); //使用apply调用underscore的方法
 };
});

机动侦听和中间转播会集中的Model事件 聚拢可以自行侦听并转账会集中的成分的事件,还只怕有一点点事件集合会做相应的分裂平时管理,那么些事件富含:

destroy 侦听到成分的destroy事件后,会自行将成分从集结中移除,并掀起remove事件
change:id 侦听到成分的id属性被change后,自动更新内部对model的征引关系
自动模型构造 动用Collection的fetch,能够加载服务端数据集结,与此同一时候,能够活动创造连锁的Model实例,并调用构造方法

要素重复判定 Collection会依照Model的idAttribute钦命的独一键,来判别成分是或不是再一次,私下认可意况下独一键是id,能够重写idAttribute来覆盖。当成分重复的时候,能够选取是甩掉重复成分,仍然合併两种因素,默许是撤销的

模型转化 有的时候候从REST接口获得的数码并无法一心满意分界面包车型大巴管理要求,能够通过Model.parse或许Collection.parse方法,在实例化Backbone对象前,对数据开展预管理。轮廓上,Model.parse用来对回到的单个对象实行品质的拍卖,而Collection.parse用来对回到的汇集实行管理,日常是过滤掉不要求的数目。例如:

//只挑选type=1的book
var Books = Backbone.Collection.extend({
 parse:function(models,options){
 return _.filter(models , function(model){
  return model.type == 1;
 })
 }
})


//为Book对象添加url属性,以便渲染
var Book = Backbone.Model.extend({
 parse: function(model,options){
 return _.extend(model,{ url : '/books/' + model.id });
 }
})

通过Collection的fetch,自动实例化的Model,其parse也会被调用。

模型的暗许值 Model能够通过设置defaults属性来设置默许值,那很有用。因为,无论是模型依然集结,fetch数据都以异步的,而频仍视图的渲染确实一点都不小概在数量来临前就实行了,若无默许值的话,一些采取了模版引擎的视图,在渲染的时候大概会出错。举例underscore自带的视图引擎,由于选择with(){}语法,会因为对象贫乏属性而报错。

视图的el Backbone的视图对象十分简答,对于开荒者来说,仅仅关注三个el属性就可以。el属性能够透过四种路子提交,优先级从高到低:

  • 实例化View的时候,传递el
  • 在类中注解el
  • 实例化View的时候传出tagName
  • 在类中表明tagName
  • 以上都并没有的意况下采用暗中认可的'div'

到底如何挑选,取决于以下几点:

  • 貌似而言,即便模块是公用模块,在类中不提供el,而是让外界在实例化的时候传出,那样能够保持国有的View的独立性,不至于信赖已经存在的DOM元素
  • tagName一般对于自成类别的View有用,比如table中的某行tr,ul中的某些li
  • 有一点点DOM事件必得在html存在的情况下技艺绑定成功,比方blur,对于这种View,只好选取已经存在的html

视图类还会有多少个属性能够导出,由外界初步化,它们是:

// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];

内部存储器泄漏 事件机制得以很好的拉动代码维护的便利,不过由于事件绑定会使对象之间的引用变得复杂和混乱,轻松导致内部存款和储蓄器泄漏。下面的写法就能够形成内部存款和储蓄器泄漏:

var Task = Backbone.Model.extend({})

var TaskView = Backbone.View.extend({
 tagName: 'tr',
 template: _.template('<td><%= id %></td><td><%= summary %></td><td><%= description %></td>'),
 initialize: function(){
 this.listenTo(this.model,'change',this.render);
 },
 render: function(){
 this.$el.html( this.template( this.model.toJSON() ) );
 return this;
 }
})

var TaskCollection = Backbone.Collection.extend({
 url: 'http://api.test.clippererm.com/api/testtasks',
 model: Task,
 comparator: 'summary'
})

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 },
 render: function(){
 var _this = this;

 //简单粗暴的将DOM清空
 //在sort事件触发的render调用时,之前实例化的TaskView对象会泄漏
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

动用下边包车型客车测量试验代码,并整合Chrome的堆内部存款和储蓄器快速照相来注脚:

var tasks = null;
var tasklist = null;

$(function () {
 // body...
 $('#start').click(function(){
 tasks = new TaskCollection();
 tasklist = new TaskCollectionView({
  collection : tasks,
  el: '#tasklist'
 })

 tasklist.render();
 tasks.fetch();
 })

 $('#refresh').click(function(){
 tasks.fetch({ reset : true });
 })

 $('#sort').click(function(){
 //将侦听sort放在这里,避免第一次加载数据后的自动排序,触发的sort事件,以至于混淆
 tasklist.listenToOnce(tasks,'sort',tasklist.render);
 tasks.sort();
 })
})

点击初叶,使用Chrome的'Profile'下的'Take Heap Snapshot'功用,查看当前堆内部存款和储蓄器意况,使用child类型过滤,能够观察Backbone对象实例一共有拾一个(1+1+4+4):

图片 8

为此用child过滤,因为大家的类承袭自Backbone的项目,而接二连三使用了重写原型的方法,Backbone在继续时,使用的变量名称为child,最终,child被重回出来了
点击排序后,再一次抓取快速照相,能够见见实例个数形成了15个,那是因为,在render进程中,更创制了4个新的TaskView,而从前的4个TaskView并未自由(之所以是4个是因为记录的条数是4)

图片 9

双着重击排序,再度抓取快速照相,实例数又扩张了4个,产生了二十一个!

图片 10

那正是说,为啥老是排序后,此前的TaskView无法释放吧。因为TaskView的实例都会侦听model,导致model对新创制的TaskView的实例存在援引,所以旧的TaskView不能够删除,更创办了新的,导致内部存款和储蓄器不断高涨。并且由于援用存在于change事件的回调队列里,model每一趟触发change都会通报旧的TaskView实例,导致实行非常多无效的代码。那么哪些立异呢?

修改TaskCollectionView:

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 //初始化一个view数组以跟踪创建的view
 this.views =[]
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 //将新创建的view保存起来
 this.views.push(view);
 },
 render: function(){
 var _this = this;

 //遍历views数组,并对每个view调用Backbone的remove
 _.each(this.views,function(view){
  view.remove().off();
 })

 //清空views数组,此时旧的view就变成没有任何被引用的不可达对象了
 //垃圾回收器会回收它们
 this.views =[];
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

Backbone的View有多个remove方法,那些措施除了剔除View所波及的DOM对象,还有大概会阻断事件侦听,它经过在listenTo方法时记录下来的那个被侦听对象(上文事件规律中涉及),来使那么些被侦听的靶子删除对友好的援引。在remove内部选取事件基类的stopListening达成这些动作。
上面包车型地铁代码应用一个views数组来跟踪新创设的TaskView对象,并在render的时候,依次调用那几个视图对象的remove,然后清空数组,那样那个TaskView对象就能够博得释放。并且,除了调用remove,还调用了off,把视图对象恐怕的被外表的侦听也断开。

事件驱动模块 自定义事件:自定义事件比较符合几人合营开辟,因为大家通晓,函数名假使同样的话,那么前面包车型大巴函数会覆盖前边的,而事件在绑定的气象下是不会被遮住的。

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4';
 },
 initialization : function(){ //初始化构造函数
  this.on('change',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>

事件绑定 除开,大家仍能自定义要绑定的被改成的数据类型:

object.on(event, callback, [context])

绑定三个回调函数到一个对象上, 当事件触发时推行回调函数 :

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4',
  age : 21;
 },
 initialization : function(){ //初始化构造函数
  this.on('change:age',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>
listenTo
<script type="text/javascript">
 $(function(){
 var Mod = Backbone.Model.extend({
  defaults : {
  name : 'trigkit4'
  }
 });
 var V = Backbone.View.extend({
  initialize : function(){
  this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
  },
  show : function(model){
  $('body').append('<div>' + model.get('name') + '</div>');
  }
 });

 var m = new Mod;
 var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
 m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了 
 });
</script>

istenTo

<script type="text/javascript">
 $(function(){
  var Mod = Backbone.Model.extend({
   defaults : {
    name : 'trigkit4'
   }
  });
  var V = Backbone.View.extend({
   initialize : function(){
    this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
   },
   show : function(model){
    $('body').append('<div>' + model.get('name') + '</div>');
   }
  });

  var m = new Mod;
  var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
  m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了  
 });
</script>

模型会集器 Backbone.Collection
聚拢是模型的不改变组合,我们得以在集聚上绑定 "change" 事件,进而当集合中的模型发生变化时获得通报,集合也可以监听 "add" 和 “remove" 事件, 从服务器更新,并能使用 Underscore.js 提供的点子

路由与正史管理

<script type="text/javascript">
  var Workspace = Backbone.Router.extend({
    routes: {
      "help":         "help",
      "search/:query":      "search",
      "search/:query/p:page":"    search"
    },

    help : function(){
      alert(123);
    },

    search : function(query,page){
      alert(345);
    }
  });

  var w = new Workspace;

  Backbone.history.start();//backbone通过hash值找到对应的回调函数
</script>
事件委托
  <script type="text/javascript">
    $(function(){
      var V = Backbone.View.extend({
        el : $('body'),
        //对events进行集体操作
        events : {
          "click input" : "hello", 
          "mouseover li" : "world"
        },
        hello : function(){
          alert(1234);
        },
        world : function(){
          alert(123)
        }
      });
      var view = new V;
    });
  </script>
<body>
  <imput type = "button" value = "hwx" />
  <ul>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
  </ul>
</body>

事件委托 格式:事件 + 空格 + 由哪个人来触发 : 对应的回调函数

您或然感兴趣的篇章:

  • js自定义事件及事件交互原理概述(一)
  • JavaScript自定义事件介绍
  • 详解javascript实现自定义事件
  • js自定义事件及事件交互原理概述(二)
  • javascript 自定义事件初探
  • js自定义事件代码表达
  • js事件监听机制(事件捕获)总计
  • 谈一谈JS新闻机制和事件机制的知道
  • 深远精通JS DOM事件机制
  • 选用Javascript达成一套自定义事件机制

本文由计算机操作发布,转载请注明来源:js中的事件机制