jQuery figuring out if parent has lost 'focus'

后端 未结 7 1897
小鲜肉
小鲜肉 2020-12-16 05:39

I\'m stuck on figuring out the logic to make a drop down menu keyboard accessible.

The HTML is structured as such (extra class names used for clarity):



        
相关标签:
7条回答
  • 2020-12-16 06:12

    I came up with this recipe (vanilla JS) which does exactly what the OP is asking for (provide a way to listen to "focus moves outside a container element") and is generic enough to work for any use case.

    In OP's example, it would be used like this:

    for (const primaryMenu of Array.from($('.primaryMenuItem'))) {
      onFocusOutsideOf(primaryMenu, () => closeMenu(primaryMenu));
    }
    

    Here is the code for onFocusOutsideOf:

    /**
     * Invokes `callback` when focus moves outside the given element's DOM
     * subtree.
     *
     * Returns a function that can optionally be called to remove the
     * event listener.
     */
    function onFocusOutsideOf(container, callback) {
      const eventListener = () => {
        // setTimeout is used to allow `document.activeElement` to
        // be updated to the newly focused element. This is needed
        // since the 'focusout' event within the container happens
        // before the 'focus' event on the new element.
        setTimeout(() => {
          if (!isDescendantOf(container, document.activeElement)) {
            callback();
          }
        })
      };
      container.addEventListener('focusout', eventListener);
    
      return function unsubscribe() {
        container.removeEventListener('focusout', eventListener);
      }
    }
    
    /**
     * Utility function which returns whether a given DOM element
     * has another DOM element as a descendant.
     */
    function isDescendantOf(ancestor: Element, potentialDescendant: Element) {
      let parent = potentialDescendant.parentNode;
      while (parent) {
        if (parent === ancestor) return true;
        parent = parent.parentElement;
      }
      return false;
    }
    
    0 讨论(0)
  • 2020-12-16 06:14

    This helped me... http://plugins.jquery.com/project/focus

    It will detect if you're still within the parent automatically. It basically changes jQuery focusout to work this way instead, which I feel is how it should work.

    <div class="parent">
       <input type="text" />
       <input type="text" />
    </div>
    
    $('#parent').focusout(function () {
        console.log('focusout of parent');
    });
    

    I don't see why pressing tab to move textfield between the child elements should trigger focusout on the parent because you're still within that parent. Something must be happening that takes you out of it for a moment and I suspect it's a bug... anyone with me on this? Well anyway the plugin above fixes it. Just include it before your code to 'fix' this. Would love someone to explain why this isn't a bug if it isn't.

    Thanks, Dom

    0 讨论(0)
  • 2020-12-16 06:18

    Use the new jquery 1.4 functions: focusin and focusout instead of blur and focus. Here's how focusout differs:

    The focusout event is sent to an element when it, or any element inside of it, loses focus. This is distinct from the blur event in that it supports detecting the loss of focus from parent elements (in other words, it supports events bubbling).

    0 讨论(0)
  • 2020-12-16 06:20

    I had a similar issue... I created a jsfiddle to determine when a parent fieldset loses focus and then calling a function. It could certainly be optimized, but it's a start.

    http://jsfiddle.net/EKhLc/10/

    function saveFields() {
      $.each($('fieldset.save'),function(index, value) {
        // WHERE THE POST WOULD GO
        alert('saving fieldset with id '+ value.id);
        $(value).removeClass('save');
      });
    
    }
    $('.control-group').focusin(function(){
      var thefield = $(this).parent('fieldset');
      if (!thefield.hasClass('active')) {
        if($('fieldset.active').length > 0){
    
          $('fieldset.active').removeClass('active').addClass('save');
          saveFields();
          }
        thefield.addClass('active');
        } else {
            console.log('already active');
        }
    });
    
    0 讨论(0)
  • 2020-12-16 06:27

    How about if you do the following:

    $('#link_A_id, #link_A_id > *').focusout(function () {
        if ($(document.activeElement).closest('#link_A_id').length == 0)
            //focus is out of link A and it's children
    });
    
    0 讨论(0)
  • 2020-12-16 06:30

    You can use event bubbling to check what has focus on the focusin event. I had success with the following code:

    
    $("li:has(ul.popUpMenu)").focusin(function(e) {
        $(this).children().fadeIn('slow');
      });
      $('body').focusin(function(e) {
        if (!$(e.target).parent().is('ul.popUpMenu li')) {
          $('ul.popUpMenu').fadeOut('slow');
        }
      });
    
    

    You could(should) probably make it more optimized, but it works.

    0 讨论(0)
提交回复
热议问题