英文:
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("#searchIcon");
const searchContent = document.querySelector( ".searchForm--content");
searchIcon.addEventListener("click", function() {
searchContent.classList.toggle("active");
});
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');
}
}
}
<!-- language: lang-css -->
.searchForm--content{
position: relative
}
#searchIcon{
background-color: green;
color: white;
padding: 12px;
width: fit-content;
}
.searchForm > 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="search"]{
width: 65%;
border: 1px solid red;
padding: 1rem 0.5rem;
color: black;
margin-left: auto;
}
<!-- language: lang-html -->
<form class="searchForm" role="search">
<div id="searchIcon">my icon search</div>
<div class="searchForm--content" id="my-box">
<input type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
<button type="submit" class="btn btn--blue" >submit</button>
</div>
</form>
<!-- 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("#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');
}
}
}
<!-- language: lang-css -->
.searchForm--content {
position: relative
}
#searchIcon {
background-color: green;
color: white;
padding: 12px;
width: fit-content;
}
.searchForm>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="search"] {
width: 65%;
border: 1px solid red;
padding: 1rem 0.5rem;
color: black;
margin-left: auto;
}
<!-- language: lang-html -->
<form class="searchForm" role="search">
<div id="searchIcon">my icon search</div>
<div class="searchForm--content" id="my-box">
<input type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
<button type="submit" class="btn btn--blue">submit</button>
</div>
</form>
<!-- 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("#searchIcon");
const searchContent = document.querySelector( ".searchForm--content");
searchIcon.addEventListener("click", function() {
searchContent.classList.toggle("active");
});
window.onclick = function(event) {
console.log(event.target.matches('#searchIcon'))
if (!(event.target.matches('#searchIcon') || event.target.matches('.searchForm--content__input'))) {
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');
}
}
}
<!-- language: lang-css -->
.searchForm--content{
position: relative
}
#searchIcon{
background-color: green;
color: white;
padding: 12px;
width: fit-content;
}
.searchForm > 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="search"]{
width: 65%;
border: 1px solid red;
padding: 1rem 0.5rem;
color: black;
margin-left: auto;
}
<!-- language: lang-html -->
<form class="searchForm" role="search">
<div id="searchIcon">my icon search</div>
<div class="searchForm--content" id="my-box">
<input type="search" placeholder="search" name="s" inputmode="search" class="searchForm--content__input" />
<button type="submit" class="btn btn--blue" >submit</button>
</div>
</form>
<!-- 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("#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');
}
}
}
<!-- language: lang-css -->
.searchForm--content {
position: relative
}
#searchIcon {
background-color: green;
color: white;
padding: 12px;
width: fit-content;
}
.searchForm>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="search"] {
width: 65%;
border: 1px solid red;
padding: 1rem 0.5rem;
color: black;
margin-left: auto;
}
<!-- language: lang-html -->
<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>
<!-- 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论