问题
I want to highlight the current navigation state. Like if the hashchange is #home
, I want to style the 'Home' menu link differently and similarly other links.
Backbone.js fires individual events like route:home
,... route:some-other
when the #home
and other links are clicked. I could not see any common event that will be fired for every hashchange. With this I m required to write the state highlight logic by binding to all the route events, which I think is not good solution.
So, I've overridden Backbone.Router.route
in my router sub class/object, like
// override backbone' Router.route method to publish
// common 'route_change' event for any hash change
route : function(route, name, callback) {
Backbone.history || (Backbone.history = new Backbone.History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
Backbone.history.route(route, _.bind(function(fragment) {
var args = this._extractParameters(route, fragment);
callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
// ADDED BY: ManiKanta G
// name: route method
// fragment: route path
// args: any additional args
this.trigger.apply(this, ['route_change'].concat(name, fragment, args));
}, this));
}
This will publish a common route_change
event for every hashchange and passing the name
, fragment
, and other args
using which I m highlighting the state all in a single place.
My question is do I have to override the Backbone method like this or is there any build in mechanism I can use here. If not, I would like to see similar behaviour in Backbone.js
Edit: sample program
Router = Backbone.Router.extend({
routes : {
'': 'root',
'home': 'home',
'about':'about'
},
// app routing methods
root: function () { console.log('root route'); },
home: function () { console.log('home route'); },
about: function () { console.log('about route'); }
});
Router.bind('all', function () {
console.log('all route...');
});
router = new Router();
and, navigating using the above router:
router.navigate('home', true);
output: home route
Update on why the above program is not working:
we should bind for all
event on Router instance
, but not on the Router
itself - so, changing the Router.bind('all', ...
to router.bind('all', ...)
will make the above program work
回答1:
In backbone 0.5.x you can bind all
event to router instance and the first argument pass to your handler will be route
Here is exemple on jsfiddle, reproduced here:
var dummy = Backbone.Router.extend({
defaultPage: 'messages',
routes: {
'': 'index',
'index': 'index',
'mailbox': 'mailbox'
},
index: function() {
// code here
},
mailbox: function() {
// code here
}
});
var router = new dummy();
router.bind('all', function(route) {
document.write('triggered: ' + route + '<br/>');
});
router.navigate('index', true);
router.navigate('mailbox', true);
回答2:
Here 's a live example from one of my apps:
routes.bind('all ', function(route, section) {
var $el;
route = route.replace('route: ', '');
$el = $('#nav - ' + route);
// If current route is highlighted, we're done.
if ($el.hasClass('selected')) {
return;
} else {
// Unhighlight active tab.
$('#menu li.selected').removeClass('selected');
// Highlight active page tab.
$el.addClass('selected');
}
});
回答3:
Here's what I'm doing:
@router.bind 'all', (route) ->
# this triggers twice for every route; ignore the second time
return if route == "route"
# ex: route="route:home", name="home", href="#home"
name = route.replace('route:', '')
# remove the active class on all of the current nav links
$("#menu li.active").removeClass('active')
# add it back to the link that has an href that ends in `name`
$("#menu a[href$='#{name}']").parent().addClass('active')
回答4:
I faced the problem that the first time a page is loaded, the menu wasn't highlighted as the event came before the binding was initiated. i fixed this by using the history:
$('#menu li.'+Backbone.history.fragment).addClass('active');
来源:https://stackoverflow.com/questions/7144365/highlighting-current-navigation-state-in-backbone-js-application