注意:强烈建议一边阅读源码一边阅读本文。html
终于到了backbone
源码解读的最后一篇,这一篇和前面几篇时间上有必定的间隔(由于要回学校有一堆乱七八糟的事...)。在这一篇里面会讲解Bakcbone
的sync
& router
& histrory
。sync
比较简单,可是路由的部分就比较复杂了。我的以为是整个backbone
源码里面最很差懂的一个部分,这个部分也使得backbone
能够方便实现能够“返回”的单页面应用。我的以为这个部分其实并无很MVC
有很密切的关系,可是它很是重要。读过源码就会发现,其实这一个部分与其余的模块(Model
,Collection
& View
)相对独立。若是不但愿使用backbone
但但愿能用到这个路由系统的话估计拆出来难度也不会很大。node
整体来讲路由模块由Router
和Histrory
组成,而Router
事实上能够当作是对History
的一个封装。用户直接操做的部分时Router
,相关函数的处理(路由匹配时调用的函数)也是在Router
中完成。History
主要是处理一个更加棘手的问题,就是有关连接的问题。这里面有关于跨浏览器的解决方案是很是值得学习的。jquery
Router
是对History
的封装,也是给用户定义路由的接口。通常来讲,用户在使用Router
的时候会定义一个routers
的对象,里面是想关路由与处理函数组成的key-value
。Router
代码中主要作两件事,一件是对正则表达式的操做(能够看见里面不少使人痛苦的正则表达式),另外一件事就是事件相关的绑定了。Router
的相关代码很少,写得比较精简。git
Router
里面定义了两种方法来定义路由事件,一个方法是用户定义routers
,经过初始化调用_bindRoutes
函数;一个方法是用自带的route
函数。其实两个方法本质上都是调用了route
函数,_bindRoutes
里面实际上也是经过循环来调用route
函数。所以路由函数重点在于route
函数。github
在route
函数里面,一开始是进行一些参数的整理。而后就是调用了History
模块的route
函数,把正则(匹配参数用的)和一个回调函数传了进去。在回调函数里面就是作 执行函数
——触发router的事件
——触发history的事件
这几个步骤,在History
的route
函数里面,只是简单的插入地把key
和callback
组成对象插入handlers
数组里面而已。ajax
Router
函数里面最难懂也很是重要的部分是格式的转换。在Router
里面有两个重要的函数_routeToRegExp
函数和_extractParameters
两个,这两个函数与正则密切相关。正则表达式
_extractParameters
函数的做用是利用正则表达式,把传进来的url
片断fragment
分割成片断存进数组当中。这些片断是真实的已经匹配出来的参数,在route
函数里面会把这些参数传给用户定义的函数里面,供用户使用。segmentfault
_routeToRegExp
函数是一个简单,但要彻底理解很难的函数。这个函数的做用就是返回一个RegExp
对象,经过这一个对象来匹配当前的连接,而后从中获得参数。进入这个函数以后会经过字符串的replace
函数,匹配出路由的是哪几(或一)种状况,而且替代成能够捕获参数的正则字符串。好比说把路由定义里的/:page
或者*fragment
这样的字符串经过事先定义好的几个正则匹配到,而后换成带()
的能够捕获的形式,而后在建立正则去捕获真正须要的常数。api
backbone
中对于History
模块的使用是经过用构造方式调用(new)
返回一个可使用prototype
方法的对象来实现的。Backbone.history = new History;
这个模块很是重要,并且在整个backbone
里面能够说是最难彻底读懂的。下面我会从三个方面来说:一个方面是有关于路径格式处理的问题,在这方面也有不少和正则表达式相关的函数;另外一个方面是最关键的一个方面,就是History
检测浏览器来使用不一样的路由控制方式;最后一个方面就是经过具体的函数来说解它是如何实现第二点各方面所说的控制的。数组
History
从接口的角度来讲有start
函数做为初始化的设置,还有经过Router
模块封装的navigate
方法。Router
里面的不少处理须要调用到这个模块的方法。
History
事实上也是对location/history
必定程度上的封装。不少时候是经过location
模块来读取匹配,经过history
的一些方法来进行路由控制。
用户能够设置root
,做为根路径。这个根路径在模块中有一些判断和处理的地方。比方说肯定当前是否在根路径,或者在当前URL
提取出相应的锚点等等都须要用到root
这个内部变量。
在这个函数里面咱们能够看到URL
的格式分为了两种。一种是hash
方式,一种是search
方式(主要是兼容较老的浏览器)。在这里经过判断来进行浏览器能力检测。对于大部分现代浏览器来讲,事实上大都是使用hash
方式获取锚点#
后面的URL
片断。
这种方式是经过监听'hashchange'
事件,而后触发事件,用location.hash.replace
方法来改变路由。
这种方式是最为推荐的HTML5
方式。使用history
的pushState
方法修改history
里的记录,而后也能够经过监听popstate
来触发一些相关的事件。
这是一个很是巧妙可是从某种程度上很是“丑陋”的方法。丑陋是在它比较吃性能,一方面它有不少dom
的操做来设置iframe
,最重要的方面是它还用了定时器每隔一小段时间就检测,而后就触发函数,判断是否改变等等。插入一个空的iframe
(通过属性设置)的做用在这里是存储hash
的值和存储hash
改变记录。在这里我遇到了一个问题:存储hash
的值彻底能够经过一个全局变量来完成,为何要大费周折建立一个iframe
呢?下面是我的的一些猜想:
Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
这是源码中的一句注释。用iframe
的理由多是为了经过开关iframe
来存储记录。说实话具体是什么原理还不清楚,若是有人了解的话欢迎指教~
// 开关`iframe` iWindow.document.open(); iWindow.document.close();
start
主要作以下操做:
进入start
函数以后会把started
设置为true
防止重复出发。
设置各类参数,用于后期判断使用哪种路由控制方式。
若是有hashchange
事件,但没有pushState
方法,就用location.replace
方法来改变路由。若是二者都有就调用navigate
函数,里面能够经过pushState
改变并记录路由。若是二者都没有就设置iframe
并启动,经过设置iframe
的hash
参数来改变路由。
绑定事件,用hashChange
方法的绑定hashchange
事件,用pushState
方法的绑定popstate
事件,用iframe
的使用setInterval
来监听。
进入函数以后首先是进行“组合”,“组合”出url
。这个过程须要有root
和fragment
,后者须要调用getFragment
函数,前者须要根据是path
仍是hash
来对root
进行处理。若是是hash
就不须要加/
,若是是path
就要加/
。解码后判断当前的this.fragment
和有没有发生变化,没有无论,有就更新。
根据浏览器使用不一样的方法。注意这里使用的判断的依据是在start
函数里面就定义好的。
若是有pushState
或者replaceState
就用;
若是有hashchange
就仅仅只调用_upadateHash
,传入当前的location
bom
对象,里面用了location.replace
,更新当前的href
或者hash
;
若是没有hashchange
就须要把当前location
和iframe.location
对象分别传入_updateHash
,而后更新当前href
或者hash
。
还有一个须要注意的是是否replace
,这是一个传入参数,判断时候要影响history
。
关于路由触发事件是经过两个函数来完成的,它们分别是checkUrl
和loadUrl
, 前者会检测路由是否发生了改变,若是改变了就会触发navigate
函数并调用loadUrl
函数,然后者会经过路由片断来找到handlers
相关的事件函数来触发。这就实现了用户在routes
对象里面设置的事件了。
最后来个简单的Sync
的讲解吧~有关ajax
的部分在backbone
中实际上是经过Backbone.ajax
函数来代理jquery
或者其余能够发起ajax
的库的。而Sync
函数事实上主要的工做就是部署ajax
参数,最后调用这个Backbone.ajax
发起请求。经过源码能够看到,其中为params
设置了type
, dataType
, url
, contentType
, data
, (processData
)属性来做为发起ajax
的参数。其中也为options
设置了beforeSend
, error
方法做为ajax
的回调(success
函数写在其余模块中,详情能够看我以前的几篇文章)。
其中还须要主要的有两个参数emulateJSON
& emulateHTTP
。在文档中的介绍很是详细,我的以为在大部分时候都不会用到。
终于把最后的第三篇文章写出来了...花了很长时间...仍是以为若是要真正彻底读懂backbone
源码要多读代码(惭愧,自认为还没彻底达到),多查资料,多读一些源码解析。有关于router
和history
我以为这篇文章仍是很棒的。这一个部分我的感受确实不是很好懂,可是能够学习到不少有关路由的处理的相关知识,实际上是很是有益的~
backbone
被称为框架的框架。这个框架的思想比起使用更有意义,毕竟如今有更多功能强大的框架。新东西要学,可是经典也是不该该被落下的。
若是这篇文章有什么错误的地方请轻喷~互相学习!谢谢你们。
下面是所有的文章:
基于 Backbone + node 的我的简历生成器(我的学习总结)
Backbone源码解读(一)
Backbone源码解读(二)
Backbone源码解读(三)