Seems that onBlur of one element is “overriding” the onclick of another

后端 未结 3 1655
無奈伤痛
無奈伤痛 2020-12-11 05:58

I have two elements:



        
相关标签:
3条回答
  • 2020-12-11 06:26

    The accepted answer will work as a quick fix, but by relying on a setTimeout, you assume that the user will only keep clicking down for less than n milliseconds before they release (just picture someone hesitating on a click). To be more sure that the click will go through, you could set a longer timeout, but that means your hide-able element will stay visible that much longer after the blur.

    So let's look at the root of the problem.

    The click event failing to go through is a result of the events being fired in the following order:

    1. mousedown
    2. blur
    3. mouseup
    4. click

    So by the time the mouseup/click events are ready to fire, the blur listener has been called and the element you had once been hovering over has already disappeared.

    Here's a general fix (based on the fact that the mousedown event fires first) that should work:

    var searchEl = $('#search');
    var listEl = $('#dropdown');
    var keepListOpen = false;
    
    searchEl
      .on('focus', function() {
        listEl.show();
      })
      .on('blur', function() {
        // Hide the list if the blur was triggered by anything other than
        //  one of the list items
        if (!keepListOpen) {
          listEl.hide();
        }
      });
    
    listEl.find('li')
      .on('mousedown', function(event) {
        // Keep the list open so the onClick handler can fire
        keepListOpen = true;
      })
      .on('click', function(event) {
        // Proof that the list item was clicked
        alert('clicked option');
      });
    
    $(window).on('mouseup', function(event) {
      // Return the keepListOpen setting to its default and hide the list
    
      // *NOTE* We could have tied this handler to the list items, 
      // but it wouldn't have fired if a mousedown happened on a
      // list item and then the user dragged the mouse pointer 
      // out of the area (or out of the window)
      if (keepListOpen) {
        listEl.hide();
        keepListOpen = false;
      }
    });
    
    // Bind to `window.top` if your page might be displayed in an iframe
    // $(window.top).on('mouseup', function(event) {
    //  if (keepListOpen) {
    //    listEl.hide();
    //    keepListOpen = false;
    //  }
    //});
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <input id="search" type="text" autocomplete="off" placeholder="Click Here">
    
    <ul id="dropdown" style="display: none;">
      <li>Click Me 1</li>
      <li>Click Me 2</li>
      <li>Click Me 3</li>
    </ul>

    0 讨论(0)
  • 2020-12-11 06:33

    I think you are short on answers because your question is confusing. Presumably you have an input that, when focussed, shows a list of suggestions based on the characters entered into the input.

    If the user uses the cursor to select an item, then I suppose the blur event of the input fires before the click event of the div and the the div is set to display:none before the click fires, and hence misses the div.

    The fix is to call the onblur listener after a short timeout, so:

      <input ... onblur="setTimeout(function(){hideSelect();}, 100);">
    

    Test in a number of browsers, you may need to set the timeout to 200ms or so. It doesn't matter if there's a short, visible delay after the blur event before the suggestions disappear (i.e. a bit too long is better than a bit too short).

    Make sure the suggestions don't obscure anything important on the page or users may find them more of a hindrance than a help. :-)

    0 讨论(0)
  • 2020-12-11 06:45

    The solution is so simple - you just need to use the mousedown event instead of the click event.

    The order of the events is:

    1. mousedown - of the div element which you wanted to use in its click event

    2. blur - of the other element, that your logic is inside.

    3. click - of the div element

    You can save a flag in the mousedown event and then, in the onBlur logic, check the flag to know if need to call the click function manually

    <input onblur="do();" />
    <button type="submit" (mousedown)="submitDown()" (click)="save()"></button>
    
    submitDown() {
      saveCalled = true;
    }
    do(){
    ....
      if(saveCalled){
         saveCalled = false;
         save();
      }
    }
    
    0 讨论(0)
提交回复
热议问题