我已经建立了一个动态菜单,也有突出显示。
现在我遇到了一个问题,路径变化事件的数量随着菜单元素的增加而增加。
当然,这是在菜单的每个元素上应用指令的结果。
此刻的自定义指令是我最弱的地方,我不知道如何重构这一切。
我还尝试将指令放在菜单(ul)的根元素中,以便注册一次,但仍然访问深度子元素(ul-> li-> a.href)。
这是指令:
app.directive("testdir", function($location)
{
return {
restrict: 'A',
link: function(scope, element, attrs, controller) {
scope.$watch(function() { return $location.path(); }, function(path)
{
scope.$parent.firedEvents++;
path=path.substring(1);
if(path === element.children().attr("href").substring(2))
{
element.addClass("activeLink");
}
else
{
element.removeClass("activeLink");
}
})
}
};
和HTML部分:
<ul ng-app="test" ng-controller="MenuCtrl">
<li ng-repeat="link in menuDef" testdir><a href="{{link.url}}">{{link.linkName}}</a></li>
</ul>
整个示例on JsFiddle
如何重构?我很累 而且,我正朝着正确的方向前进?我觉得这件事可以用更轻松的方式完成,但也许我错了。
答案 0 :(得分:1)
首先,您的firedEvents
表示调用回调的次数,而不是实际更改位置的次数,这不是“路径更改事件的数量”!
您有20个(在您的小提琴中)范围正在观看位置更改,当您点击除当前活动的链接以外的其他链接时,位置更改,20个范围的全部将看到更改并调用他们的自己的 $watch
回调函数,每次调用回调都会增加firedEvents
,结果就是你所看到的:计数上升了到了20岁。
因此,如果您想让firedEvents
计算位置发生变化的次数,则应将scope.$parent.firedEvents++;
移至if
。但请记住,每次点击仍会导致回调函数被调用20次!
有很多方法可以达到你在这里尝试的相同效果,我有一个解决方案,你根本不需要深入研究指令。你走了:
HTML
<ul ng-controller="MenuCtrl">
<li ng-repeat="link in menuDef" ng-class="{activeLink: link.isActive}" ng-click="onLinkClick(link)"><a href="{{link.url}}">{{link.linkName}}</a>
</li>
</ul>
JS
app.controller("MenuCtrl", function ($scope, $location) {
var menugen = [];
for (var i = 1; i <= 20; i++) {
menugen.push({
linkName: "Link " + i,
url: "#/url" + i
});
}
$scope.menuDef = menugen;
var activeLink = null;
$scope.onLinkClick = function (link) {
if (activeLink && $scope.activeLink !== link) {
activeLink.isActive = false;
}
link.isActive = true;
activeLink = link;
};
});
我的第一次尝试是针对简单性,但正如@VirtualVoid指出的那样,它有一个巨大的缺点 - 它无法轻易处理来自菜单外部的位置变化。
在这里,我提出了一个更好的解决方案:向ul
添加指令,在那里观察位置更改,和在手表的回调函数中更新activeLink。通过这种方式,可以调用一个$watch
,并且只需调用一个回调即可进行单击。
JS
app.directive('menu', function ($location) {
return {
restrict: 'A',
controller: function ($scope, $location) {
var links = [];
this.registerLink = function (elem, path) {
links.push({
elem: elem,
path: path
});
};
$scope.$watch(function () {
return $location.path();
}, function (path) {
for (var i = 0; i < links.length; i++) {
if (path === links[i].path) {
links[i].elem.addClass('activeLink');
} else {
links[i].elem.removeClass('activeLink');
}
}
});
}
};
}).
directive("testdir", function () {
return {
restrict: 'A',
require: '^menu',
link: function (scope, element, attrs, controller) {
controller.registerLink(element, scope.link.url.substring(1));
}
};
});
HTML
<ul ng-app="test" ng-controller="MenuCtrl" menu>
<li ng-repeat="link in menuDef" testdir>
<a href="{{link.url}}">{{link.linkName}}</a>
</li>
</ul>
jsFiddle:http://jsfiddle.net/jaux/MFYCX/