2

そこで、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 は閉じません。

4

1 に答える 1

2

基本的な考え方は、すべてのドロップダウン サブメニュー間で状態を共有する必要があるため、そのうちの 1 つが表示されると、他のすべてが非表示になるということです。状態 (open または closed など) を保存する最も簡単な方法は... CSS クラスです!

menu 用と 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ネストする必要があります。これにより、メニュー コントローラーをのリンク関数に挿入できます。コンパイルされた HTML 出力内の元のマークアップの位置を制御します (元のマークアップがコンパイルされたものに置き換えられ、元のマークアップの一部がコンパイルされた出力に挿入されることを意味します)。menurequire : "^menu"submenutranscludereplacereplace=truetransclude

これが終わったら、すべての子メニューを閉じるように menu と言うだけです! メニューはサブメニューを繰り返し処理し、それらを強制的に閉じます。

menu関数のコントローラーに子を追加していaddSubmenuます。これはsubmenus リンク関数で呼び出されるため、コンパイルされた submenu のすべてのインスタンスが に追加されますmenusubmenusこれで、すべての子を反復処理するのと同じくらい簡単にすべてを閉じることができます。これはコントローラー内で実行さcloseAllSubmenusれます。menu

これは完全な Plunker です

于 2013-08-11T21:38:26.710 に答える