使用 AngularJS 设置活动标签样式

IT技术 javascript html angularjs
2021-01-15 11:02:35

我在 AngularJS 中设置了这样的路由:

$routeProvider
    .when('/dashboard', {templateUrl:'partials/dashboard', controller:widgetsController})
    .when('/lab', {templateUrl:'partials/lab', controller:widgetsController})

我在顶部栏上有一些链接样式为选项卡。如何根据当前模板或 url 将“活动”类添加到选项卡?

6个回答

一种无需依赖 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>
我实际上一直无法让这个工作。你能提供一个plnkr吗?
2021-03-20 11:02:35
将此与$rootScope下面@Lucas 技巧相结合,使其适用于所有范围。
2021-03-20 11:02:35
这是迄今为止我见过的最好的解决方案,因为它支持像 /foo/:bar 这样的动态 url。
2021-03-21 11:02:35
只是一件事:更好地设置,$scope.activeTab = $route.current.activetab以便您可以保持 html 更干净一点。
2021-03-25 11:02:35
这在 AngularJS 1.0.8 中不起作用。$route.current 未定义。
2021-04-03 11:02:35

一种方法是使用 ngClass 指令和 $location 服务。在您的模板中,您可以执行以下操作:

ng-class="{active:isActive('/dashboard')}"

whereisActive将是一个在如下定义的范围内的函数:

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')}"在每个导航选项卡上重复可能很乏味(如果您有很多选项卡),因此此逻辑可能是一个非常简单的指令的候选者。

我花了很长时间才发现“非常简单的指令”实际上编写起来非常简单,所以我在下面提供了一个。:-) 它应该可以在各种上下文中重用,没有非声明性配置。
2021-03-15 11:02:35
查看 jsFiddle,如何在页面加载时设置当前页面处于活动状态?该示例仅在用户单击选项时有效。例如,您可能希望在从外部链接登陆主页时突出显示“主页”导航。
2021-03-27 11:02:35
啊,这让我摸不着头脑。谢谢!
2021-04-06 11:02:35

遵循 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>

因此,如果您的选项卡应该对路径的基本级别做出react,请将参数设为“1”。因此,当 location.path() 为“/home”时,它将与href. 如果您的选项卡应该对路径的第二层、第三层或 11 层做出react,请相应地进行调整。这种从 1 或更大的切片将绕过 href 中的邪恶“#”,它将位于索引 0 处。

唯一的要求是您调用<a>,因为该元素假设存在一个href属性,它将与当前路径进行比较。但是,如果您更喜欢调用<li>或 某物,您可以很容易地适应读/写父元素或子元素我挖掘这个是因为您可以通过简单地改变 pathLevel 参数在许多上下文中重新使用它。如果在逻辑中假设了要读取的深度,则需要多个版本的指令才能与导航的多个部分一起使用。


2014 年 3 月 18 日编辑:该解决方案没有得到充分的概括,如果您为 'activeTab' 的值定义了一个 arg ,该值undefined针对$location.path()和元素的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>

请注意,此版本不再类似于 Bootstrap 样式的 HTML。但是,它更现代,使用的元素更少,所以我偏爱它。这个版本的指令,加上原来的,现在可以在 Github 上作为一个插入module使用,你可以声明为一个依赖项。如果有人真的使用它们,我很乐意将它们鲍尔化。

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

要使其与 bootstrap3 一起使用,您所要做的就是将 ` element.addClass("active");` 更改为 ` element.parent('li').addClass("active");` 我认为它可能会更好虽然命名,但类似于is-active-tab insead of active-tab似乎声明该选项卡处于活动状态。否则,这是一个非常好的指令。在@domi 的答案中查看此更改
2021-03-23 11:02:35
这是简单而精彩的。我很惊讶 Angular 中没有这样的东西来检查你所在的路线。
2021-03-26 11:02:35
你对 activeTab,@DavidLin 是完全正确的。已编辑。但是,我不喜欢 Bootstrap 的结构,因此有故意的不同。事实上,我开始认为导航抽象可能根本不属于 in ul,也许应该只是锚点的集合,由 anav或其他分组元素包裹处理li's的中间层增加了复杂性,而且没有回报,特别是现在我们可以使用nav元素来明确发生了什么。
2021-04-03 11:02:35
我简直不敢相信没有人真的给这个投票!这是我的 2 美分。尽管代码中有一个小错误,但我认为“tabLevel”应该是“activeTab”。对于 Bootstrap 样式,您可能希望将 'active' 类添加到 LI 元素而不是 A 元素。但这只需要微小的改变。
2021-04-07 11:02:35
此页面上的最佳解决方案,无法相信它的投票如此之少。
2021-04-07 11:02:35

@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>
取决于你想要什么。通常,您将 '/' url 作为您的主控制器。这样,当用户访问您的 url 时,它将加载该控制器并将该选项卡设置为活动状态。在上面的示例中,我没有“/”网址,因此如果您的情况是这样,只需添加一个 .otherwise() $routeProvider。when('/dashboard', { templateUrl: 'partials/dashboard.html', 控制器: Ctrl1 })。when('/lab', { templateUrl: 'partials/lab.html', 控制器: Ctrl2 }).否则({ redirectTo: '/dashboard' }); 祝你好运!
2021-03-21 11:02:35
非常感谢您的修改。非常好。在页面首次加载时,您对设置活动标签有什么建议吗?
2021-03-22 11:02:35
非常感谢@Lucas。那有帮助。出于某种原因,我不得不将 # 符号添加到我的主路由中 - when('#/', { controller: FormsController, templateUrl: 'partials/dashboard.html' })。
2021-03-22 11:02:35
我更喜欢这种方式。拥有一个 rootScope 并在任何地方做任何事情
2021-03-31 11:02:35

也许这样的指令可能会解决您的问题: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);
                }
            });
        }

    };

}]);
请注意,如果 href 包含表达式,则必须使用 $observe :docs.angularjs.org/guide/directive#Attributes查看更新的小提琴:jsfiddle.net/p3ZMR/10
2021-03-18 11:02:35