Backbone.js路由配置 #

一、路由规则 #

1.1 routes对象 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        '': 'home',
        'about': 'about',
        'users': 'users',
        'users/:id': 'userDetail'
    }
});

1.2 动态添加路由 #

javascript
var router = new Backbone.Router();

router.route('posts/:id', 'showPost', function(id) {
    console.log('文章ID:', id);
});

router.route('categories/:category/posts/:id', 'showCategoryPost', function(category, id) {
    console.log('分类:', category, '文章ID:', id);
});

1.3 函数形式的routes #

javascript
var AppRouter = Backbone.Router.extend({
    routes: function() {
        var routes = {
            '': 'home',
            'about': 'about'
        };
        
        if (this.options.enableAdmin) {
            routes['admin'] = 'admin';
            routes['admin/users'] = 'adminUsers';
        }
        
        return routes;
    }
});

二、参数类型 #

2.1 基本参数 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'users/:id': 'showUser'
    },
    
    showUser: function(id) {
        console.log('用户ID:', id);
    }
});

2.2 多个参数 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'posts/:year/:month/:day': 'showPost'
    },
    
    showPost: function(year, month, day) {
        console.log('日期:', year, month, day);
    }
});

2.3 通配符参数 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'files/*path': 'showFile',
        'search/*query': 'search'
    },
    
    showFile: function(path) {
        console.log('文件路径:', path);
    },
    
    search: function(query) {
        console.log('搜索词:', query);
    }
});

2.4 可选参数 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'products(/:category)(/sort/:sort)': 'products',
        'users(/page/:page)': 'users'
    },
    
    products: function(category, sort) {
        category = category || 'all';
        sort = sort || 'default';
        console.log('分类:', category, '排序:', sort);
    },
    
    users: function(page) {
        page = page || 1;
        console.log('页码:', page);
    }
});

2.5 参数约束 #

javascript
var AppRouter = Backbone.Router.extend({
    initialize: function() {
        this.route(/^users\/(\d+)$/, 'showUser');
        this.route(/^posts\/([a-z0-9-]+)$/, 'showPost');
    },
    
    showUser: function(id) {
        console.log('用户ID:', parseInt(id, 10));
    },
    
    showPost: function(slug) {
        console.log('文章别名:', slug);
    }
});

三、复杂路由 #

3.1 嵌套路由 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'admin': 'adminIndex',
        'admin/users': 'adminUsers',
        'admin/users/:id': 'adminUserDetail',
        'admin/users/:id/edit': 'adminUserEdit',
        'admin/posts': 'adminPosts',
        'admin/posts/:id': 'adminPostDetail'
    }
});

3.2 查询参数 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        'search': 'search',
        'products': 'products'
    },
    
    search: function() {
        var query = this.getQueryParams();
        console.log('搜索参数:', query);
    },
    
    products: function() {
        var params = this.getQueryParams();
        console.log('产品参数:', params);
    },
    
    getQueryParams: function() {
        var fragment = Backbone.history.getFragment();
        var queryString = fragment.split('?')[1];
        
        if (!queryString) return {};
        
        var params = {};
        queryString.split('&').forEach(function(pair) {
            var parts = pair.split('=');
            params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1] || '');
        });
        
        return params;
    }
});

3.3 带查询参数的导航 #

javascript
router.navigate('search?q=keyword&page=1', { trigger: true });

router.navigate('products?category=electronics&sort=price', { trigger: true });

四、路由组织 #

4.1 模块化路由 #

javascript
var UserRoutes = {
    routes: {
        'users': 'listUsers',
        'users/:id': 'showUser',
        'users/:id/edit': 'editUser'
    },
    
    listUsers: function() {
        console.log('用户列表');
    },
    
    showUser: function(id) {
        console.log('用户详情:', id);
    },
    
    editUser: function(id) {
        console.log('编辑用户:', id);
    }
};

var PostRoutes = {
    routes: {
        'posts': 'listPosts',
        'posts/:id': 'showPost'
    },
    
    listPosts: function() {
        console.log('文章列表');
    },
    
    showPost: function(id) {
        console.log('文章详情:', id);
    }
};

var AppRouter = Backbone.Router.extend({
    routes: {}
});

_.extend(AppRouter.prototype, UserRoutes, PostRoutes);

4.2 路由配置对象 #

javascript
var routeConfig = {
    home: {
        path: '',
        action: 'home',
        title: '首页'
    },
    users: {
        path: 'users',
        action: 'listUsers',
        title: '用户列表'
    },
    userDetail: {
        path: 'users/:id',
        action: 'showUser',
        title: '用户详情'
    }
};

var AppRouter = Backbone.Router.extend({
    initialize: function() {
        var self = this;
        
        _.each(routeConfig, function(config, name) {
            self.route(config.path, name, function() {
                document.title = config.title;
                self[config.action].apply(self, arguments);
            });
        });
    },
    
    home: function() {
        console.log('首页');
    },
    
    listUsers: function() {
        console.log('用户列表');
    },
    
    showUser: function(id) {
        console.log('用户详情:', id);
    }
});

4.3 路由分组 #

javascript
var RouterGroup = function(prefix, routes) {
    this.prefix = prefix;
    this.routes = routes;
};

RouterGroup.prototype.register = function(router) {
    var self = this;
    
    _.each(this.routes, function(handler, path) {
        var fullPath = self.prefix + (path ? '/' + path : '');
        router.route(fullPath, handler);
    });
};

var userRoutes = new RouterGroup('users', {
    '': 'listUsers',
    ':id': 'showUser',
    ':id/edit': 'editUser'
});

