使用AngularJS设置活动选项卡样式

Ser*_*rov 144 html javascript angularjs

我在AngularJS中设置的路由如下:

$routeProvider
    .when('/dashboard', {templateUrl:'partials/dashboard', controller:widgetsController})
    .when('/lab', {templateUrl:'partials/lab', controller:widgetsController})
Run Code Online (Sandbox Code Playgroud)

我在顶部栏上有一些链接,用作标签.如何根据当前模板或网址将"有效"类添加到选项卡?

Rob*_*ink 274

在不必依赖URL的情况下解决此问题的方法是在$routeProvider配置期间向每个部分添加自定义属性,如下所示:

$routeProvider.
    when('/dashboard', {
        templateUrl: 'partials/dashboard.html',
        controller: widgetsController,
        activetab: 'dashboard'
    }).
    when('/lab', {
        templateUrl: 'partials/lab.html',
        controller: widgetsController,
        activetab: 'lab'
    });
Run Code Online (Sandbox Code Playgroud)

暴露$route在您的控制器中:

function widgetsController($scope, $route) {
    $scope.$route = $route;
}
Run Code Online (Sandbox Code Playgroud)

active根据当前活动选项卡设置类:

<li ng-class="{active: $route.current.activetab == 'dashboard'}"></li>
<li ng-class="{active: $route.current.activetab == 'lab'}"></li>
Run Code Online (Sandbox Code Playgroud)

  • 只有一件事:更好地设置`$ scope.activeTab = $ route.current.activetab`,这样你就可以保持html更清洁. (9认同)
  • 这是迄今为止我见过的最好的解决方案,因为它支持像/ foo /:bar这样的动态网址. (3认同)
  • 我实际上无法让这个工作.你能提供一个plnkr吗? (3认同)
  • 在AngularJS 1.2.0rc1中,此解决方案对我不起作用. (2认同)
  • 这在AngularJS 1.0.8中不起作用.$ route.current未定义. (2认同)
  • 将此与@ Lucas的`$ rootScope`技巧结合使用,使其在所有范围内都可用. (2认同)

pko*_*rce 134

一种方法是使用ngClass指令和$ location服务.在您的模板中,您可以:

ng-class="{active:isActive('/dashboard')}"
Run Code Online (Sandbox Code Playgroud)

where isActive将是如下定义的范围中的函数:

myApp.controller('MyCtrl', function($scope, $location) {
    $scope.isActive = function(route) {
        return route === $location.path();
    }
});
Run Code Online (Sandbox Code Playgroud)

这是完整的jsFiddle:http://jsfiddle.net/pkozlowski_opensource/KzAfG/

ng-class="{active:isActive('/dashboard')}"在每个导航选项卡上重复可能很繁琐(如果你有很多选项卡),所以这个逻辑可能是一个非常简单的指令的候选者.


XML*_*XML 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");
            }
        });
      }
    };
  });
Run Code Online (Sandbox Code Playgroud)

我们通过倾听$routeChangeSuccess事件来实现我们的目标,而不是通过$watch路径.我认为这意味着逻辑应该不那么频繁地运行,因为我认为手表会在每个$digest循环中触发.

通过在指令声明上传递路径级参数来调用它.这指定了要与href属性匹配的当前$ location.path()的块.

<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>
Run Code Online (Sandbox Code Playgroud)

因此,如果您的选项卡应对路径的基本级别做出反应,请将参数设为"1".因此,当location.path()为"/ home"时,它将匹配中的"#/ home" href.如果您的选项卡应对路径的第二级,第三级或第11级作出反应,请相应地进行调整.从1或更大的切片将绕过href中的邪恶'#',它将存在于索引0处.

唯一的要求是你调用一个<a>,因为元素假定存在一个href属性,它将与当前路径进行比较.但是,如果您希望调用<li>或者某些内容,则可以相当容易地调整父/子元素的读/写.我挖掘它是因为您可以通过简单地改变pathLevel参数在许多上下文中重复使用它.如果在逻辑中假定要读取的深度,则需要多个版本的指令才能与导航的多个部分一起使用.


编辑3/18/14:解决方案没有充分概括,并且如果您为undefined两者$location.path()和元素返回的'activeTab'值定义了一个arg,则会激活href.因为: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>
Run Code Online (Sandbox Code Playgroud)

请注意,此版本不再远程类似于Bootstrap样式的HTML.但是,它更现代,使用更少的元素,所以我偏爱它.这个版本的指令加上原始版本现在可以作为一个插件模块在Github上使用,您可以将其声明为依赖项.如果有人真正使用它们,我会很高兴Bower-ize.

此外,如果你想要一个包含<li>s 的bootstrap兼容版本,你可以使用 angular-ui-bootstrap Tabs模块,我认为这个模块在这篇原始帖子之后出现,它可能比这个更具声明性.它对于基本内容不太简洁,但为您提供了一些其他选项,例如禁用选项卡和激活和停用时触发的声明性事件.

  • 我简直不敢相信没有人给这个投票!这是我的2美分.虽然代码中存在一个小错误,但我认为'tabLevel'应该是'activeTab'.对于Bootstrap样式,您可能希望将"active"类添加到LI元素而不是A元素.但这只需要很小的改变. (4认同)

Luc*_*cas 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;
   });
}]);
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

  • 取决于你想要什么.通常你会'/'url成为你的主控制器.这样,当用户转到您的网址时,它将加载该控制器并将该选项卡设置为活动状态.在上面的示例中,我没有'/'url,所以如果你的情况只是添加一个.otherwise()$ routeProvider.when('/ dashboard',{templateUrl:'partials/dashboard.html',controller:Ctrl1}).when('/ lab',{templateUrl:'partials/lab.html',controller:Ctrl2}).否则({redirectTo:'/ dashboard'}); 祝你好运! (2认同)

kfi*_*fis 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>
Run Code Online (Sandbox Code Playgroud)

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);
                }
            });
        }

    };

}]);
Run Code Online (Sandbox Code Playgroud)


Zym*_*tik 14

最简单的解决方案:

如何使用Angular JS设置bootstrap navbar活动类?

这是:

使用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>
Run Code Online (Sandbox Code Playgroud)

并包含在controllers.js中:

function HeaderController($scope, $location) 
{ 
    $scope.isActive = function (viewLocation) { 
        return viewLocation === $location.path();
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 同意,到目前为止最简单 (2认同)

Dav*_*Lin 12

我建议使用state.ui模块,它不仅支持多个和嵌套视图,而且使这种工作非常简单(下面引用的代码):

<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>
Run Code Online (Sandbox Code Playgroud)

值得阅读.