【问题标题】:AngularJS directive toggle menu preventing default for other directiveAngularJS 指令切换菜单阻止其他指令的默认设置
【发布时间】:2013-08-11 12:28:53
【问题描述】:

所以我为 AngularJS 中的切换(下拉)菜单做了一个指令。我将指令用于页面中的多个项目,但我有一个小问题。当一个项目打开并单击另一个项目时,我希望前一个项目关闭。 event.preventDefault 和 event.stopPropagation 停止前一项的事件并且不会关闭它。有想法该怎么解决这个吗?有没有办法只在范围内停止事件?

app.directive('toggleMenu', function ($document) {
    return {
        restrict: 'CA',
        link: function (scope, element, attrs) {
            var opened = false;
            var button = (attrs.menuButton ? angular.element(document.getElementById(attrs.menuButton)) : element.parent());
            var closeButton = (attrs.closeButton ? angular.element(document.getElementById(attrs.closeButton)) : false);

            var toggleMenu = function(){
                (opened ? element.fadeOut('fast') : element.fadeIn('fast'));
            };

            button.bind('click', function(event){
                event.preventDefault();
                event.stopPropagation();
                toggleMenu();
                opened = ! opened;
            });

            element.bind('click', function(event){
                if(attrs.stayOpen && event.target != closeButton[0]){
                    event.preventDefault();
                    event.stopPropagation();
                }
            });

            $document.bind('click', function(){
                if(opened){
                    toggleMenu();
                    opened = false;
                }
            });


        }
    };

这是一个小提琴:http://jsfiddle.net/JknUJ/5/ 按钮打开内容,在 div 外部单击时内容应关闭。当点击按钮 2 时,内容 1 并没有关闭。

【问题讨论】:

标签: events angularjs directive


【解决方案1】:

基本思想是您需要在所有下拉子菜单之间共享状态,因此当其中一个显示时,所有其他子菜单都将被隐藏。存储状态(例如打开或关闭)的最简单方法是... CSS 类!

我们将创建一对指令 - 一个用于菜单,另一个用于 sumbenu。比divs 更有表现力。

这里是标记。

<menu>
  <submenu data-caption="Button 1">
    Content 1
  </submenu>
  <submenu data-caption="Button 2">
    Content 2
  </submenu>
</menu>

看看它的可读性如何!对指令表示感谢:

plunker.directive("menu", function(){
    return {
        restrict : "E",
        scope : {},
        transclude : true,
        replace : true,
        template : "<div class='menu' data-ng-transclude></div>",
        controller : function ($scope, $element, $attrs, $transclude){
            $scope.submenus = [];

            this.addSubmenu = function (submenu) {
                $scope.submenus.push(submenu);
            }

            this.closeAllSubmenus = function (doNotTouch){
                angular.forEach($scope.submenus, function(submenu){
                    if(submenu != doNotTouch){
                        submenu.close();    
                    }
                })
            }
        }
    }
});

plunker.directive("submenu", function(){
    return {
        restrict : "E",
        require : "^menu",
        scope : {
            caption : "@"
        },
        transclude : true,
        replace : true,
        template : "<div class='submenu'><label>{{caption}}</label><div class='submenu-content' data-ng-transclude></div></div>",
        link : function ($scope, $iElement, $iAttrs, menuController) {
            menuController.addSubmenu($scope);

            $iElement.bind("click", function(event){
                menuController.closeAllSubmenus($scope);
                $iElement.toggleClass("active");
            });

            $scope.close = function (){
                $iElement.removeClass("active");
            }
        }
    }
});

请注意,我们将它们限制为 HTML 元素 (restrict : "E")。 submenu 需要嵌套在menu (require : "^menu") 中,这允许我们将菜单控制器注入submenu 的链接函数。 transcludereplace 控制原始标记在编译后的 HTML 输出中的位置(replace=true 表示原始标记将被编译替换,transclude 将部分原始标记插入到编译输出中)。

完成此操作后,我们只需说菜单 关闭所有子菜单! 并且菜单会遍历子菜单,强制它们关闭。

我们在addSubmenu 函数中将子代添加到menu 控制器。它在submenus 链接函数中调用,因此每个已编译的子菜单实例都将自己添加到menu。现在,关闭所有 submenus 就像遍历所有孩子一样简单,这是由 closeAllSubmenusmenu 控制器中完成的。

Here 是一个完整的 Plunker。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-27
    • 2016-12-08
    • 2014-03-08
    • 2015-04-19
    • 1970-01-01
    • 2015-10-28
    • 2015-06-24
    • 1970-01-01
    相关资源
    最近更新 更多