【问题标题】:How to highlight a current menu item?如何突出显示当前菜单项?
【发布时间】:2012-09-17 12:46:55
【问题描述】:

AngularJS 是否有助于在当前页面的链接上设置active 类?

我想有一些神奇的方法可以做到这一点,但我似乎找不到。

我的菜单如下:

 <ul>
   <li><a class="active" href="/tasks">Tasks</a>
   <li><a href="/actions">Tasks</a>
 </ul>

我的路由中每个都有控制器:TasksControllerActionsController

但我无法找到将a 链接上的“活动”类绑定到控制器的方法。

有什么提示吗?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    正在观看

    <a ng-class="getClass('/tasks')" href="/tasks">Tasks</a>
    

    在控制器上

    $scope.getClass = function (path) {
      return ($location.path().substr(0, path.length) === path) ? 'active' : '';
    }
    

    这样,任务链接将在任何以“/tasks”开头的 url 中具有活动类(例如“/tasks/1/reports”)

    【讨论】:

    • 这最终会匹配“/”和“/anything”,或者如果您有多个具有相似网址的菜单项,例如“/test”、“/test/this”、“/test/ this/path" 如果您在 /test 上,它将突出显示所有这些选项。
    • 我把它改成了 if ($location.path() == path) and ,y path is "/blah" etc
    • 我更喜欢 ngClass="{active: isActive('/tasks')} 表示法,其中 isActive() 将返回一个布尔值,因为它将控制器和标记/样式解耦。
    • 以防万一有人想知道如果路径是“/”,代码不会加倍,就是这样(抱歉格式化): $scope.getClass = function (path) { if ($location.path().substr(0, path.length) == path) { if (path == "/" && $location.path() == "/") { return "active"; } else if (path == "/") { return ""; } 返回“活跃” } 否则 { 返回“” } }
    • EdHinchliffe 已经指出,这混合了标记和逻辑。它还会导致路径重复,因此可能容易出现复制和粘贴错误。我发现@kfis 的指令方法虽然行数更多,但可重用性更高,并且使标记更清晰。
    【解决方案2】:

    我建议在链接上使用指令。

    但它还不完美。当心hashbangs ;)

    这是指令的javascript:

    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 not return including hashbang
            scope.location = location;
            scope.$watch('location.path()', function (newPath) {
              if (path === newPath) {
                element.addClass(clazz);
              } else {
                element.removeClass(clazz);
              }
            });
          }
        };
      }]);
    

    这是它在 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>
    

    之后使用 css 进行样式设置:

    .active { color: red; }
    

    【讨论】:

    • 我不确定您所说的“注意 hashbangs”是什么意思。似乎它总是会起作用。你能举个反例吗?
    • 如果你尝试使用 Bootstrap 并且需要根据 a li 中 a 的 href 的哈希进行设置,则使用 var path = $(element).children("a")[0].hash.substring(1);。这适用于&lt;li active-link="active"&gt;&lt;a href="#/dashboard"&gt;Dashboard&lt;/a&gt;&lt;/li&gt; 之类的样式
    • 我会将scope.$watch('location.path()', function(newPath) { 更改为scope.$on('$locationChangeStart', function(){
    • 如果您使用的是 ng-href,只需将:var path = attrs.href; 更改为 var path = attrs.href||attrs.ngHref;
    • 如果你使用Bootstrap,需要把活动类放到&lt;li&gt;上,可以把element.addClass(clazz);改成element.parent().addClass(clazz);
    【解决方案3】:

    这是一种适用于 Angular 的简单方法。

    <ul>
        <li ng-class="{ active: isActive('/View1') }"><a href="#/View1">View 1</a></li>
        <li ng-class="{ active: isActive('/View2') }"><a href="#/View2">View 2</a></li>
        <li ng-class="{ active: isActive('/View3') }"><a href="#/View3">View 3</a></li>
    </ul>
    

    在您的 AngularJS 控制器中:

    $scope.isActive = function (viewLocation) {
         var active = (viewLocation === $location.path());
         return active;
    };
    

    这个帖子有许多其他类似的答案。

    How to set bootstrap navbar active class with Angular JS?

    【讨论】:

    • 删除变量,因为它是不必要的。只返回比较结果。 return viewLocation === $location.path()
    【解决方案4】:

    只是为了在辩论中增加我的两分钱,我制作了一个纯角度模块(没有 jQuery),它也适用于包含数据的哈希 url。 (例如#/this/is/path?this=is&amp;some=data

    您只需将模块添加为依赖项并将auto-active 添加到菜单的祖先之一。像这样:

    <ul auto-active>
        <li><a href="#/">main</a></li>
        <li><a href="#/first">first</a></li>
        <li><a href="#/second">second</a></li>
        <li><a href="#/third">third</a></li>
    </ul>
    

    模块看起来像这样:

    (function () {
        angular.module('autoActive', [])
            .directive('autoActive', ['$location', function ($location) {
            return {
                restrict: 'A',
                scope: false,
                link: function (scope, element) {
                    function setActive() {
                        var path = $location.path();
                        if (path) {
                            angular.forEach(element.find('li'), function (li) {
                                var anchor = li.querySelector('a');
                                if (anchor.href.match('#' + path + '(?=\\?|$)')) {
                                    angular.element(li).addClass('active');
                                } else {
                                    angular.element(li).removeClass('active');
                                }
                            });
                        }
                    }
    
                    setActive();
    
                    scope.$on('$locationChangeSuccess', setActive);
                }
            }
        }]);
    }());
    

    (你当然可以只使用指令部分)

    还值得注意的是,这不适用于空哈希(例如example.com/# 或仅example.com),它至少需要具有example.com/#/ 或仅example.com#/。但这会在 ngResource 之类的情况下自动发生。

    这里是小提琴:http://jsfiddle.net/gy2an/8/

    【讨论】:

    • 很好的解决方案,但是它在初始页面加载时不起作用,只是在应用程序运行时在 locationChange 上起作用。我更新了你的snippet 来处理这个问题。
    • @Jarek:谢谢!已实施您的更改。我个人没有遇到过这个问题,但是对于那些应该遇到这个问题的人来说,你的解决方案似乎是一个很好的稳定解决方案。
    • 如果其他人有任何好的想法,我现在已经为拉取请求创建了一个 Github 存储库:github.com/Karl-Gustav/autoActive
    • 我刚刚修复了一些在您使用 ng-href 时会出现的错误。可以在这里找到:github.com/Karl-Gustav/autoActive/pull/3
    • 如果这个脚本允许你指定一个路径,这样你就可以让它激活其他元素,那就太好了。
    【解决方案5】:

    在我的例子中,我通过创建一个负责导航的简单控制器解决了这个问题

    angular.module('DemoApp')
      .controller('NavigationCtrl', ['$scope', '$location', function ($scope, $location) {
        $scope.isCurrentPath = function (path) {
          return $location.path() == path;
        };
      }]);
    

    只需像这样将 ng-class 添加到元素中:

    <ul class="nav" ng-controller="NavigationCtrl">
      <li ng-class="{ active: isCurrentPath('/') }"><a href="#/">Home</a></li>
      <li ng-class="{ active: isCurrentPath('/about') }"><a href="#/about">About</a></li>
      <li ng-class="{ active: isCurrentPath('/contact') }"><a href="#/contact">Contact</a></li>
    </ul>
    

    【讨论】:

      【解决方案6】:

      AngularUI路由器用户:

      <a ui-sref-active="active" ui-sref="app">
      

      这将在被选中的对象上放置一个active 类。

      【讨论】:

      • 这是一个 ui-router 指令,如果你使用内置路由器,也就是 ngRoute,它就不起作用。也就是说,ui-router 很棒。
      • 同意,我一开始忘了说这是一个 ui-router 唯一的解决方案。
      【解决方案7】:

      有一个ng-class 指令,它绑定变量和css 类。 它还接受对象(类名与布尔值对)。

      这是一个例子,http://plnkr.co/edit/SWZAqj

      【讨论】:

      • 谢谢,但这不适用于以下路径:/test1/blahblah,还是这样?
      • 那么您是说active: activePath=='/test1' 自动返回“活动”是路径以给定字符串开头吗?这是某种预定义的运算符或正则表达式吗?
      • 抱歉,我认为我没有正确理解您的要求。这是我的新猜测,当路由为“test1/blahblah”时,您希望同时突出显示“test1”链接和“test1/blahblah”链接。”我正确吗?如果这是要求,你是对的,我的解决方案没有工作。
      • 这里是更新后的 plnkr:plnkr.co/edit/JI5DtK(满足猜测的要求)仅显示替代解决方案。
      • 我知道你在那里做了什么。但我不喜欢在 html 中重复 == 检查。
      【解决方案8】:

      来自@Renan-tomal-fernandes 的answer 很好,但需要一些改进才能正常工作。 事实上,它总是会检测到主页 ( / ) 的链接被触发,即使您在另一个部分。

      所以我对其进行了一些改进,这是代码。 我使用Bootstrap,因此活动部分位于&lt;li&gt; 元素中,而不是&lt;a&gt;

      控制器

      $scope.getClass = function(path) {
          var cur_path = $location.path().substr(0, path.length);
          if (cur_path == path) {
              if($location.path().substr(0).length > 1 && path.length == 1 )
                  return "";
              else
                  return "active";
          } else {
              return "";
          }
      }
      

      模板

      <div class="nav-collapse collapse">
        <ul class="nav">
          <li ng-class="getClass('/')"><a href="#/">Home</a></li>
          <li ng-class="getClass('/contents/')"><a href="#/contests/">Contents</a></li>
          <li ng-class="getClass('/data/')"><a href="#/data/">Your data</a></li>
        </ul>
      </div>
      

      【讨论】:

        【解决方案9】:

        这是我在阅读了上面的一些优秀建议后提出的解决方案。在我的特殊情况下,我试图使用 Bootstrap tabs component 作为我的菜单,但不想使用 Angular-UI 版本,因为我希望选项卡充当菜单,每个选项卡都可以添加书签,而不是作为单个页面导航的选项卡。 (如果您对 Angular-UI 版本的引导选项卡的外观感兴趣,请参阅 http://angular-ui.github.io/bootstrap/#/tabs)。

        我真的很喜欢 kfis 关于创建自己的指令来处理这个问题的答案,但是有一个需要放置在每个链接上的指令似乎很麻烦。所以我创建了我自己的 Angular 指令,它被放置在 ul 上一次。以防万一其他人尝试做同样的事情,我想我会把它贴在这里,尽管正如我所说,上述许多解决方案也有效。就 javascript 而言,这是一个稍微复杂的解决方案,但它创建了一个可重用的组件,并且标记最少。

        这是指令的 javascript 和 ng:view 的路由提供程序:

        var app = angular.module('plunker', ['ui.bootstrap']).
          config(['$routeProvider', function($routeProvider) {
            $routeProvider.
                when('/One', {templateUrl: 'one.html'}).
                when('/Two', {templateUrl: 'two.html'}).
                when('/Three', {templateUrl: 'three.html'}).
                otherwise({redirectTo: '/One'});
          }]).
          directive('navTabs', ['$location', function(location) {
            return {
                restrict: 'A',
                link: function(scope, element) {
                    var $ul = $(element);
                    $ul.addClass("nav nav-tabs");
        
                    var $tabs = $ul.children();
                    var tabMap = {};
                    $tabs.each(function() {
                      var $li = $(this);
                      //Substring 1 to remove the # at the beginning (because location.path() below does not return the #)
                      tabMap[$li.find('a').attr('href').substring(1)] = $li;
                    });
        
                    scope.location = location;
                    scope.$watch('location.path()', function(newPath) {
                        $tabs.removeClass("active");
                        tabMap[newPath].addClass("active");
                    });
                }
        
            };
        
         }]);
        

        然后在您的 html 中,您只需:

        <ul nav-tabs>
          <li><a href="#/One">One</a></li>
          <li><a href="#/Two">Two</a></li>
          <li><a href="#/Three">Three</a></li>
        </ul>
        <ng:view><!-- Content will appear here --></ng:view>
        

        这是它的 plunker:http://plnkr.co/edit/xwGtGqrT7kWoCKnGDHYN?p=preview

        【讨论】:

          【解决方案10】:

          你可以很简单地实现这个,这里有一个例子:

          <div ng-controller="MenuCtrl">
            <ul class="menu">
              <li ng-class="menuClass('home')"><a href="#home">Page1</a></li>
              <li ng-class="menuClass('about')"><a href="#about">Page2</a></li>
            </ul>
          
          </div>
          

          你的控制器应该是这样的:

          app.controller("MenuCtrl", function($scope, $location) {
            $scope.menuClass = function(page) {
              var current = $location.path().substring(1);
              return page === current ? "active" : "";
            };
          });
          

          【讨论】:

            【解决方案11】:

            使用 angular-ui-router 的 ui-sref-active 指令 https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statename

            <ul>
              <li ui-sref-active="active" class="item">
                <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
              </li>
              <!-- ... -->
            </ul>

            【讨论】:

              【解决方案12】:

              在 Bootstrap 4.1 中使用 Angular 版本 6

              我能够完成它,如下所示。

              在下面的示例中,当 URL 看到“/contact”时,将激活引导程序添加到 html 标记中。当 URL 发生变化时,它会被删除。

              <ul>
              <li class="nav-item" routerLink="/contact" routerLinkActive="active">
                  <a class="nav-link" href="/contact">Contact</a>
              </li>
              </ul>
              

              这个指令允许你在链接的时候给一个元素添加一个 CSS 类 路线变得活跃。

              阅读更多Angular website

              【讨论】:

              • 这是 2020 年的答案。(activecss-class
              【解决方案13】:

              我在控制器范围之外的菜单遇到了类似的问题。不确定这是最好的解决方案还是推荐的解决方案,但这对我有用。我已将以下内容添加到我的应用配置中:

              var app = angular.module('myApp');
              
              app.run(function($rootScope, $location){
                $rootScope.menuActive = function(url, exactMatch){
                  if (exactMatch){
                    return $location.path() == url;
                  }
                  else {
                    return $location.path().indexOf(url) == 0;
                  }
                }
              });
              

              然后在我的视图中:

              <li><a href="/" ng-class="{true: 'active'}[menuActive('/', true)]">Home</a></li>
              <li><a href="/register" ng-class="{true: 'active'}[menuActive('/register')]">
              <li>...</li>
              

              【讨论】:

              • 嗯...这似乎比公认的答案更复杂。你能描述一下这个比那个的优势吗?
              • 当您的菜单在 ng-view 之外时,您将需要它。视图控制器无法访问外部的任何内容,因此我使用 $rootScope 来启用通信。如果您的菜单在 ng-view 中,那么使用此解决方案对您没有任何好处。
              【解决方案14】:

              使用指令(因为我们在这里进行 DOM 操作)以下可能是最接近“角度方式”的处理方式:

              $scope.timeFilters = [
                {'value':3600,'label':'1 hour'},
                {'value':10800,'label':'3 hours'},
                {'value':21600,'label':'6 hours'},
                {'value':43200,'label':'12 hours'},
                {'value':86400,'label':'24 hours'},
                {'value':604800,'label':'1 week'}
              ]
              
              angular.module('whatever', []).directive('filter',function(){
              return{
                  restrict: 'A',
                  template: '<li ng-repeat="time in timeFilters" class="filterItem"><a ng-click="changeTimeFilter(time)">{{time.label}}</a></li>',
                  link: function linkFn(scope, lElement, attrs){
              
                      var menuContext = attrs.filter;
              
                      scope.changeTimeFilter = function(newTime){
                        scope.selectedtimefilter = newTime;
              
                      }
              
                      lElement.bind('click', function(cevent){
                          var currentSelection = angular.element(cevent.srcElement).parent();
                          var previousSelection = scope[menuContext];
              
                          if(previousSelection !== currentSelection){
                              if(previousSelection){
                                  angular.element(previousSelection).removeClass('active')
                              }
                              scope[menuContext] = currentSelection;
              
                              scope.$apply(function(){
                                  currentSelection.addClass('active');
                              })
                          }
                      })
                  }
              }
              })
              

              那么您的 HTML 将如下所示:

              <ul class="dropdown-menu" filter="times"></ul>
              

              【讨论】:

              • 有趣。但是menu-item 在每一行似乎都是多余的。也许将属性附加到ul 元素(例如&lt;ul menu&gt;)会更好,但我不确定这是否可能。
              • 刚刚更新了新版本 - 我现在使用 Boostrap 下拉菜单作为选择列表,而不是静态无序列表。
              • 这确实看起来最像惯用的角度。它似乎符合stackoverflow.com/questions/14994391/… 给出的建议,并且避免了在视图、href 和 ng-class 中重复路径。
              【解决方案15】:

              我是这样做的:

              var myApp = angular.module('myApp', ['ngRoute']);
              
              myApp.directive('trackActive', function($location) {
                  function link(scope, element, attrs){
                      scope.$watch(function() {
                          return $location.path();
                      }, function(){
                          var links = element.find('a');
                          links.removeClass('active');
                          angular.forEach(links, function(value){
                              var a = angular.element(value);
                              if (a.attr('href') == '#' + $location.path() ){
                                  a.addClass('active');
                              }
                          });
                      });
                  }
                  return {link: link};
              });
              

              这使您可以在具有 track-active 指令的部分中拥有链接:

              <nav track-active>
                   <a href="#/">Page 1</a>
                   <a href="#/page2">Page 2</a>
                   <a href="#/page3">Page 3</a>
              </nav>
              

              对我来说,这种方法似乎比其他方法更干净。

              另外,如果你使用 jQuery,你可以让它更整洁,因为 jQlite 只支持基本的选择器。在 angular include 之前包含 jquery 的更简洁的版本如下所示:

              myApp.directive('trackActive', function($location) {
                  function link(scope, element, attrs){
                      scope.$watch(function() {
                          return $location.path();
                      }, function(){
                          element.find('a').removeClass('active').find('[href="#'+$location.path()+'"]').addClass('active');
                      });
                  }
                  return {link: link};
              });
              

              Here is a jsFiddle

              【讨论】:

                【解决方案16】:

                我对这个问题的解决方法,在角模板中使用route.current

                由于您在菜单中突出显示了 /tasks 路由,因此您可以将自己的属性 menuItem 添加到模块声明的路由中:

                $routeProvider.
                  when('/tasks', {
                    menuItem: 'TASKS',
                    templateUrl: 'my-templates/tasks.html',
                    controller: 'TasksController'
                  );
                

                然后在你的模板tasks.html你可以使用下面的ng-class指令:

                <a href="app.html#/tasks" 
                    ng-class="{active : route.current.menuItem === 'TASKS'}">Tasks</a>
                

                在我看来,这比所有提议的解决方案都要干净。

                【讨论】:

                  【解决方案17】:

                  这是我对 kfis 指令的扩展,它允许不同级别的路径匹配。本质上,我发现需要将 URL 路径匹配到一定深度,因为精确匹配不允许嵌套和默认状态重定向。希望这会有所帮助。

                      .directive('selectedLink', ['$location', function(location) {
                      return {
                          restrict: 'A',
                          scope:{
                              selectedLink : '='
                              },
                          link: function(scope, element, attrs, controller) {
                              var level = scope.selectedLink;
                              var path = attrs.href;
                              path = path.substring(1); //hack because path does not return including hashbang
                              scope.location = location;
                              scope.$watch('location.path()', function(newPath) {
                                  var i=0;
                                  p = path.split('/');
                                  n = newPath.split('/');
                                  for( i ; i < p.length; i++) { 
                                      if( p[i] == 'undefined' || n[i] == 'undefined' || (p[i] != n[i]) ) break;
                                      }
                  
                                  if ( (i-1) >= level) {
                                      element.addClass("selected");
                                      } 
                                  else {
                                      element.removeClass("selected");
                                      }
                                  });
                              }
                  
                          };
                      }]);
                  

                  这是我使用链接的方式

                  <nav>
                      <a href="#/info/project/list"  selected-link="2">Project</a>
                      <a href="#/info/company/list" selected-link="2">Company</a>
                      <a href="#/info/person/list"  selected-link="2">Person</a>
                  </nav>
                  

                  该指令将匹配指令属性值中指定的深度级别。只是意味着它可以在其他地方多次使用。

                  【讨论】:

                    【解决方案18】:

                    这是另一个突出显示活动链接的指令。

                    主要特点:

                    • 适用于包含动态角度表达式的 href
                    • 兼容 hash-bang 导航
                    • 与 Bootstrap 兼容,其中活动类应应用于父 li 而不是链接本身
                    • 如果任何嵌套路径处于活动状态,则允许使链接处于活动状态
                    • 如果链接不活动,则允许禁用链接

                    代码:

                    .directive('activeLink', ['$location', 
                    function($location) {
                        return {
                            restrict: 'A',
                            link: function(scope, elem, attrs) {
                                var path = attrs.activeLink ? 'activeLink' : 'href';
                                var target = angular.isDefined(attrs.activeLinkParent) ? elem.parent() : elem;
                                var disabled = angular.isDefined(attrs.activeLinkDisabled) ? true : false;
                                var nested = angular.isDefined(attrs.activeLinkNested) ? true : false;
                    
                                function inPath(needle, haystack) {
                                    var current = (haystack == needle);
                                    if (nested) {
                                        current |= (haystack.indexOf(needle + '/') == 0);
                                    }
                    
                                    return current;
                                }
                    
                                function toggleClass(linkPath, locationPath) {
                                    // remove hash prefix and trailing slashes
                                    linkPath = linkPath ? linkPath.replace(/^#!/, '').replace(/\/+$/, '') : '';
                                    locationPath = locationPath.replace(/\/+$/, '');
                    
                                    if (linkPath && inPath(linkPath, locationPath)) {
                                        target.addClass('active');
                                        if (disabled) {
                                            target.removeClass('disabled');
                                        }
                                    } else {
                                        target.removeClass('active');
                                        if (disabled) {
                                            target.addClass('disabled');
                                        }
                                    }
                                }
                    
                                // watch if attribute value changes / evaluated
                                attrs.$observe(path, function(linkPath) {
                                    toggleClass(linkPath, $location.path());
                                });
                    
                                // watch if location changes
                                scope.$watch(
                                    function() {
                                        return $location.path(); 
                                    }, 
                                    function(newPath) {
                                        toggleClass(attrs[path], newPath);
                                    }
                                );
                            }
                        };
                    }
                    ]);
                    

                    用法:

                    带有角度表达式的简单示例,假设 $scope.var = 2,如果位置为 /url/2,则链接将处于活动状态:

                    <a href="#!/url/{{var}}" active-link>
                    

                    Bootstrap 示例,父 li 将获得活动类:

                    <li>
                        <a href="#!/url" active-link active-link-parent>
                    </li>
                    

                    嵌套 url 示例,如果任何嵌套 url 处于活动状态,则链接将处于活动状态(即 /url/1/url/2url/1 /2/...)

                    <a href="#!/url" active-link active-link-nested>
                    

                    复杂的例子,链接指向一个 url (/url1) 但如果另一个被选中 (/url2) 则会激活:

                    <a href="#!/url1" active-link="#!/url2" active-link-nested>
                    

                    禁用链接的示例,如果它未激活,它将具有 'disabled' 类:

                    <a href="#!/url" active-link active-link-disabled>
                    

                    所有active-link-*属性都可以任意组合使用,因此可以实现非常复杂的条件。

                    【讨论】:

                      【解决方案19】:

                      如果您希望将指令的链接放在包装器中,而不是选择每个单独的链接(更容易查看 Batarang 中的范围),这也很有效:

                        angular.module("app").directive("navigation", [
                          "$location", function($location) {
                            return {
                              restrict: 'A',
                              scope: {},
                              link: function(scope, element) {
                                var classSelected, navLinks;
                      
                                scope.location = $location;
                      
                                classSelected = 'selected';
                      
                                navLinks = element.find('a');
                      
                                scope.$watch('location.path()', function(newPath) {
                                  var el;
                                  el = navLinks.filter('[href="' + newPath + '"]');
                      
                                  navLinks.not(el).closest('li').removeClass(classSelected);
                                  return el.closest('li').addClass(classSelected);
                                });
                              }
                            };
                          }
                        ]);
                      

                      标记只是:

                          <nav role="navigation" data-navigation>
                              <ul>
                                  <li><a href="/messages">Messages</a></li>
                                  <li><a href="/help">Help</a></li>
                                  <li><a href="/details">Details</a></li>
                              </ul>
                          </nav>
                      

                      我还应该提到,我在这个例子中使用了“全脂”jQuery,但是你可以很容易地改变我在过滤等方面所做的事情。

                      【讨论】:

                        【解决方案20】:

                        这是我的两分钱,这很好用。

                        注意:这与子页面不匹配(这是我需要的)。

                        查看:

                        <a ng-class="{active: isCurrentLocation('/my-path')}"  href="/my-path" >
                          Some link
                        </a>
                        

                        控制器:

                        // make sure you inject $location as a dependency
                        
                        $scope.isCurrentLocation = function(path){
                            return path === $location.path()
                        }
                        

                        【讨论】:

                          【解决方案21】:

                          根据@kfis 的回答,是cmets,我推荐,最终指令如下:

                          .directive('activeLink', ['$location', function (location) {
                              return {
                                restrict: 'A',
                                link: function(scope, element, attrs, controller) {
                                  var clazz = attrs.activeLink;        
                                  var path = attrs.href||attrs.ngHref;
                                  path = path.substring(1); //hack because path does not return including hashbang
                                  scope.location = location;
                                  scope.$watch('window.location.href', function () {
                                    var newPath = (window.location.pathname + window.location.search).substr(1);
                                    if (path === newPath) {
                                      element.addClass(clazz);
                                    } else {
                                      element.removeClass(clazz);
                                    }
                                  });
                                }
                              };
                            }]);
                          

                          这是它在 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>
                          

                          之后使用 css 进行样式设置:

                          .active { color: red; }
                          

                          【讨论】:

                            【解决方案22】:

                            对于那些使用 ui-router 的人,我的回答有点类似于 Ender2050 的,但我更喜欢通过州名测试来做到这一点:

                            $scope.isActive = function (stateName) {
                              var active = (stateName === $state.current.name);
                              return active;
                            };
                            

                            对应的HTML:

                            <ul class="nav nav-sidebar">
                                <li ng-class="{ active: isActive('app.home') }"><a ui-sref="app.home">Dashboard</a></li>
                                <li ng-class="{ active: isActive('app.tiles') }"><a ui-sref="app.tiles">Tiles</a></li>
                            </ul>
                            

                            【讨论】:

                              【解决方案23】:

                              上述指令建议对我没有用处。如果你有这样的引导导航栏

                              <ul class="nav navbar-nav">
                                  <li><a ng-href="#/">Home</a></li>
                                  <li><a ng-href="#/about">About</a></li>
                                ...
                              </ul>
                              

                              (可能是$ yo angular 启动)然后您想将.active 添加到 &lt;li&gt; 元素类列表,而不是元素本身;即&lt;li class="active"&gt;..&lt;/li&gt;。所以我写了这个:

                              .directive('setParentActive', ['$location', function($location) {
                                return {
                                  restrict: 'A',
                                  link: function(scope, element, attrs, controller) {
                                    var classActive = attrs.setParentActive || 'active',
                                        path = attrs.ngHref.replace('#', '');
                                    scope.location = $location;
                                    scope.$watch('location.path()', function(newPath) {
                                      if (path == newPath) {
                                        element.parent().addClass(classActive);
                                      } else {
                                        element.parent().removeClass(classActive);
                                      }
                                    })
                                  }
                                }
                              }])
                              

                              使用set-parent-active; .active 是默认的所以不需要设置

                              <li><a ng-href="#/about" set-parent-active>About</a></li>
                              

                              当链接处于活动状态时,父 &lt;li&gt; 元素将为 .active。要使用像 .highlight 这样的替代 .active 类,只需

                              <li><a ng-href="#/about" set-parent-active="highlight">About</a></li>
                              

                              【讨论】:

                              • 我试过 scope.$on("$routeChangeSuccess", function (event, current, previous) { applyActiveClass(); });但它仅在单击链接而不是“页面加载”(单击刷新按钮)时才有效。观看位置对我有用
                              【解决方案24】:

                              对我来说最重要的是完全不要更改引导默认代码。 这是我的菜单控制器,它搜索菜单选项,然后添加我们想要的行为。

                              file: header.js
                              function HeaderCtrl ($scope, $http, $location) {
                                $scope.menuLinkList = [];
                                defineFunctions($scope);
                                addOnClickEventsToMenuOptions($scope, $location);
                              }
                              
                              function defineFunctions ($scope) {
                                $scope.menuOptionOnClickFunction = function () {
                                  for ( var index in $scope.menuLinkList) {
                                    var link = $scope.menuLinkList[index];
                                    if (this.hash === link.hash) {
                                      link.parentElement.className = 'active';
                                    } else {
                                      link.parentElement.className = '';
                                    }
                                  }
                                };
                              }
                              
                              function addOnClickEventsToMenuOptions ($scope, $location) {
                                var liList = angular.element.find('li');
                                for ( var index in liList) {
                                  var liElement = liList[index];
                                  var link = liElement.firstChild;
                                  link.onclick = $scope.menuOptionOnClickFunction;
                                  $scope.menuLinkList.push(link);
                                  var path = link.hash.replace("#", "");
                                  if ($location.path() === path) {
                                    link.parentElement.className = 'active';
                                  }
                                }
                              }
                              
                                   <script src="resources/js/app/header.js"></script>
                               <div class="navbar navbar-fixed-top" ng:controller="HeaderCtrl">
                                  <div class="navbar-inner">
                                    <div class="container-fluid">
                                      <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                                        <span class="icon-bar"></span> <span class="icon-bar"></span> 
                              <span     class="icon-bar"></span>
                                      </button>
                                      <a class="brand" href="#"> <img src="resources/img/fom-logo.png"
                                        style="width: 80px; height: auto;">
                                      </a>
                                      <div class="nav-collapse collapse">
                                        <ul class="nav">
                                          <li><a href="#/platforms">PLATFORMS</a></li>
                                          <li><a href="#/functionaltests">FUNCTIONAL TESTS</a></li>
                                        </ul> 
                                      </div>
                                    </div>
                                  </div>
                                </div>
                              

                              【讨论】:

                                【解决方案25】:

                                有同样的问题。这是我的solution

                                .directive('whenActive',
                                  [
                                    '$location',
                                    ($location)->
                                      scope: true,
                                      link: (scope, element, attr)->
                                        scope.$on '$routeChangeSuccess', 
                                          () ->
                                            loc = "#"+$location.path()
                                            href = element.attr('href')
                                            state = href.indexOf(loc)
                                            substate = -1
                                
                                            if href.length > 3
                                              substate = loc.indexOf(href)
                                            if loc.length is 2
                                              state = -1
                                
                                            #console.log "Is Loc: "+loc+" in Href: "+href+" = "+state+" and Substate = "+substate
                                
                                            if state isnt -1 or substate isnt -1
                                              element.addClass 'selected'
                                              element.parent().addClass 'current-menu-item'
                                            else if href is '#' and loc is '#/'
                                              element.addClass 'selected'
                                              element.parent().addClass 'current-menu-item'
                                            else
                                              element.removeClass 'selected'
                                              element.parent().removeClass 'current-menu-item'
                                  ])
                                

                                【讨论】:

                                  【解决方案26】:

                                  我刚刚为此写了一个指令。

                                  用法:

                                  <ul class="nav navbar-nav">
                                    <li active><a href="#/link1">Link 1</a></li>
                                    <li active><a href="#/link2">Link 2</a></li>
                                  </ul>
                                  

                                  实施:

                                  angular.module('appName')
                                    .directive('active', function ($location, $timeout) {
                                      return {
                                        restrict: 'A',
                                        link: function (scope, element, attrs) {
                                          // Whenever the user navigates to a different page...
                                          scope.$on('$routeChangeSuccess', function () {
                                            // Defer for other directives to load first; this is important
                                            // so that in case other directives are used that this directive
                                            // depends on, such as ng-href, the href is evaluated before
                                            // it's checked here.
                                            $timeout(function () {
                                              // Find link inside li element
                                              var $link = element.children('a').first();
                                  
                                              // Get current location
                                              var currentPath = $location.path();
                                  
                                              // Get location the link is pointing to
                                              var linkPath = $link.attr('href').split('#').pop();
                                  
                                              // If they are the same, it means the user is currently
                                              // on the same page the link would point to, so it should
                                              // be marked as such
                                              if (currentPath === linkPath) {
                                                $(element).addClass('active');
                                              } else {
                                                // If they're not the same, a li element that is currently
                                                // marked as active needs to be "un-marked"
                                                element.removeClass('active');
                                              }
                                            });
                                          });
                                        }
                                      };
                                    });
                                  

                                  测试:

                                  'use strict';
                                  
                                  describe('Directive: active', function () {
                                  
                                    // load the directive's module
                                    beforeEach(module('appName'));
                                  
                                    var element,
                                        scope,
                                        location,
                                        compile,
                                        rootScope,
                                        timeout;
                                  
                                    beforeEach(inject(function ($rootScope, $location, $compile, $timeout) {
                                      scope = $rootScope.$new();
                                      location = $location;
                                      compile = $compile;
                                      rootScope = $rootScope;
                                      timeout = $timeout;
                                    }));
                                  
                                    describe('with an active link', function () {
                                      beforeEach(function () {
                                        // Trigger location change
                                        location.path('/foo');
                                      });
                                  
                                      describe('href', function () {
                                        beforeEach(function () {
                                          // Create and compile element with directive; note that the link
                                          // is the same as the current location after the location change.
                                          element = angular.element('<li active><a href="#/foo">Foo</a></li>');
                                          element = compile(element)(scope);
                                  
                                          // Broadcast location change; the directive waits for this signal
                                          rootScope.$broadcast('$routeChangeSuccess');
                                  
                                          // Flush timeout so we don't have to write asynchronous tests.
                                          // The directive defers any action using a timeout so that other
                                          // directives it might depend on, such as ng-href, are evaluated
                                          // beforehand.
                                          timeout.flush();
                                        });
                                  
                                        it('adds the class "active" to the li', function () {
                                          expect(element.hasClass('active')).toBeTruthy();
                                        });
                                      });
                                  
                                      describe('ng-href', function () {
                                        beforeEach(function () {
                                          // Create and compile element with directive; note that the link
                                          // is the same as the current location after the location change;
                                          // however this time with an ng-href instead of an href.
                                          element = angular.element('<li active><a ng-href="#/foo">Foo</a></li>');
                                          element = compile(element)(scope);
                                  
                                          // Broadcast location change; the directive waits for this signal
                                          rootScope.$broadcast('$routeChangeSuccess');
                                  
                                          // Flush timeout so we don't have to write asynchronous tests.
                                          // The directive defers any action using a timeout so that other
                                          // directives it might depend on, such as ng-href, are evaluated
                                          // beforehand.
                                          timeout.flush();
                                        });
                                  
                                        it('also works with ng-href', function () {
                                          expect(element.hasClass('active')).toBeTruthy();
                                        });
                                      });
                                    });
                                  
                                    describe('with an inactive link', function () {
                                      beforeEach(function () {
                                        // Trigger location change
                                        location.path('/bar');
                                  
                                        // Create and compile element with directive; note that the link
                                        // is the NOT same as the current location after the location change.
                                        element = angular.element('<li active><a href="#/foo">Foo</a></li>');
                                        element = compile(element)(scope);
                                  
                                        // Broadcast location change; the directive waits for this signal
                                        rootScope.$broadcast('$routeChangeSuccess');
                                  
                                        // Flush timeout so we don't have to write asynchronous tests.
                                        // The directive defers any action using a timeout so that other
                                        // directives it might depend on, such as ng-href, are evaluated
                                        // beforehand.
                                        timeout.flush();
                                      });
                                  
                                      it('does not add the class "active" to the li', function () {
                                        expect(element.hasClass('active')).not.toBeTruthy();
                                      });
                                    });
                                  
                                    describe('with a formerly active link', function () {
                                      beforeEach(function () {
                                        // Trigger location change
                                        location.path('/bar');
                                  
                                        // Create and compile element with directive; note that the link
                                        // is the same as the current location after the location change.
                                        // Also not that the li element already has the class "active".
                                        // This is to make sure that a link that is active right now will
                                        // not be active anymore when the user navigates somewhere else.
                                        element = angular.element('<li class="active" active><a href="#/foo">Foo</a></li>');
                                        element = compile(element)(scope);
                                  
                                        // Broadcast location change; the directive waits for this signal
                                        rootScope.$broadcast('$routeChangeSuccess');
                                  
                                        // Flush timeout so we don't have to write asynchronous tests.
                                        // The directive defers any action using a timeout so that other
                                        // directives it might depend on, such as ng-href, are evaluated
                                        // beforehand.
                                        timeout.flush();
                                      });
                                  
                                      it('removes the "active" class from the li', function () {
                                        expect(element.hasClass('active')).not.toBeTruthy();
                                      });
                                    });
                                  });
                                  

                                  【讨论】:

                                    【解决方案27】:

                                    路线:

                                    $routeProvider.when('/Account/', { templateUrl: '/Home/Account', controller: 'HomeController' });
                                    

                                    菜单html:

                                    <li id="liInicio" ng-class="{'active':url=='account'}">
                                    

                                    控制器:

                                    angular.module('Home').controller('HomeController', function ($scope, $http, $location) {
                                        $scope.url = $location.url().replace(/\//g, "").toLowerCase();
                                    ...
                                    

                                    我在这里发现的问题是菜单项只有在整个页面加载时才处于活动状态。加载局部视图时,菜单不会更改。有人知道为什么会这样吗?

                                    【讨论】:

                                      【解决方案28】:
                                      $scope.getClass = function (path) {
                                      return String(($location.absUrl().split('?')[0]).indexOf(path)) > -1 ? 'active' : ''
                                      }
                                      
                                      
                                      <li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/bookings">MY BOOKING</a></li>
                                      <li class="listing-head" ng-class="getClass('/v/fleets')"><a href="/v/fleets">MY FLEET</a></li>
                                      <li class="listing-head" ng-class="getClass('/v/adddriver')"><a href="/v/adddriver">ADD DRIVER</a></li>
                                      <li class="listing-head" ng-class="getClass('/v/bookings')"><a href="/v/invoice">INVOICE</a></li>
                                      <li class="listing-head" ng-class="getClass('/v/profile')"><a href="/v/profile">MY PROFILE</a></li>
                                      <li class="listing-head"><a href="/v/logout">LOG OUT</a></li>
                                      

                                      【讨论】:

                                        【解决方案29】:

                                        我找到了最简单的解决方案。只是为了比较 HTML 中的 indexOf

                                        var myApp = angular.module('myApp', []);
                                        
                                        myApp.run(function($rootScope) {
                                            $rootScope.$on("$locationChangeStart", function(event, next, current) { 
                                                 $rootScope.isCurrentPath = $location.path();  
                                            });
                                        });
                                        
                                        
                                        
                                        <li class="{{isCurrentPath.indexOf('help')>-1 ? 'active' : '' }}">
                                        <a href="/#/help/">
                                                  Help
                                                </a>
                                        </li>
                                        

                                        【讨论】:

                                          猜你喜欢
                                          • 2021-04-07
                                          • 2012-04-05
                                          • 1970-01-01
                                          • 2013-11-18
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 2014-05-19
                                          相关资源
                                          最近更新 更多