最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

深入解析JavaScript框架Backbone.js中的事件机制_基础知识

来源:动视网 责编:小采 时间:2020-11-27 20:50:41
文档

深入解析JavaScript框架Backbone.js中的事件机制_基础知识

深入解析JavaScript框架Backbone.js中的事件机制_基础知识:事件模型及其原理 Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力 var Events = Backbone.Events = { .. } 对象通过listenTo侦听其他对象,通过trigger触发事件。可以脱离Backbone的MVC,在自定义的对象上使用事件 var
推荐度:
导读深入解析JavaScript框架Backbone.js中的事件机制_基础知识:事件模型及其原理 Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力 var Events = Backbone.Events = { .. } 对象通过listenTo侦听其他对象,通过trigger触发事件。可以脱离Backbone的MVC,在自定义的对象上使用事件 var
 事件模型及其原理
Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力

对象通过listenTo侦听其他对象,通过trigger触发事件。可以脱离Backbone的MVC,在自定义的对象上使用事件

执行结果:

Backbone的Model和View等核心类,都是继承自Backbone.Events的。例如Backbone.Model:

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

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

一个事件名可以对应多个回调,对于被侦听者而言,只知道回调的存在,并不知道具体是哪个对象在侦听它。当被侦听者调用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最后是否包含'/'的不确定性。

    这个正则匹配的是行末的非/字符,这样,像/resources这样的目标会匹配s,然后replace中使用分组编号$1捕获了s,将s替换为s/,这样就自动加上了缺失的/;而当/resources/这样目标却无法匹配到结果,也就不需要替换了。
    Model和Collection的关系
    在backbone中,即便一类的模型实例的确是在一个集合里面,也并没有强制要求使用集合类。但是使用集合有一些额外的好处,这些好处包括:

    url继承
    Model属于Collection后,可以继承Collection的url属性。Collection沿用了underscore90%的集合和数组操作,使得集合操作极其方便:

    自动侦听和转发集合中的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用来对返回的集合进行处理,通常是过滤掉不必要的数据。例如:

    通过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
  • 视图类还有几个属性可以导出,由外部初始化,它们是:

    内存泄漏
    事件机制可以很好的带来代码维护的便利,但是由于事件绑定会使对象之间的引用变得复杂和错乱,容易造成内存泄漏。下面的写法就会造成内存泄漏:

    使用下面的测试代码,并结合Chrome的堆内存快照来证明:

    点击开始,使用Chrome的'Profile'下的'Take Heap Snapshot'功能,查看当前堆内存情况,使用child类型过滤,可以看到Backbone对象实例一共有10个(1+1+4+4):

    之所以用child过滤,因为我们的类继承自Backbone的类型,而继承使用了重写原型的方法,Backbone在继承时,使用的变量名为child,最后,child被返回出来了
    点击排序后,再次抓取快照,可以看到实例个数变成了14个,这是因为,在render过程中,又创建了4个新的TaskView,而之前的4个TaskView并没有释放(之所以是4个是因为记录的条数是4)

    再次点击排序,再次抓取快照,实例数又增加了4个,变成了18个!

    那么,为什么每次排序后,之前的TaskView无法释放呢。因为TaskView的实例都会侦听model,导致model对新创建的TaskView的实例存在引用,所以旧的TaskView无法删除,又创建了新的,导致内存不断上涨。而且由于引用存在于change事件的回调队列里,model每次触发change都会通知旧的TaskView实例,导致执行很多无用的代码。那么如何改进呢?

    修改TaskCollectionView:

    Backbone的View有一个remove方法,这个方法除了删除View所关联的DOM对象,还会阻断事件侦听,它通过在listenTo方法时记录下来的那些被侦听对象(上文事件原理中提到),来使这些被侦听的对象删除对自己的引用。在remove内部使用事件基类的stopListening完成这个动作。
    上面的代码使用一个views数组来跟踪新创建的TaskView对象,并在render的时候,依次调用这些视图对象的remove,然后清空数组,这样这些TaskView对象就能得到释放。并且,除了调用remove,还调用了off,把视图对象可能的被外部的侦听也断开。

    事件驱动模块
    自定义事件:自定义事件比较适合多人合作开发,因为我们知道,函数名如果一样的话,那么后面的函数会覆盖前面的,而事件在绑定的情况下是不会被覆盖的。


    事件绑定
    除此之外,我们还可以自定义要绑定的被改变的数据类型:

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

    
     //自定义事件
     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
    
    listenTo
    

    istenTo

    模型集合器
    Backbone.Collection
    集合是模型的有序组合,我们可以在集合上绑定 "change" 事件,从而当集合中的模型发生变化时获得通知,集合也可以监听 "add" 和 “remove" 事件, 从服务器更新,并能使用 Underscore.js 提供的方法

    路由与历史管理

    
     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值找到对应的回调函数
    
    事件委托
     

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

    文档

    深入解析JavaScript框架Backbone.js中的事件机制_基础知识

    深入解析JavaScript框架Backbone.js中的事件机制_基础知识:事件模型及其原理 Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力 var Events = Backbone.Events = { .. } 对象通过listenTo侦听其他对象,通过trigger触发事件。可以脱离Backbone的MVC,在自定义的对象上使用事件 var
    推荐度:
    标签: js javascript 机制
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top