var postRoutes = new RouterGroup('posts', {
    '': 'listPosts',
    ':id': 'showPost'
});

var AppRouter = Backbone.Router.extend({
    initialize: function() {
        userRoutes.register(this);
        postRoutes.register(this);
    },
    
    listUsers: function() {},
    showUser: function(id) {},
    editUser: function(id) {},
    listPosts: function() {},
    showPost: function(id) {}
});

五、路由守卫 #

5.1 认证守卫 #

javascript
var AuthRouter = Backbone.Router.extend({
    routes: {
        'login': 'login',
        'dashboard': 'dashboard',
        'profile': 'profile'
    },
    
    execute: function(callback, args, name) {
        var publicRoutes = ['login'];
        
        if (publicRoutes.indexOf(name) === -1 && !this.isAuthenticated()) {
            this.navigate('login', { trigger: true });
            return false;
        }
        
        if (callback) callback.apply(this, args);
    },
    
    isAuthenticated: function() {
        return !!localStorage.getItem('token');
    },
    
    login: function() {
        console.log('登录页面');
    },
    
    dashboard: function() {
        console.log('仪表盘');
    },
    
    profile: function() {
        console.log('个人资料');
    }
});

5.2 权限守卫 #

javascript
var PermissionRouter = Backbone.Router.extend({
    permissions: {
        admin: ['admin', 'adminUsers', 'adminSettings'],
        manager: ['dashboard', 'reports'],
        user: ['profile', 'settings']
    },
    
    execute: function(callback, args, name) {
        var userRole = this.getUserRole();
        
        if (!this.hasPermission(name, userRole)) {
            this.navigate('forbidden', { trigger: true });
            return false;
        }
        
        if (callback) callback.apply(this, args);
    },
    
    getUserRole: function() {
        return localStorage.getItem('role') || 'user';
    },
    
    hasPermission: function(route, role) {
        var allowedRoutes = this.permissions[role] || [];
        return allowedRoutes.indexOf(route) !== -1;
    }
});

5.3 确认守卫 #

javascript
var ConfirmRouter = Backbone.Router.extend({
    initialize: function() {
        this.pendingNavigation = null;
    },
    
    execute: function(callback, args, name) {
        if (this.hasUnsavedChanges()) {
            this.pendingNavigation = { callback: callback, args: args, name: name };
            this.showConfirmDialog();
            return false;
        }
        
        if (callback) callback.apply(this, args);
    },
    
    hasUnsavedChanges: function() {
        return this.currentView && this.currentView.hasChanges;
    },
    
    showConfirmDialog: function() {
        if (confirm('有未保存的更改,确定要离开吗?')) {
            this.proceedWithNavigation();
        } else {
            this.pendingNavigation = null;
        }
    },
    
    proceedWithNavigation: function() {
        if (this.pendingNavigation) {
            var nav = this.pendingNavigation;
            this.pendingNavigation = null;
            if (nav.callback) nav.callback.apply(this, nav.args);
        }
    }
});

六、实用示例 #

6.1 完整应用路由 #

javascript
var AppRouter = Backbone.Router.extend({
    routes: {
        '': 'home',
        'login': 'login',
        'register': 'register',
        'dashboard': 'dashboard',
        'users': 'users',
        'users/:id': 'userDetail',
        'users/:id/edit': 'userEdit',
        'posts': 'posts',
        'posts/:id': 'postDetail',
        'posts/new': 'postNew',
        'settings': 'settings',
        '*notFound': 'notFound'
    },
    
    initialize: function(options) {
        this.app = options.app;
        this.currentView = null;
    },
    
    showView: function(view) {
        if (this.currentView) {
            this.currentView.remove();
        }
        this.currentView = view;
        this.app.$main.html(view.render().el);
    },
    
    home: function() {
        this.showView(new HomeView());
    },
    
    login: function() {
        this.showView(new LoginView());
    },
    
    register: function() {
        this.showView(new RegisterView());
    },
    
    dashboard: function() {
        this.showView(new DashboardView());
    },
    
    users: function() {
        var collection = new Users();
        collection.fetch().then(function() {
            this.showView(new UsersView({ collection: collection }));
        }.bind(this));
    },
    
    userDetail: function(id) {
        var model = new User({ id: id });
        model.fetch().then(function() {
            this.showView(new UserDetailView({ model: model }));
        }.bind(this));
    },
    
    userEdit: function(id) {
        var model = new User({ id: id });
        model.fetch().then(function() {
            this.showView(new UserEditView({ model: model }));
        }.bind(this));
    },
    
    posts: function() {
        var collection = new Posts();
        collection.fetch().then(function() {
            this.showView(new PostsView({ collection: collection }));
        }.bind(this));
    },
    
    postDetail: function(id) {
        var model = new Post({ id: id });
        model.fetch().then(function() {
            this.showView(new PostDetailView({ model: model }));
        }.bind(this));
    },
    
    postNew: function() {
        this.showView(new PostNewView());
    },
    
    settings: function() {
        this.showView(new SettingsView());
    },
    
    notFound: function() {
        this.showView(new NotFoundView());
    }
});

七、总结 #

7.1 路由配置要点 #

要点 说明
routes对象 定义路由规则
route方法 动态添加路由
参数提取 :param, *splat
可选参数 (/optional)

7.2 最佳实践 #

  1. 使用语义化的路由路径
  2. 合理组织路由规则
  3. 使用路由守卫控制访问
  4. 处理404页面
  5. 模块化组织路由
最后更新:2026-03-28