1

我已经建立了一个动态菜单,它也有突出显示。
现在我遇到了一个问题,路径更改事件的数量随着菜单元素的增加而增加。
当然,这是对菜单的每个元素应用指令的结果。

目前自定义指令是我最薄弱的地方,我不知道如何重构这一切。
我还尝试将指令放在菜单 (ul) 的根元素中以便注册一次 watch,但坚持访问深层子元素 (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>

JsFiddle 上的完整示例

如何重构?我累极了。
而且,我正朝着正确的方向前进?我有一种感觉,这件事可以以更简单的方式完成,但也许我错了。

4

1 回答 1

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

jsFiddle

更新

我的第一次尝试是针对简单性,但正如@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/

于 2013-06-17T03:04:19.627 回答