Marionette.AppRouter
扩展了标准Backbone.Router
,它们都没有提供拦截机制,允许您阻止执行路由回调。需要相同的功能,我想出了以下代码(_
是Lodash)。在原始Backbone.Router.prototype.route()
中,将创建将在路线匹配上执行的功能。以下代码为原始Backbone.Router.prototype.route()
提供了一个包装器,以便用执行一系列中间件功能的函数替换已注册的路由回调。这些中间件中的每一个都可以在执行原始路由回调之前或之后执行任何附加处理,包括阻止执行进一步回调并引发异常。
Backbone.RouteMiddlewares.use(function (route, name, fragment, args, next) {
if (App.routeRequiresAuthentication(name) && !App.isUserAuthenticated()) {
Backbone.history.navigate('login', {trigger: true});
}
else {
next();
}
});
注:
Backbone.RouteMiddlewares = (function() {
var Backbone = require('backbone')
, _ = require('lodash');
/**
* A wrapper for `Backbone.Router.prototype.route()` that will use route middlewares (in addition to its
* normal callback).
*
* @param {Function} fn - The wrapped function (should be compatible with `Backbone.Router.prototype.route()`).
* @param {string|RegExp} route - A route pattern or regexp.
* @param {string} name - The name of the route.
* @param {Function} callback - The route callback.
* @returns {Backbone.Router}
*/
function RouteMiddleware(fn, route, name, callback) {
// Prepare arguments as the original Backbone.Router.prototype.route() would.
if (!_.isRegExp(route)) route = Backbone.Router.prototype._routeToRegExp.apply(this, [route]);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
// Execute the wrapper `route` method, with the callback as final middleware.
return fn.apply(this, [route, name, function() {
executeMiddlewares.apply(this, [route, name, Backbone.history.getFragment(), Array.prototype.slice.apply(arguments, [0]), callback]);
}]);
};
/**
* Add a route middelware.
*
* @param {RouteMiddleware} fn
*/
RouteMiddleware.use = function use(fn) {
middlewares.push.apply(middlewares, _.filter(arguments, _.isFunction));
};
/**
* @callback RouteMiddleware
* @param {RegExp} route - The matched route regexp.
* @param {string} name - The matched route.
* @param {string} fragment - The matched URL fragment.
* @param {Array} args - The route arguments (extracted from `fragment`).
* @param {Function} next - The function to call to execute the next middleware in the chain.
*/
/**
* @type {RouteMiddleware[]}
*/
var middlewares = [];
/**
* Execute the route middlware, ending with the provided callback.
*
* @param {RegExp} route - The matched route regexp.
* @param {string} name - The matched route.
* @param {string} fragment - The matched URL fragment.
* @param {Array} args - The route arguments (extracted from `fragment`).
* @param {Function} callback - The route handler to execute as final middleware.
*/
function executeMiddlewares(route, name, fragment, args, callback) {
var index = 0;
var h = middlewares.concat(function (route, name, fragment, args, next) {
callback.apply(this, args);
});
function next(err) {
if (err) throw err;
h[index++].apply(this, [route, name, fragment, args, next.bind(this)]);
}
next.apply(this);
}
})();
Backbone.Router.prototype.route = _.wrap(Backbone.Router.prototype.route, Backbone.RouteMiddlewares);
使用该拦截器/中间件机制,用户在登录页面的重定向可以用下面的实现如果能够通过中间件路线回调后执行代码与路由器上的route
事件以及Backbone.history
都是多余的,但它随中间件模式一起提供。
事实上,我最终通过在jquery的ajax调用中设置默认行为来使用类似于您的解决方案,我对此感到非常满意。你能举一个你想要获得什么的例子吗? – Ingro