【问题标题】:How do you detect the clearing of a "search" HTML5 input?您如何检测“搜索”HTML5 输入的清除?
【发布时间】:2011-02-27 22:53:45
【问题描述】:

在 HTML5 中,search 输入类型在右侧出现一个小 X,这将清除文本框(至少在 Chrome 中,也许在其他中)。有没有一种方法可以检测何时在 Javascript 或 jQuery 中单击此 X,而不是检测何时单击该框或进行某种位置单击检测(x 位置/y 位置)?

【问题讨论】:

标签: javascript jquery html events dom-events


【解决方案1】:

就我而言,我不想使用 JQuery,而且我的输入也是通用的,因此在某些情况下它可能是“搜索”类型,但并非总是如此。根据此处的其他答案之一,我能够稍微延迟地让它工作。基本上我想在单击输入时打开一个组件,但如果单击清除按钮则不是。

function onClick(e: React.MouseEvent<HTMLInputElement>) {
  const target = e.currentTarget;
  const oldValue = target.value;
  setTimeout(() => {
    const newValue = target.value;
    if (oldValue && !newValue) {
      // Clear was clicked so do something here on clear
      return;
    }

    // Was a regular click so do something here
  }, 50);
};

【讨论】:

    【解决方案2】:

    实际上,每当用户搜索或点击“x”时,都会触发一个“搜索”事件。这特别有用,因为它理解“增量”属性。

    现在,话虽如此,我不确定您是否可以区分单击“x”和搜索之间的区别,除非您使用“onclick”黑客。不管怎样,希望这会有所帮助。

    Dottoro web reference

    【讨论】:

    • 谢谢,除了单击“x”之外,无法确定search 事件何时发生。它似乎不会在keyupblur 或提交的表单上触发。但这值得被标记为答案。
    • search 事件应在用户按下 Enter 时触发。如果搜索框有incremental 属性,它也会在用户停止输入一秒钟时触发。
    • 仅供参考:在撰写此评论时,这仅适用于 Chrome。
    • IE11 会触发input 事件,但不会触发search 事件。
    • “搜索”事件是非标准的。见this。我不建议在没有 poly-fill 的情况下使用它。
    【解决方案3】:

    我想添加一个“迟到”的答案,因为我今天在changekeyupsearch 上苦苦挣扎,也许我最终发现的内容可能对其他人也有用。 基本上,我有一个 search-as-type 面板,我只是想对小 X 的按下做出适当的反应(在 Chrome 和 Opera 下,FF 没有实现它),并因此清除一个内容窗格。

    我有这个代码:

     $(some-input).keyup(function() { 
        // update panel
     });
    
     $(some-input).change(function() { 
        // update panel
     });
    
     $(some-input).on("search", function() { 
        // update panel
     });
    

    (它们是分开的,因为我想检查每个调用的时间和情况)。

    事实证明,Chrome 和 Firefox 的反应不同。 特别是,Firefox 将change 视为“对输入的每次更改”,而 Chrome 将其视为“当焦点丢失且内容发生更改时”。 因此,在 Chrome 上,“更新面板”功能被调用一次,在 FF 上,每次击键调用两次(keyup 一个,change 一个)

    此外,清除带有小 X(FF 下不存在)的字段会触发 Chrome 下的 search 事件:没有 keyup,没有 change

    结论?请改用input

     $(some-input).on("input", function() { 
        // update panel
     }
    

    它在我测试的所有浏览器下都具有相同的行为,对输入内容的每一次变化做出反应(用鼠标复制粘贴,自动完成和“X”包括在内)。

    【讨论】:

    • 谢谢洛伦佐...这很有帮助。
    • 太棒了,简直太棒了。非常感谢为我节省了试图弄清楚这一点的时间。
    • 似乎 Firefox 从那以后改变了它的行为?我使用 Firefox 42.0 进行了测试,它处理 change 事件就像 Chrome 一样,仅在 Enter 或焦点丢失时触发。
    • 我喜欢 on input 选项...不错!
    【解决方案4】:

    简单易读的简短解决方案

    哇,对于一个非常简单的问题,这里有一些非常复杂的答案。

    只需在您的搜索输入中添加'input' 的侦听器,当用户在输入中键入内容点击清除图标时,该侦听器将捕获。

    document.getElementById('searchInput').addEventListener('input', (e) => {
      console.log(`Input value: "${e.currentTarget.value}"`);
    })
    &lt;input id="searchInput" type="search" placeholder="Search" /&gt;

    如果你不能使用 ES6+,那么这里是为你转换的代码:

    document.getElementById('searchInput').addEventListener('input', function(e) { 
      // Yay! You make it in here when a user types or clicks the clear icon
    })` 
    

    【讨论】:

    • 感谢您,但它实际上并没有回答问题!是的,您可以使用您的方法来确定input 之后的值是否为空字符串,但您不一定确定有人点击了 X。如果您想在用户特别时执行某些操作点击X,你的答案没有解决它:)
    • @Jason 确实如此。当有人单击 X 时,该值为空,因此只需检查长度。 document.getElementById('searchInput').addEventListener('input', function (e) { let length = $(this).val().length; });
    【解决方案5】:

    似乎没有一个好的答案,所以我想我会添加另一个可能的解决方案。

    // Get the width of the input search field
    const inputWidth = $event.path[0].clientWidth;
    // If the input has content and the click is within 17px of the end of the search you must have clicked the cross
    if ($event.target.value.length && ($event.offsetX < inputWidth && $event.offsetX > inputWidth - 17)) {
        this.tableRows = [...this.temp_rows];
    }
    

    更新

    const searchElement = document.querySelector('.searchField');
    searchElement.addEventListener('click', event => {
      // Get the width of the input search field
      const inputWidth = $event.path[0].clientWidth;
      // If the input has content and the click is within 17px of the end of the search you must have clicked the cross
      if ($event.target.value.length && ($event.offsetX < inputWidth && $event.offsetX > inputWidth - 17)) {
        this.tableRows = [...this.temp_rows];
    }
    });
    

    【讨论】:

    • 你能给这个sn-p提供一些代码上下文吗? $event 指的是什么?还是if里面的代码?我认为您的解决方案可能会起作用,尽管我认为依赖浏览器特定的布局(即“X”在搜索框中的位置)存在脆弱性。
    • 嗨,马克,我已经用事件监听器更新了 sn-p。是的,这在浏览器中可能很脆弱/脆弱,但就像我说的那样,没有一个“好的”答案,这只是另一种方法。我个人认为这是需要上级解决的问题,例如在事件中添加对 clear 的引用。
    【解决方案6】:

    最初的问题是“我可以检测到点击‘x’吗?”。 这可以通过在search 事件中“牺牲” Enter 来实现。

    在输入框生命周期的不同时间触发了许多事件 类型搜索:inputchangesearch。其中一些在某些情况下重叠。默认情况下,“搜索”会在您按 Enter 和按“x”时触发;使用incremental 属性,它也会在您添加/删除任何字符时触发,并以 500 毫秒的延迟捕获多个更改并避免压倒听众。 问题是,search 生成了一个带有 input.value == "" 的模棱两可的事件,因为它可以通过三种方式变为空:(1)“用户按下了‘x’”,(2)“用户按下了 Enter 键没有文本的输入”,或 (3) “用户编辑输入(退格、剪切等)直到输入变为空,最终incremental 触发了空输入的search 事件”。

    消除歧义的最佳方法是将 Enter 排除在等式之外,并且仅在按下“x”时才触发search。您可以通过完全抑制 Enter 按键来实现这一点。我知道这听起来很傻,但是您可以通过keydown 事件(您也可以在其中进行抑制)、input 事件或change 事件在更好的受控情况下恢复 Enter 行为。 search 唯一的独特之处是“x”点击。

    如果您不使用incremental,这将消除歧义。如果您使用incremental,问题是,您可以通过input 事件实现大部分incremental 行为(您只需要重新实现500ms 去抖动逻辑)。因此,如果您可以删除incremental(或可选地使用input 模拟它),则此问题由searchkeydownevent.preventDefault() 的组合来回答。如果您不能删除incremental,您将继续存在上述一些歧义。

    这里有一段代码 sn-p 展示了这一点:

    inpEl = document.getElementById("inp");
    monitor = document.getElementById("monitor");
    
    function print(msg) {
      monitor.value += msg + "\n";
    }
    
    function searchEventCb(ev) {
      print(`You clicked the 'x'. Input value: "${ev.target.value}"`);
    }
    
    function keydownEventCb(ev) {
        if(ev.key == "Enter") {
        print(`Enter pressed, input value: "${ev.target.value}"`);
            ev.preventDefault();
        }
    }
    
    inpEl.addEventListener("search", searchEventCb, true);
    inpEl.addEventListener("keydown", keydownEventCb, true);
    <input type="search" id="inp" placeholder="Type something">
    
    <textarea id="monitor" rows="10" cols="50">
    </textarea>

    在这个简单的 sn-p 中,您已将 search 变成了一个专用事件,该事件仅在您按“x”时触发,并回答了最初发布的问题。您可以使用 keydown 跟踪 input.value 以输入。

    我个人更喜欢在按下回车键的时候放一个ev.target.blur()(模拟输入框失去焦点),并监控change事件来跟踪input.value(而不是监控input.value通过keydown)。通过这种方式,您可以统一跟踪 input.value 的焦点变化,这很有用。它对我有用,因为只有在 input.value 实际发生变化时我才需要处理该事件,但它可能不适用于所有人。

    这是带有blur() 行为的 sn-p(现在即使您手动将焦点从输入框移开,您也会收到一条消息,但请记住,只有在实际发生更改时才会看到更改消息):

    inpEl = document.getElementById("inp");
    monitor = document.getElementById("monitor");
    
    function print(msg) {
      monitor.value += msg + "\n";
    }
    
    function searchEventCb(ev) {
      print(`You clicked the 'x'. Input value: "${ev.target.value}"`);
    }
    
    function changeEventCb(ev) {
      print(`Change fired, input value: "${ev.target.value}"`);
    }
    
    function keydownEventCb(ev) {
        if(ev.key == "Enter") {
            ev.target.blur();
            ev.preventDefault();
        }
    }
    
    inpEl.addEventListener("search", searchEventCb, true);
    inpEl.addEventListener("change", changeEventCb, true);
    inpEl.addEventListener("keydown", keydownEventCb, true);
    <input type="search" id="inp" placeholder="Type something">
    
    <textarea id="monitor" rows="10" cols="50">
    </textarea>

    【讨论】:

      【解决方案7】:

      我的解决方案基于onclick 事件,我在事件触发的确切时间检查输入的值(确保它不为空),然后等待 1 毫秒并再次检查该值;如果它为空,则表示已单击清除按钮,而不仅仅是输入字段。

      这是一个使用 Vue 函数的示例:

      HTML

      <input
        id="searchBar"
        class="form-input col-span-4"
        type="search"
        placeholder="Search..."
        @click="clearFilter($event)"
      />
      

      JS

      clearFilter: function ($event) {
        if (event.target.value !== "") {
          setTimeout(function () {
            if (document.getElementById("searchBar").value === "")
              console.log("Clear button is clicked!");
          }, 1);
        }
        console.log("Search bar is clicked but not the clear button.");
      },
      

      【讨论】:

      • 不错的方法,但它不起作用,按预期触发清除按钮
      【解决方案8】:

      对我来说,单击 X 应该算作更改事件是有道理的。我已经设置了 onChange 事件来做我需要做的事情。所以对我来说,解决方法是简单地做这个 jQuery 行:

      $('#search').click(function(){ $(this).change(); });
      

      【讨论】:

      • 如果您希望在按下清除按钮时触发此功能,您还可以添加对输入值的检查,下面是 Jannis 的评论:stackoverflow.com/questions/2977023/…if (this.value === "") { ... }
      【解决方案9】:
      document.querySelectorAll('input[type=search]').forEach(function (input) {
         input.addEventListener('mouseup', function (e) {
                      if (input.value.length > 0) {
                          setTimeout(function () {
                              if (input.value.length === 0) {
                                  //do reset action here
                              }
                          }, 5);
                      }
                  });
      }
      

      ECMASCRIPT 2016

      【讨论】:

        【解决方案10】:

        这是实现这一目标的一种方法。您需要在 html 中添加增量属性,否则它将不起作用。

        window.onload = function() {
          var tf = document.getElementById('textField');
          var button = document.getElementById('b');
          button.disabled = true;
          var onKeyChange = function textChange() {
            button.disabled = (tf.value === "") ? true : false;
          }
          tf.addEventListener('keyup', onKeyChange);
          tf.addEventListener('search', onKeyChange);
        
        }
        <input id="textField" type="search" placeholder="search" incremental="incremental">
        <button id="b">Go!</button>

        【讨论】:

          【解决方案11】:

          基于js的事件循环,清除按钮上的click会触发输入上的search事件,所以下面的代码将按预期工作:

          input.onclick = function(e){
            this._cleared = true
            setTimeout(()=>{
              this._cleared = false
            })
          }
          input.onsearch = function(e){
            if(this._cleared) {
              console.log('clear button clicked!')
            }
          }
          

          上面的代码,onclick事件预定了一个this._cleared = false事件循环,但是事件总是在onsearch事件之后运行,所以可以稳定的查看this._cleared 状态判断用户是否刚刚点击了X 按钮,然后触发了onsearch 事件。

          这几乎适用于所有条件粘贴文本,具有增量属性,ENTER/ESC键按等。

          【讨论】:

            【解决方案12】:

            我知道这是一个老问题,但我一直在寻找类似的东西。确定何时单击“X”以清除搜索框。这里的答案都没有帮助我。一个很接近,但当用户点击“输入”按钮时也会受到影响,它会触发与单击“X”相同的结果。

            我在另一篇文章中找到了这个答案,它对我来说很完美,只有在用户清除搜索框时才会触发。

            $("input").bind("mouseup", function(e){
               var $input = $(this),
               oldValue = $input.val();
            
               if (oldValue == "") return;
            
               // When this event is fired after clicking on the clear button
               // the value is not cleared yet. We have to wait for it.
               setTimeout(function(){
                 var newValue = $input.val();
            
                  if (newValue == ""){
                     // capture the clear
                     $input.trigger("cleared");
                  }
                }, 1);
            });
            

            【讨论】:

              【解决方案13】:

              点击TextField cross button(X) onmousemove() 被触发,我们可以使用这个事件来调用任何函数。

              <input type="search" class="actInput" id="ruleContact" onkeyup="ruleAdvanceSearch()" placeholder="Search..." onmousemove="ruleAdvanceSearch()"/>
              

              【讨论】:

                【解决方案14】:

                完整的解决方案在这里

                这将在单击搜索 x 时清除搜索。 要么 当用户按回车时,将调用搜索 API。 可以使用额外的 esc keyup 事件匹配器进一步扩展此代码。但这应该可以做到。

                document.getElementById("userSearch").addEventListener("search", 
                function(event){
                  if(event.type === "search"){
                    if(event.currentTarget.value !== ""){
                      hitSearchAjax(event.currentTarget.value);
                    }else {
                      clearSearchData();  
                    }
                  }
                });
                

                干杯。

                【讨论】:

                  【解决方案15】:

                  我相信这是唯一只有在单击 x 时才会触发的答案。

                  但是,这有点 hacky,ggutenberg 的答案对大多数人都有效。

                  $('#search-field').on('click', function(){
                    $('#search-field').on('search', function(){
                      if(!this.value){
                        console.log("clicked x");
                        // Put code you want to run on clear here
                      }
                    });
                    setTimeout(function() {
                      $('#search-field').off('search');
                    }, 1);
                  });
                  

                  '#search-field' 是用于输入的 jQuery 选择器。使用'input[type=search]' 选择所有搜索输入。通过单击该字段后立即检查搜索事件(Pauan 的答案)来工作。

                  【讨论】:

                    【解决方案16】:

                    试试这个,希望对你有帮助

                    $("input[name=search-mini]").on("search", function() {
                      //do something for search
                    });
                    

                    【讨论】:

                      【解决方案17】:

                      搜索或 onclick 有效...但我发现的问题与旧版浏览器有关 - 搜索失败。许多插件(jquery ui 自动完成或花式树过滤器)都有模糊和焦点处理程序。将此添加到自动完成输入框中对我有用(使用 this.value == "" 因为它评估速度更快)。当您点击小“x”时,模糊然后焦点将光标保持在框中。

                      PropertyChange 和输入适用于 IE 10 和 IE 8 以及其他浏览器:

                      $("#INPUTID").on("propertychange input", function(e) { 
                          if (this.value == "") $(this).blur().focus(); 
                      });
                      

                      对于 FancyTree 过滤器扩展,您可以使用重置按钮并强制其点击事件,如下所示:

                      var TheFancyTree = $("#FancyTreeID").fancytree("getTree");
                      
                      $("input[name=FT_FilterINPUT]").on("propertychange input", function (e) {
                          var n,
                          leavesOnly = false,
                          match = $(this).val();
                          // check for the escape key or empty filter
                          if (e && e.which === $.ui.keyCode.ESCAPE || $.trim(match) === "") {
                              $("button#btnResetSearch").click();
                              return;
                          }
                      
                          n = SiteNavTree.filterNodes(function (node) {
                              return MatchContainsAll(CleanDiacriticsString(node.title.toLowerCase()), match);
                              }, leavesOnly);
                      
                          $("button#btnResetSearch").attr("disabled", false);
                          $("span#SiteNavMatches").text("(" + n + " matches)");
                      }).focus();
                      
                      // handle the reset and check for empty filter field... 
                      // set the value to trigger the change
                      $("button#btnResetSearch").click(function (e) {
                          if ($("input[name=FT_FilterINPUT]").val() != "")
                              $("input[name=FT_FilterINPUT]").val("");
                          $("span#SiteNavMatches").text("");
                          SiteNavTree.clearFilter();
                      }).attr("disabled", true);
                      

                      应该能够适应大多数用途。

                      【讨论】:

                        【解决方案18】:

                        绑定search-事件搜索框如下-

                        $('input[type=search]').on('search', function () {
                            // search logic here
                            // this function will be executed on click of X (clear button)
                        });
                        

                        【讨论】:

                        【解决方案19】:

                        发现这篇文章,我意识到它有点旧,但我认为我可能会有答案。这将处理单击十字、退格和按 ESC 键。我相信它可能会写得更好——我对 javascript 还是比较陌生。这是我最终做的 - 我使用的是 jQuery (v1.6.4):

                        var searchVal = ""; //create a global var to capture the value in the search box, for comparison later
                        $(document).ready(function() {
                          $("input[type=search]").keyup(function(e) {
                            if (e.which == 27) {  // catch ESC key and clear input
                              $(this).val('');
                            }
                            if (($(this).val() === "" && searchVal != "") || e.which == 27) {
                              // do something
                              searchVal = "";
                            }
                            searchVal = $(this).val();
                          });
                          $("input[type=search]").click(function() {
                            if ($(this).val() != filterVal) {
                              // do something
                              searchVal = "";
                            }
                          });
                        });
                        

                        【讨论】:

                        • 看起来 filterVal 没有定义
                        【解决方案20】:

                        根据 Pauan 的回答,这很有可能。例如。

                        <head>
                            <script type="text/javascript">
                                function OnSearch(input) {
                                    if(input.value == "") {
                                        alert("You either clicked the X or you searched for nothing.");
                                    }
                                    else {
                                        alert("You searched for " + input.value);
                                    }
                                }
                            </script>
                        </head>
                        <body>
                            Please specify the text you want to find and press ENTER!
                            <input type="search" name="search" onsearch="OnSearch(this)"/>
                        </body>
                        

                        【讨论】:

                        • 对我来说,change 事件基本上直到blur 才会触发。只需在 Chrome 的搜索字段中单击 (x) 似乎不会触发任何事件。经过进一步调查(并阅读下面的 cmets),我得到了 click 为我工作。所以$("input[type='search']").bind('click', function(e) { if ( this.value=="") {//this just cleared!} }); 对我有用
                        • 但是$("input[type='search']").bind('click', function(e) { if ( this.value=="") {//this just cleared!} });也会在用户点击输入框时触发。
                        【解决方案21】:

                        您似乎无法在浏览器中访问此内容。搜索输入是 Cocoa NSSearchField 的 Webkit HTML 包装器。取消按钮似乎包含在浏览器客户端代码中,而包装器中没有可用的外部引用。

                        来源:

                        看起来你必须通过点击鼠标位置来解决这个问题:

                        $('input[type=search]').bind('click', function(e) {
                          var $earch = $(this);
                          var offset = $earch.offset();
                        
                          if (e.pageX > offset.left + $earch.width() - 16) { // X button 16px wide?
                            // your code here
                          }
                        });
                        

                        【讨论】:

                        • 好吧,这很糟糕。也许我会选择 B 计划,如果输入现在为空,它会在 onClick 上运行一个事件......也许把它放在一个 25 毫秒的计时器上
                        • @Jason 是的,您可以使用我在上面放置的代码仅在单击发生在 X 所在的区域时运行它。除了像你说的那样检查输入是否为空之外就足够了
                        猜你喜欢
                        • 2016-11-15
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-02-14
                        • 1970-01-01
                        • 2019-03-24
                        • 1970-01-01
                        • 2021-08-29
                        相关资源
                        最近更新 更多