Router 為客戶端路由提供了許多方法,並能連接到指定的動作(actions)和事件(events)。 對於不支持 History API 的舊瀏覽器,路由提供了優雅的回調函數並可以透明的進行 URL 片段的轉換。
頁面加載期間,當應用已經創建了所有的路由,需要調用 Backbone.history.start(),或 Backbone.history.start({pushState : true}) 來確保驅動初始化 URL 的路由。
關於history詳解,可見backbone 學習之history
源碼:
// Backbone.Router // --------------- // Routers map faux-URLs to actions, and fire events when routes are // matched. Creating a new one sets its `routes` hash, if not set statically. var Router = Backbone.Router = function(options) { options || (options = {}); if (options.routes) this.routes = options.routes;// 鍵值對式的導航規則 映射到處理函數上 this._bindRoutes(); this.initialize.apply(this, arguments); }; // Cached regular expressions for matching named param parts and splatted // parts of route strings. var optionalParam = /\((.*?)\)/g; var namedParam = /(\(\?)?:\w+/g; var splatParam = /\*\w+/g; var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; // Set up all inheritable **Backbone.Router** properties and methods. _.extend(Router.prototype, Events, { // Initialize is an empty function by default. Override it with your own // initialization logic. initialize: function(){}, // Manually bind a single named route to a callback. For example: // // this.route('search/:query/p:num', 'search', function(query, num) { // ... // }); // 導航 指定路由規則 和routes的效果相同 規則也一樣 route: function(route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); // 規則驗證 if (_.isFunction(name)) { callback = name; name = ''; } if (!callback) callback = this[name]; var router = this; Backbone.history.route(route, function(fragment) { var args = router._extractParameters(route, fragment); callback && callback.apply(router, args); router.trigger.apply(router, ['route:' + name].concat(args)); // 觸發router的route事件 router.trigger('route', name, args); // 觸發history的route事件 Backbone.history.trigger('route', router, name, args); }); return this; }, // Simple proxy to `Backbone.history` to save a fragment into the history. navigate: function(fragment, options) { Backbone.history.navigate(fragment, options); return this; }, // Bind all defined routes to `Backbone.history`. We have to reverse the // order of the routes here to support behavior where the most general // routes can be defined at the bottom of the route map. // 綁定所有的routes _bindRoutes: function() { if (!this.routes) return; this.routes = _.result(this, 'routes'); var route, routes = _.keys(this.routes); while ((route = routes.pop()) != null) { this.route(route, this.routes[route]); } }, // Convert a route string into a regular expression, suitable for matching // against the current location hash. // 將route字符串轉成正則表達式 _routeToRegExp: function(route) { route = route.replace(escapeRegExp, '\\$&') // 將 - { } [ ] + ? . , \ ^ $ # 空格 等進行轉義 .replace(optionalParam, '(?:$1)?') // 規則中的括號部分 也就是可有可沒有的部分 .replace(namedParam, function(match, optional){ // 將不帶括號部分的 但是:...形式的進行替換可以匹配為非/以外任意字符 return optional ? match : '([^\/]+)'; })// .replace(splatParam, '(.*?)');// 將*...形式的替換為除換行以外的任何字符匹配.* return new RegExp('^' + route + '$'); // 構建正則 加上 開始^和結束$ }, // Given a route, and a URL fragment that it matches, return the array of // extracted decoded parameters. Empty or unmatched parameters will be // treated as `null` to normalize cross-browser behavior. // 返回decode后的一些URL信息(通過和route匹配的fragment做處理) _extractParameters: function(route, fragment) { var params = route.exec(fragment).slice(1); return _.map(params, function(param) { return param ? decodeURIComponent(param) : null; }); } });
歡迎指導、糾錯、建議。