我在AngularJS中设置的路径如下:
$routeProvider
.when('/dashboard', {templateUrl:'partials/dashboard', controller:widgetsController})
.when('/lab', {templateUrl:'partials/lab', controller:widgetsController})
我在顶部栏上有一些链接,用作标签。如何根据当前模板或网址将“有效”类添加到选项卡?
答案 0 :(得分:274)
在不必依赖URL的情况下解决此问题的方法是在$routeProvider
配置期间为每个部分添加自定义属性,如下所示:
$routeProvider.
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: widgetsController,
activetab: 'dashboard'
}).
when('/lab', {
templateUrl: 'partials/lab.html',
controller: widgetsController,
activetab: 'lab'
});
在您的控制器中公开$route
:
function widgetsController($scope, $route) {
$scope.$route = $route;
}
根据当前活动标签设置active
类:
<li ng-class="{active: $route.current.activetab == 'dashboard'}"></li>
<li ng-class="{active: $route.current.activetab == 'lab'}"></li>
答案 1 :(得分:133)
这样做的一种方法是使用ngClass指令和$ location服务。在您的模板中,您可以这样做:
ng-class="{active:isActive('/dashboard')}"
其中isActive
将是如下定义的范围中的函数:
myApp.controller('MyCtrl', function($scope, $location) {
$scope.isActive = function(route) {
return route === $location.path();
}
});
以下是完整的jsFiddle:http://jsfiddle.net/pkozlowski_opensource/KzAfG/
在每个导航选项卡上重复ng-class="{active:isActive('/dashboard')}"
可能很繁琐(如果你有很多标签),所以这个逻辑可能是一个非常简单的指令的候选者。
答案 2 :(得分:41)
遵循Pavel的建议使用自定义指令,这里的版本需要不向routeConfig添加有效负载,是超级声明的,并且可以通过简单地更改slice()
来适应路径的任何级别。你正在关注它。
app.directive('detectActiveTab', function ($location) {
return {
link: function postLink(scope, element, attrs) {
scope.$on("$routeChangeSuccess", function (event, current, previous) {
/*
Designed for full re-usability at any path, any level, by using
data from attrs. Declare like this:
<li class="nav_tab">
<a href="#/home" detect-active-tab="1">HOME</a>
</li>
*/
// This var grabs the tab-level off the attribute, or defaults to 1
var pathLevel = attrs.detectActiveTab || 1,
// This var finds what the path is at the level specified
pathToCheck = $location.path().split('/')[pathLevel] ||
"current $location.path doesn't reach this level",
// This var finds grabs the same level of the href attribute
tabLink = attrs.href.split('/')[pathLevel] ||
"href doesn't include this level";
// Above, we use the logical 'or' operator to provide a default value
// in cases where 'undefined' would otherwise be returned.
// This prevents cases where undefined===undefined,
// possibly causing multiple tabs to be 'active'.
// now compare the two:
if (pathToCheck === tabLink) {
element.addClass("active");
}
else {
element.removeClass("active");
}
});
}
};
});
我们通过倾听$routeChangeSuccess
事件来实现我们的目标,而不是在路径上放置$watch
。我认为这意味着逻辑应该不那么频繁地运行,因为我认为手表会在每个$digest
周期中发出警报。
通过在指令声明上传递路径级参数来调用它。这指定了您希望与href
属性匹配的当前$ location.path()的块。
<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>
因此,如果您的选项卡应对路径的基本级做出反应,请将参数设为“1”。因此,当location.path()为“/ home”时,它将匹配href
中的“#/ home”。如果您的选项卡应对路径的第二级,第三级或第11级作出反应,请相应地进行调整。从1或更大的切片将绕过href中的邪恶'#',它将生活在索引0处。
唯一的要求是你在<a>
上调用,因为元素假设存在href
属性,它将与当前路径进行比较。但是,如果您希望在<li>
或其他内容上调用,则可以非常轻松地调整父/子元素的读/写。我挖掘它是因为您可以通过简单地改变pathLevel参数在许多上下文中重复使用它。如果在逻辑中假定要读取的深度,则需要多个版本的指令才能与导航的多个部分一起使用。
编辑3/18/14:解决方案没有充分概括,并且如果您为'undefined
和$location.path()
返回href
的'activeTab'值定义了一个arg,则会激活该元素的{ {1}}。因为:undefined === undefined
。更新以修复该情况。
在研究这个时,我意识到应该有一个版本,您可以在父元素上声明,其模板结构如下:
<nav id="header_tabs" find-active-tab="1">
<a href="#/home" class="nav_tab">HOME</a>
<a href="#/finance" class="nav_tab">Finance</a>
<a href="#/hr" class="nav_tab">Human Resources</a>
<a href="#/quarterly" class="nav_tab">Quarterly</a>
</nav>
请注意,此版本不再远程类似于Bootstrap样式的HTML。但是,它更现代,使用更少的元素,所以我偏爱它。此版本的指令加上原始版本现在是available on Github作为插入模块,您可以将其声明为依赖项。如果有人真正使用它们,我会很高兴Bower-ize。
另外,如果你想要一个包含<li>
的兼容引导程序的版本,你可以使用angular-ui-bootstrap Tabs module,我想这是在原帖后发布的,可能更多陈述比这个。它不是简洁的基本内容,但为您提供了一些额外的选项,如禁用选项卡和激活和停用时触发的声明性事件。
答案 3 :(得分:27)
@ rob-juurlink我对你的解决方案有所改进:
而不是每个需要活动标签的路线;并且需要在每个控制器中设置活动选项卡,我这样做:
var App = angular.module('App',[]);
App.config(['$routeProvider', function($routeProvider){
$routeProvider.
when('/dashboard', {
templateUrl: 'partials/dashboard.html',
controller: Ctrl1
}).
when('/lab', {
templateUrl: 'partials/lab.html',
controller: Ctrl2
});
}]).run(['$rootScope', '$location', function($rootScope, $location){
var path = function() { return $location.path();};
$rootScope.$watch(path, function(newVal, oldVal){
$rootScope.activetab = newVal;
});
}]);
HTML看起来像这样。 activetab只是与该路由相关的URL。这只是消除了在每个控制器中添加代码的需要(拖动依赖关系,如$ route和$ rootScope,如果这是他们被使用的唯一原因)
<ul>
<li ng-class="{active: activetab=='/dashboard'}">
<a href="#/dashboard">dashboard</a>
</li>
<li ng-class="{active: activetab=='/lab'}">
<a href="#/lab">lab</a>
</li>
</ul>
答案 4 :(得分:16)
也许像这样的指令可以解决你的问题: http://jsfiddle.net/p3ZMR/4/
HTML
<div ng-app="link">
<a href="#/one" active-link="active">One</a>
<a href="#/two" active-link="active">One</a>
<a href="#" active-link="active">home</a>
</div>
JS
angular.module('link', []).
directive('activeLink', ['$location', function(location) {
return {
restrict: 'A',
link: function(scope, element, attrs, controller) {
var clazz = attrs.activeLink;
var path = attrs.href;
path = path.substring(1); //hack because path does bot return including hashbang
scope.location = location;
scope.$watch('location.path()', function(newPath) {
if (path === newPath) {
element.addClass(clazz);
} else {
element.removeClass(clazz);
}
});
}
};
}]);
答案 5 :(得分:14)
这里最简单的解决方案:
How to set bootstrap navbar active class with Angular JS?
这是:
使用ng-controller在ng-view之外运行单个控制器:
<div class="collapse navbar-collapse" ng-controller="HeaderController">
<ul class="nav navbar-nav">
<li ng-class="{ active: isActive('/')}"><a href="/">Home</a></li>
<li ng-class="{ active: isActive('/dogs')}"><a href="/dogs">Dogs</a></li>
<li ng-class="{ active: isActive('/cats')}"><a href="/cats">Cats</a></li>
</ul>
</div>
<div ng-view></div>
并包含在controllers.js中:
function HeaderController($scope, $location)
{
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
}
答案 6 :(得分:12)
我建议使用state.ui module,它不仅支持多个和嵌套视图,而且使这种工作变得非常简单(下面引用的代码):
<ul class="nav">
<li ng-class="{ active: $state.includes('contacts') }"><a href="#{{$state.href('contacts')}}">Contacts</a></li>
<li ng-class="{ active: $state.includes('about') }"><a href="#{{$state.href('about')}}">About</a></li>
</ul>
值得一读。
答案 7 :(得分:4)
这是另一个版本的XMLillies w / domi的LI更改,它使用搜索字符串而不是路径级别。我认为这对我的用例来说更加明显。
statsApp.directive('activeTab', function ($location) {
return {
link: function postLink(scope, element, attrs) {
scope.$on("$routeChangeSuccess", function (event, current, previous) {
if (attrs.href!=undefined) { // this directive is called twice for some reason
// The activeTab attribute should contain a path search string to match on.
// I.e. <li><a href="#/nested/section1/partial" activeTab="/section1">First Partial</a></li>
if ($location.path().indexOf(attrs.activeTab) >= 0) {
element.parent().addClass("active");//parent to get the <li>
} else {
element.parent().removeClass("active");
}
}
});
}
};
});
HTML现在看起来像:
<ul class="nav nav-tabs">
<li><a href="#/news" active-tab="/news">News</a></li>
<li><a href="#/some/nested/photos/rawr" active-tab="/photos">Photos</a></li>
<li><a href="#/contact" active-tab="/contact">Contact</a></li>
</ul>
答案 8 :(得分:3)
我发现XMLilley是最好的,最具适应性和非侵入性的。
但是我有一个小故障。
与bootstrap nav一起使用,以下是我修改它的方法:
app.directive('activeTab', function ($location) {
return {
link: function postLink(scope, element, attrs) {
scope.$on("$routeChangeSuccess", function (event, current, previous) {
/* designed for full re-usability at any path, any level, by using
data from attrs
declare like this: <li class="nav_tab"><a href="#/home"
active-tab="1">HOME</a></li>
*/
if(attrs.href!=undefined){// this directive is called twice for some reason
// this var grabs the tab-level off the attribute, or defaults to 1
var pathLevel = attrs.activeTab || 1,
// this var finds what the path is at the level specified
pathToCheck = $location.path().split('/')[pathLevel],
// this var finds grabs the same level of the href attribute
tabLink = attrs.href.split('/')[pathLevel];
// now compare the two:
if (pathToCheck === tabLink) {
element.parent().addClass("active");//parent to get the <li>
}
else {
element.parent().removeClass("active");
}
}
});
}
};
});
我添加了“if(attrs.href!= undefined)”,因为此函数显然被调用两次,第二次产生错误。
至于html:
<ul class="nav nav-tabs">
<li class="active" active-tab="1"><a href="#/accueil" active-tab="1">Accueil</a></li>
<li><a active-tab="1" href="#/news">News</a></li>
<li><a active-tab="1" href="#/photos" >Photos</a></li>
<li><a active-tab="1" href="#/contact">Contact</a></li>
</ul>
答案 9 :(得分:3)
Bootstrap示例。
如果您使用内置路由(Angview)的Angulars,可以使用此指令:
angular.module('myApp').directive('classOnActiveLink', [function() {
return {
link: function(scope, element, attrs) {
var anchorLink = element.children()[0].getAttribute('ng-href') || element.children()[0].getAttribute('href');
anchorLink = anchorLink.replace(/^#/, '');
scope.$on("$routeChangeSuccess", function (event, current) {
if (current.$$route.originalPath == anchorLink) {
element.addClass(attrs.classOnActiveLink);
}
else {
element.removeClass(attrs.classOnActiveLink);
}
});
}
};
}]);
假设您的标记看起来像这样:
<ul class="nav navbar-nav">
<li class-on-active-link="active"><a href="/orders">Orders</a></li>
<li class-on-active-link="active"><a href="/distributors">Distributors</a></li>
</ul>
我喜欢这样做,因为您可以在属性中设置所需的类名。
答案 10 :(得分:2)
您也可以简单地inject the location into the scope并使用它来扣除导航的样式:
function IndexController( $scope, $rootScope, $location ) {
$rootScope.location = $location;
...
}
然后在ng-class
:
<li ng-class="{active: location.path() == '/search'}">
<a href="/search">Search><a/>
</li>
答案 11 :(得分:2)
另一种方法是使用ui-sref-active
与ui-sref一起使用的指令,用于在相关的ui-sref指令状态处于活动状态时向元素添加类,并在其处于非活动状态时将其删除。主要用例是通过使用&#34; active&#34;来简化依赖于ui-sref的导航菜单的特殊外观。州的菜单按钮显示不同,区别于非活动菜单项。
用法:
ui-sref-active =&#39; class1 class2 class3&#39; - 课程&#34; class1&#34;,&#34; class2&#34;和&#34; class3&#34;当相关的ui-sref状态处于活动状态时,每个状态都被添加到指令元素,并且当它处于非活动状态时被删除。
示例:强>
给出以下模板,
<ul>
<li ui-sref-active="active" class="item">
<a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
</li>
<!-- ... -->
</ul>
当app状态为&#34; app.user&#34;时,包含状态参数&#34; user&#34;有价值&#34; bilbobaggins&#34;,生成的HTML将显示为
<ul>
<li ui-sref-active="active" class="item active">
<a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
</li>
<!-- ... -->
</ul>
在指令链接时间内对类名进行插值一次(忽略对插值的任何进一步更改)。可以用空格分隔格式指定多个类。
使用ui-sref-opts指令将选项传递给$ state.go()。例如:
<a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
答案 12 :(得分:1)
我同意Rob关于在控制器中拥有自定义属性的帖子。显然我没有足够的代表发表评论。这是请求的jsfiddle:
示例html
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="link in links" ng-class="{active: $route.current.activeNav == link.type}"> <a href="{{link.uri}}">{{link.name}}</a>
</li>
</ul>
</div>
示例app.js
angular.module('MyApp', []).config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/a', {
activeNav: 'a'
})
.when('/a/:id', {
activeNav: 'a'
})
.when('/b', {
activeNav: 'b'
})
.when('/c', {
activeNav: 'c'
});
}])
.controller('MyCtrl', function ($scope, $route) {
$scope.$route = $route;
$scope.links = [{
uri: '#/a',
name: 'A',
type: 'a'
}, {
uri: '#/b',
name: 'B',
type: 'b'
}, {
uri: '#/c',
name: 'C',
type: 'c'
}, {
uri: '#/a/detail',
name: 'A Detail',
type: 'a'
}];
});
答案 13 :(得分:1)
'use strict';
angular.module('cloudApp')
.controller('MenuController', function ($scope, $location, CloudAuth) {
$scope.menu = [
{
'title': 'Dashboard',
'iconClass': 'fa fa-dashboard',
'link': '/dashboard',
'active': true
},
{
'title': 'Devices',
'iconClass': 'fa fa-star',
'link': '/devices'
},
{
'title': 'Settings',
'iconClass': 'fa fa-gears',
'link': '/settings'
}
];
$location.path('/dashboard');
$scope.isLoggedIn = CloudAuth.isLoggedIn;
$scope.isAdmin = CloudAuth.isAdmin;
$scope.isActive = function(route) {
return route === $location.path();
};
});
在模板中使用以下内容:
<li role="presentation" ng-class="{active:isActive(menuItem.link)}" ng-repeat="menuItem in menu"><a href="{{menuItem.link}}"><i class="{{menuItem.iconClass}}"></i> {{menuItem.title}}</a></li>
答案 14 :(得分:0)
我需要一个不需要更改控制器的解决方案,因为对于某些页面我们只渲染模板而根本没有控制器。感谢以前的评论者建议使用$routeChangeSuccess
,我提出了类似的内容:
# Directive
angular.module('myapp.directives')
.directive 'ActiveTab', ($route) ->
restrict: 'A'
link: (scope, element, attrs) ->
klass = "active"
if $route.current.activeTab? and attrs.flActiveLink is $route.current.activeTab
element.addClass(klass)
scope.$on '$routeChangeSuccess', (event, current) ->
if current.activeTab? and attrs.flActiveLink is current.activeTab
element.addClass(klass)
else
element.removeClass(klass)
# Routing
$routeProvider
.when "/page",
templateUrl: "page.html"
activeTab: "page"
.when "/other_page",
templateUrl: "other_page.html"
controller: "OtherPageCtrl"
activeTab: "other_page"
# View (.jade)
a(ng-href='/page', active-tab='page') Page
a(ng-href='/other_page', active-tab='other_page') Other page
它不依赖于URL,因此很容易为任何子页面等设置它。
答案 15 :(得分:0)
我不记得我在哪里找到了这种方法,但它非常简单且效果很好。
HTML:
<nav role="navigation">
<ul>
<li ui-sref-active="selected" class="inactive"><a ui-sref="tab-01">Tab 01</a></li>
<li ui-sref-active="selected" class="inactive"><a ui-sref="tab-02">Tab 02</a></li>
</ul>
</nav>
CSS:
.selected {
background-color: $white;
color: $light-blue;
text-decoration: none;
border-color: $light-grey;
}
答案 16 :(得分:0)
如果您正在使用ngRoute(用于路由),那么您的应用程序将具有以下配置,
angular
.module('appApp', [
'ngRoute'
])
config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
controllerAs: 'main'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl',
controllerAs: 'about'
})
}
});
现在,只需在此配置中添加一个控制器,如下所示,
angular
.module('appApp', [
'ngRoute'
])
config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl',
activetab: 'main'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl',
activetab: 'about'
})
}
})
.controller('navController', function ($scope, $route) {
$scope.$route = $route;
});
正如您在配置中提到的有效标签,现在您只需在<li>
或<a>
标记中添加有效课程。像,
ng-class="{active: $route.current.activetab == 'about'}"
这意味着,每当用户点击页面时,这将自动识别当前选项卡并应用活动的css类。
我希望这有帮助!
答案 17 :(得分:-3)
来到这里寻求解决方案..虽然以上解决方案工作正常,但发现它们有点复杂不必要。对于那些仍在寻找简单明了的解决方案的人来说,它将完美地完成任务。
<section ng-init="tab=1">
<ul class="nav nav-tabs">
<li ng-class="{active: tab == 1}"><a ng-click="tab=1" href="#showitem">View Inventory</a></li>
<li ng-class="{active: tab == 2}"><a ng-click="tab=2" href="#additem">Add new item</a></li>
<li ng-class="{active: tab == 3}"><a ng-click="tab=3" href="#solditem">Sold item</a></li>
</ul>
</section>