how to remove search box when click outside element but not remove when click inside (special input and button)

huangapple go评论54阅读模式
英文:

how to remove search box when click outside element but not remove when click inside (special input and button)

问题

I have created a search box like this code.
当我点击搜索框外部时,我希望它关闭。
但是在我的代码中,当我点击用于输入或搜索框内部的内容时,搜索框会关闭。

Could you guide me to where my code is wrong?
您能指导我代码哪里出错吗?

Thank you in advance for your cooperation.
提前感谢您的合作。

英文:

I have created a search box like this code.
When I click outside the search box, I want it to close.
But in my code, when I click on Input for writing or the content inside the search box, the search box closes.

Could you guide me to where my code is wrong?

Thank you in advance for your cooperation.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const searchIcon = document.querySelector(&quot;#searchIcon&quot;);
const searchContent = document.querySelector( &quot;.searchForm--content&quot;);
searchIcon.addEventListener(&quot;click&quot;, function() {
    searchContent.classList.toggle(&quot;active&quot;);
});


window.onclick = function(event) {
  if (!event.target.matches(&#39;#searchIcon&#39;) ) {	  
   var searchContent=document.querySelector(&quot;.searchForm--content&quot;);
	 var searchFormInput=document.querySelector(&quot;searchForm--content.active &gt; .searchForm--content__input&quot;);
	 if(searchContent.classList.contains(&#39;active&#39;) &amp;&amp; !event.target.contains(searchFormInput)){
		  searchContent.classList.remove(&#39;active&#39;);
	  }
  }
}

<!-- language: lang-css -->

.searchForm--content{
	position: relative
}

#searchIcon{
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

.searchForm &gt; img {
  cursor: pointer;
  width: auto;
  vertical-align: middle;
}

.searchForm--content{
  border: 1px solid blue;
  border-radius: 10px;
  padding-inline:0.75rem;
  color: black;
  position: absolute;
  left: 12px;
  width: 40%;
  top: 70px;
  display: none;
  align-items: center;
  justify-content: space-between;
}
.searchForm--content.active {
  display: flex;
} 

.searchForm--content .btn{
	position: absolute;
	left:0.2rem;
	top:50%;
	transform: translatey(-50%);
}
.searchForm--content input[type=&quot;search&quot;]{
	width: 65%;
	border: 1px solid red;
	padding: 1rem 0.5rem;
	color: black;
  margin-left: auto;
}

<!-- language: lang-html -->

&lt;form class=&quot;searchForm&quot; role=&quot;search&quot;&gt;
  &lt;div id=&quot;searchIcon&quot;&gt;my icon search&lt;/div&gt;
  
	&lt;div class=&quot;searchForm--content&quot; id=&quot;my-box&quot;&gt;
		&lt;input type=&quot;search&quot; placeholder=&quot;search&quot; name=&quot;s&quot; inputmode=&quot;search&quot;  class=&quot;searchForm--content__input&quot; /&gt; 
		&lt;button type=&quot;submit&quot; class=&quot;btn btn--blue&quot; &gt;submit&lt;/button&gt;
	&lt;/div&gt;
&lt;/form&gt;

<!-- end snippet -->

答案1

得分: 1

您的问题是,每当您单击一个元素时,click 事件不仅会触发该元素上的事件处理程序,还会触发其所有父元素上的事件。要阻止 click 事件传播到其他事件处理程序,您可以调用 event.stopImmediatePropagation() 方法。只需像这样使用它:

const searchIcon = document.querySelector("#searchIcon");
const searchContent = document.querySelector(".searchForm--content");
searchIcon.addEventListener("click", function() {
  searchContent.classList.toggle("active");
});

searchContent.addEventListener('click', function(event) {
  event.stopImmediatePropagation();
});

window.onclick = function(event) {
  if (!event.target.matches('#searchIcon')) {
    var searchContent = document.querySelector(".searchForm--content");
    var searchFormInput = document.querySelector("searchForm--content.active > .searchForm--content__input");
    if (searchContent.classList.contains('active') && !event.target.contains(searchFormInput)) {
      searchContent.classList.remove('active');
    }
  }
}

您的 HTML、CSS 和 JavaScript 代码已经被翻译完毕。

英文:

Your issue is that whenever you click on an element, the click event fires for not only that element, but also all of its parent elements. So, a click event handler on window will fire for any click anywhere on the page.

To stop a click event from going to other event handlers like this, you can call the event.stopImmediatePropagation() method. Just use it like this:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const searchIcon = document.querySelector(&quot;#searchIcon&quot;);
const searchContent = document.querySelector(&quot;.searchForm--content&quot;);
searchIcon.addEventListener(&quot;click&quot;, function() {
  searchContent.classList.toggle(&quot;active&quot;);
});

searchContent.addEventListener(&#39;click&#39;, function(event) {
  event.stopImmediatePropagation();
});

window.onclick = function(event) {
  if (!event.target.matches(&#39;#searchIcon&#39;)) {
    var searchContent = document.querySelector(&quot;.searchForm--content&quot;);
    var searchFormInput = document.querySelector(&quot;searchForm--content.active &gt; .searchForm--content__input&quot;);
    if (searchContent.classList.contains(&#39;active&#39;) &amp;&amp; !event.target.contains(searchFormInput)) {
      searchContent.classList.remove(&#39;active&#39;);
    }
  }
}

<!-- language: lang-css -->

.searchForm--content {
  position: relative
}

#searchIcon {
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

.searchForm&gt;img {
  cursor: pointer;
  width: auto;
  vertical-align: middle;
}

.searchForm--content {
  border: 1px solid blue;
  border-radius: 10px;
  padding-inline: 0.75rem;
  color: black;
  position: absolute;
  left: 12px;
  width: 40%;
  top: 70px;
  display: none;
  align-items: center;
  justify-content: space-between;
}

.searchForm--content.active {
  display: flex;
}

.searchForm--content .btn {
  position: absolute;
  left: 0.2rem;
  top: 50%;
  transform: translatey(-50%);
}

.searchForm--content input[type=&quot;search&quot;] {
  width: 65%;
  border: 1px solid red;
  padding: 1rem 0.5rem;
  color: black;
  margin-left: auto;
}

<!-- language: lang-html -->

&lt;form class=&quot;searchForm&quot; role=&quot;search&quot;&gt;
  &lt;div id=&quot;searchIcon&quot;&gt;my icon search&lt;/div&gt;

  &lt;div class=&quot;searchForm--content&quot; id=&quot;my-box&quot;&gt;
    &lt;input type=&quot;search&quot; placeholder=&quot;search&quot; name=&quot;s&quot; inputmode=&quot;search&quot; class=&quot;searchForm--content__input&quot; /&gt;
    &lt;button type=&quot;submit&quot; class=&quot;btn btn--blue&quot;&gt;submit&lt;/button&gt;
  &lt;/div&gt;
&lt;/form&gt;

<!-- end snippet -->

答案2

得分: 1

通过更新条件语句,现在当点击搜索输入框和具有id“searchIcon”的div时,它们都不会关闭搜索表单内容。

英文:

The problem is this that you are just matching the div with id searchIcon. So, when you click that div, the search Form Content show. But when you click on search input field, it close the search Form Content, because you are not matching search input field in if condition. So, you have to update the if condition. Here is the updated answer:-

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const searchIcon = document.querySelector(&quot;#searchIcon&quot;);
const searchContent = document.querySelector( &quot;.searchForm--content&quot;);
searchIcon.addEventListener(&quot;click&quot;, function() {
    searchContent.classList.toggle(&quot;active&quot;);
});


window.onclick = function(event) {
  console.log(event.target.matches(&#39;#searchIcon&#39;))
  if (!(event.target.matches(&#39;#searchIcon&#39;) ||  event.target.matches(&#39;.searchForm--content__input&#39;))) {    
   var searchContent=document.querySelector(&quot;.searchForm--content&quot;);
     var searchFormInput=document.querySelector(&quot;searchForm--content.active &gt; .searchForm--content__input&quot;);
     if(searchContent.classList.contains(&#39;active&#39;) &amp;&amp; !event.target.contains(searchFormInput)){
          searchContent.classList.remove(&#39;active&#39;);
      }
  }
}

<!-- language: lang-css -->

.searchForm--content{
	position: relative
}

#searchIcon{
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

.searchForm &gt; img {
  cursor: pointer;
  width: auto;
  vertical-align: middle;
}

.searchForm--content{
  border: 1px solid blue;
  border-radius: 10px;
  padding-inline:0.75rem;
  color: black;
  position: absolute;
  left: 12px;
  width: 40%;
  top: 70px;
  display: none;
  align-items: center;
  justify-content: space-between;
}
.searchForm--content.active {
  display: flex;
} 

.searchForm--content .btn{
	position: absolute;
	left:0.2rem;
	top:50%;
	transform: translatey(-50%);
}
.searchForm--content input[type=&quot;search&quot;]{
	width: 65%;
	border: 1px solid red;
	padding: 1rem 0.5rem;
	color: black;
  margin-left: auto;
}

<!-- language: lang-html -->

&lt;form class=&quot;searchForm&quot; role=&quot;search&quot;&gt;
  &lt;div id=&quot;searchIcon&quot;&gt;my icon search&lt;/div&gt;
  
	&lt;div class=&quot;searchForm--content&quot; id=&quot;my-box&quot;&gt;
		&lt;input type=&quot;search&quot; placeholder=&quot;search&quot; name=&quot;s&quot; inputmode=&quot;search&quot;  class=&quot;searchForm--content__input&quot; /&gt; 
		&lt;button type=&quot;submit&quot; class=&quot;btn btn--blue&quot; &gt;submit&lt;/button&gt;
	&lt;/div&gt;
&lt;/form&gt;

<!-- end snippet -->

In this way, when you click submit button, it will close the search Form content. That's good. So, only clicking on search field and div with id searchIcon will not close the searchForm content.

答案3

得分: 1

你的EventListener中的条件根本没有检查点击是否发生在文本框内部。你只检查了#searchIcon

更新后的代码片段:

const searchIcon = document.querySelector("#searchIcon");
const searchContent = document.querySelector(".searchForm--content");
searchIcon.addEventListener("click", function() {
  searchContent.classList.toggle("active");
});

window.onclick = function(event) {
  if (!(event.target.closest('#searchIcon') || event.target.closest('#my-box'))) {
    var searchContent = document.querySelector(".searchForm--content");
    var searchFormInput = document.querySelector(
      "searchForm--content.active > .searchForm--content__input");
    if (searchContent.classList.contains('active') && !event.target.contains(searchFormInput)) {
      searchContent.classList.remove('active');
    }
  }
}
.searchForm--content {
  position: relative
}

#searchIcon {
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

/* 其余的 CSS 样式... */
<form class="searchForm" role="search">
  <div id="searchIcon">my icon search</div>

  <div class="searchForm--content" id="my-box">
    <input id="inputSearch" type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
    <button type="submit" class="btn btn--blue">submit</button>
  </div>
</form>

请注意,我使用了event.target.closest而不是matches,以便它检查#my-box及其所有子元素,因此您无需担心检查该区域中的每个元素。我从@AuxTaco的这个答案中获取了灵感。

英文:

Your condition in the EventListener doesn't check at all whether your click happened inside the textbox. You're only checking for #searchIcon.

Updated snippet:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const searchIcon = document.querySelector(&quot;#searchIcon&quot;);
const searchContent = document.querySelector(&quot;.searchForm--content&quot;);
searchIcon.addEventListener(&quot;click&quot;, function() {
  searchContent.classList.toggle(&quot;active&quot;);
});


window.onclick = function(event) {
  if (!(event.target.closest(&#39;#searchIcon&#39;) || event.target.closest(&#39;#my-box&#39;))) {
    var searchContent = document.querySelector(&quot;.searchForm--content&quot;);
    var searchFormInput = document.querySelector(
      &quot;searchForm--content.active &gt; .searchForm--content__input&quot;);
    if (searchContent.classList.contains(&#39;active&#39;) &amp;&amp; !event.target.contains(searchFormInput)) {
      searchContent.classList.remove(&#39;active&#39;);
    }
  }
}

<!-- language: lang-css -->

.searchForm--content {
  position: relative
}

#searchIcon {
  background-color: green;
  color: white;
  padding: 12px;
  width: fit-content;
}

.searchForm&gt;img {
  cursor: pointer;
  width: auto;
  vertical-align: middle;
}

.searchForm--content {
  border: 1px solid blue;
  border-radius: 10px;
  padding-inline: 0.75rem;
  color: black;
  position: absolute;
  left: 12px;
  width: 40%;
  top: 70px;
  display: none;
  align-items: center;
  justify-content: space-between;
}

.searchForm--content.active {
  display: flex;
}

.searchForm--content .btn {
  position: absolute;
  left: 0.2rem;
  top: 50%;
  transform: translatey(-50%);
}

.searchForm--content input[type=&quot;search&quot;] {
  width: 65%;
  border: 1px solid red;
  padding: 1rem 0.5rem;
  color: black;
  margin-left: auto;
}

<!-- language: lang-html -->

&lt;form class=&quot;searchForm&quot; role=&quot;search&quot;&gt;
  &lt;div id=&quot;searchIcon&quot;&gt;my icon search&lt;/div&gt;

  &lt;div class=&quot;searchForm--content&quot; id=&quot;my-box&quot;&gt;
    &lt;input id=&quot;inputSearch&quot; type=&quot;search&quot; placeholder=&quot;search&quot; name=&quot;s&quot; inputmode=&quot;search&quot; class=&quot;searchForm--content__input&quot; /&gt;
    &lt;button type=&quot;submit&quot; class=&quot;btn btn--blue&quot;&gt;submit&lt;/button&gt;
  &lt;/div&gt;
&lt;/form&gt;

<!-- end snippet -->

Notice that I used event.target.closest instead of matches so that the it checks against #my-box and all of its children so you don't need to worry about checking against each element in that area. Got inspiration for that from this answer by @AuxTaco

huangapple
  • 本文由 发表于 2023年5月20日 23:27:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76295973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定