减少AngularJS中动态菜单中的事件?

时间:2013-06-16 23:09:55

标签: events angularjs menu watch

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

此刻的自定义指令是我最弱的地方,我不知道如何重构这一切。
我还尝试将指令放在菜单(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

如何重构?我很累 而且,我正朝着正确的方向前进?我觉得这件事可以用更轻松的方式完成,但也许我错了。

1 个答案:

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

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/