【问题标题】:Reduce events in dynamic menu in AngularJS?减少AngularJS动态菜单中的事件?
【发布时间】:2013-06-17 16:11:51
【问题描述】:

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

目前自定义指令是我最薄弱的地方,我不知道如何重构所有这些。
我还尝试将指令放在菜单 (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>

整个例子on JsFiddle

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

【问题讨论】:

    标签: events angularjs menu watch


    【解决方案1】:

    首先,您的firedEvents 表示回调被调用了多少次,而不是位置实际更改了多少次,它不是“路径更改事件的数量”!

    您有 20 个(如在您的小提琴中)范围正在观察位置变化,当您单击当前活动链接以外的其他链接时,位置会发生变化,20 个范围中的 ALL 将看到变化并调用他们自己的$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/

    【讨论】:

    • 很好。谢谢。但是这个变体有一个缺点,它不监听路径变化,并且任何其他链接(菜单中不存在)对突出显示没有影响。看看这里:jsfiddle.net/rRgE5/2 顺便说一句,我做了一些重构,现在我有一个事件生产者和 20 个消费者(这是 li 标签),恕我直言,这要好得多。在这里:jsfiddle.net/eHzLe/3 不幸的是,这个也有问题。第一个“pathChange”事件发生得太早,而指令还没有监听事件。有任何想法吗? :)
    • 看起来我解决了最后一个问题。不知道,如果这正确与否。在这里:jsfiddle.net/eHzLe/4
    • @VirtualVoid 一个 $watch 调用肯定看起来更好,但是每次点击仍然会调用 20 个事件处理程序,这对性能不利。我将用更好的解决方案更新我的答案。
    • @VirtualVoid 更新了我的答案。
    • @VirtualVoid 我已经更新了小提琴来处理第一个位置更改问题
    猜你喜欢
    • 2014-12-25
    • 2016-07-21
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    相关资源
    最近更新 更多