AngularJS在为当前页面的链接设置一个活动类方面有任何帮助吗?

我想一定有什么神奇的方法可以做到,但我似乎找不到。

我的菜单是这样的:

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

我在我的路由中为它们每个都有控制器:TasksController和ActionsController。

但是我想不出一种方法将a链接上的“活动”类绑定到控制器。

有提示吗?


当前回答

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

但它还不完美。小心哈希邦;)

下面是指令的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; }

其他回答

$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>

在视图

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

在控制器

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

这样,tasks链接将在任何以'/tasks'开头的url中具有活动类。/任务/ 1 /报告)

Here is the solution that I came up with after reading some of the excellent suggestions above. In my particular situation, I was trying to use Bootstrap tabs component as my menu, but didn't want to use the Angular-UI version of this because I want the tabs to act as a menu, where each tab is bookmark-able, rather than the tabs acting as navigation for a single page. (See http://angular-ui.github.io/bootstrap/#/tabs if you're interested in what the Angular-UI version of bootstrap tabs looks like).

I really liked kfis's answer about creating your own directive to handle this, however it seemed cumbersome to have a directive that needed to be placed on every single link. So I've created my own Angular directive which is placed instead once on the ul. Just in case any one else is trying to do the same thing, I thought I'd post it here, though as I said, many of the above solutions work as well. This is a slightly more complex solution as far as the javascript goes, but it creates a reusable component with minimal markup.

下面是指令的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>

这里是它的活塞:http://plnkr.co/edit/xwGtGqrT7kWoCKnGDHYN?p=preview。

如果你想把指令的链接放在一个包装器中,而不是选择每个单独的链接(这样更容易查看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,但你可以很容易地改变我所做的过滤等。

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

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