Следуя совету Павла об использовании пользовательской директивы, вот версия, которая не требует добавления полезной нагрузки к 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
цикле.
Вызовите его, передав аргумент уровня пути в объявлении директивы. Это указывает, с каким блоком текущего $ location.path () вы хотите сопоставить свой href
атрибут.
<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>
Итак, если ваши вкладки должны реагировать на базовый уровень пути, задайте аргумент «1». Таким образом, когда location.path () равен "/ home", он будет совпадать с "# / home" в href
. Если у вас есть вкладки, которые должны реагировать на второй уровень, третий или одиннадцатый путь, скорректируйте их соответствующим образом. Это разделение от 1 или больше будет обходить гнусное «#» в href, которое будет жить с индексом 0.
Единственное требование заключается в том, что вы вызываете для <a>
, так как элемент предполагает наличие href
атрибута, который он будет сравнивать с текущим путем. Тем не менее, вы можете довольно легко адаптироваться для чтения / записи родительского или дочернего элемента, если вы предпочитаете вызывать его <li>
или что-то еще. Я копаю это, потому что вы можете использовать его во многих контекстах, просто меняя аргумент pathLevel. Если в логике предполагалась глубина чтения, вам понадобилось бы несколько версий директивы для использования с несколькими частями навигации.
РЕДАКТИРОВАНИЕ 18.03.14: Решение было недостаточно обобщено и активировалось бы, если бы вы определили arg для значения 'activeTab', которое возвращалось 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>
Обратите внимание, что эта версия больше не напоминает HTML в стиле Bootstrap. Но он более современный и использует меньше элементов, поэтому я неравнодушен к этому. Эта версия директивы, а также оригинал теперь доступны на Github в качестве вставного модуля, который вы можете просто объявить как зависимость. Я был бы счастлив, чтобы Bower-ize их, если кто-то на самом деле использует их.
Кроме того, если вам нужна совместимая с начальной загрузкой версия, включающая в себя <li>
, вы можете использовать модуль вкладок angular-ui-bootstrap , который, как мне кажется, появился после этой первоначальной публикации и, возможно, даже более декларативный, чем этот. Он менее лаконичен для базовых вещей, но предоставляет вам некоторые дополнительные опции, такие как отключенные вкладки и декларативные события, которые запускаются при активации и деактивации.