webcomponents - hide dropdown menu on [removed]

后端 未结 2 1029
长发绾君心
长发绾君心 2021-01-27 10:48

dropdown menu is created in shadowDOM

almost perfect, but the problem is how to hide the dropdown menu when click on any where else in window

class NavC         


        
2条回答
  •  一向
    一向 (楼主)
    2021-01-27 10:56

    An unrelated suggestion: you should probably separate .dropdown into its own component and assign the 'click' event listeners in its 'constructor' or 'connectedCallback'.

    The best idea for your problem is to

    ddc[index].addEventListener('click', e => {
        if(dd[index].classList.contains('show')) {
            dd[index].classList.remove('show');
            window.removeEventListener('click', handleDropdownUnfocus, true);
        }
        else {
            dd[index].classList.add('show');
            window.addEventListener('click', handleDropdownUnfocus, true);
        }
    });
    

    Note: I use addEventListener with true, such that the event happens at capture, so that it's will not happen immediately after the .dropdown click handler.

    And your handleDropdownUnfocus will look like

    function handleDropdownUnfocus(e) {
        Array.from(document.querySelectorAll('app-nav')).forEach(function(appNav) {
            Array.from(appNav.shadowRoot.querySelectorAll('.dropdown')).forEach(function(dd) {
                dd.classList.remove('show');
            });
        });
        window.removeEventListener('click', handleDropdownUnfocus, true);
    }
    

    There's a problem with this solution though, that if you click on the menu item again after opening it, it will call both .dropdown and window handlers, and the net result will be that the dropdown will remain open. To fix that, you would normally add a check in handleDropdownUnfocus:

    if(e.target.closest('.dropdown')) return;
    

    However, it will not work. Even when you click on .dropdown, your e.target will be app-nav element, due to Shadow DOM. Which makes it more difficult to do the toggling. I don't know how you'd address this issue, maybe you can come up with something fancy, or stop using Shadow DOM.

    Also, your code has some red flags... For example, you use let keyword in your for-loop, which is fine. The support for let is very limited still, so you're more likely going to transpile. The transpiler will just change every let to var. However, if you use var in your loop, assigning the handlers in a loop like that will not work anymore, because index for every handler will refer to the last dropdown (because index will now be global within the function's context and not local for every loop instance).

提交回复
热议问题