英文:
Dropdown menu that opens with mouseover and click event only flickering
问题
以下是您要翻译的内容:
我正在尝试创建一个下拉菜单,点击按钮或悬停在按钮上时打开。
使用我现有的代码,下拉菜单在点击或悬停时会闪烁。换句话说,显示和不透明度不会保持。我希望能够点击或悬停在下拉菜单头部以显示下拉菜单。
HTML:
<div class="menu-link dropdown">
<p class="dropdown-select">Item</p>
<div class="dropdown-menu">
<div class="top">
<div class="arr-wrap">
<div class="arr"></div>
</div>
</div>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
</div>
</div>
CSS:
.menu-link {
width: 100px;
text-align: right;
transition: 0.3s;
margin-right: 25px;
}
.dropdown .menu-link {
width: 200px;
text-align: left;
padding: 15px 0px;
margin-left: 35px;
height: 25px;
}
.dropdown-menu {
position: absolute;
top: 100px;
opacity: 0;
width: fit-content;
height: fit-content;
margin-left: -8px;
width: fit-content;
flex-flow: column;
z-index: 3;
border-radius: 10px;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
display: none;
}
.dropdown-select {
height: fit-content;
}
.menu .menu-link {
width: 100px;
text-align: right;
transition: 0.3s;
margin-right: 25px;
}
.dropdown .menu-link {
width: 200px;
text-align: left;
padding: 15px 0px;
margin-left: 35px;
height: 25px;
}
.dropdown-menu {
position: absolute;
top: 100px;
opacity: 0;
width: fit-content;
height: fit-content;
margin-left: -8px;
width: fit-content;
flex-flow: column;
z-index: 3;
border-radius: 10px;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
display: none;
}
.dropdown-select {
height: fit-content;
}
.display {
display: flex;
opacity: 1;
z-index: 3;
}
JavaScript:
document.addEventListener('DOMContentLoaded', load, false);
function load() {
document.getElementsByClassName("dropdown")[0].addEventListener("click", dropdown, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseover", dropdown, false);
}
function dropdown() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.toggle("display");
}
英文:
I am trying to create a dropdown menu that opens upon clicking a button, or hovering over it.
With the code I have, the dropdown menu flickers upon clicking or hovering. In other words, the display and opacity doesn't stay. I want to be able to either click or hover over the dropdown menu header to display the dropdown menu.
HTML:
<div class="menu-link dropdown">
<p class="dropdown-select">Item</p>
<div class="dropdown-menu">
<div class="top">
<div class="arr-wrap">
<div class="arr"></div>
</div>
</div>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
</div>
</div>
CSS:
.menu-link {
width: 100px;
text-align: right;
transition: 0.3s;
margin-right: 25px;
}
.dropdown .menu-link {
width: 200px;
text-align: left;
padding: 15px 0px;
margin-left: 35px;
height: 25px;
}
.dropdown-menu {
position: absolute;
top: 100px;
opacity: 0;
width: fit-content;
height: fit-content;
margin-left: -8px;
width: fit-content;
flex-flow: column;
z-index: 3;
border-radius: 10px;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
display: none;
}
.dropdown-select {
height: fit-content;
}
.menu .menu-link {
width: 100px;
text-align: right;
transition: 0.3s;
margin-right: 25px;
}
.dropdown .menu-link {
width: 200px;
text-align: left;
padding: 15px 0px;
margin-left: 35px;
height: 25px;
}
.dropdown-menu {
position: absolute;
top: 100px;
opacity: 0;
width: fit-content;
height: fit-content;
margin-left: -8px;
width: fit-content;
flex-flow: column;
z-index: 3;
border-radius: 10px;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
display: none;
}
.dropdown-select {
height: fit-content;
}
.display {
display: flex;
opacity: 1;
z-index: 3;
}
JavaScript:
document.addEventListener('DOMContentLoaded', load, false);
function load() {
document.getElementsByClassName("dropdown")[0].addEventListener("click", dropdown, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseover", dropdown, false);
}
function dropdown() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.toggle("display");
}
答案1
得分: 1
这是一个容易犯的错误:
菜单闪烁是因为“mouseover”在鼠标稍微移动到元素上时就会触发,所以当你将鼠标移动到下拉菜单上时,mouseover会不断调用函数,从而切换“display”类,所以它会打开,然后关闭,然后再次打开,依此类推,无限循环。
要修复它,你可以尝试像这样做:
document.getElementsByClassName("dropdown")[0].addEventListener("click", dropdownClick, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseenter", dropdownMouseEnter, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseleave", dropdownMouseLeave, false);
function dropdownClick() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.toggle("display");
}
function dropdownMouseEnter() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.add("display");
}
function dropdownMouseLeave() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.remove("display");
}
这不是制作下拉菜单的最佳方法,但这将使你原本想要的功能更好地工作。
如前所述,mouseover会在鼠标光标移动到元素上时触发,而mouseenter会在鼠标首次悬停在元素上时触发,mouseleave会在鼠标不再悬停在元素上时触发。
我稍微修改了一下,使它更加实用。查看下面的结果:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function _(id) { return document.getElementById(id); }
_("dropdown1").addEventListener("click", dropdownClick, false);
_("dropdown1").addEventListener("mouseenter", dropdownMouseEnter, false);
_("dropdown1").addEventListener("mouseleave", dropdownMouseLeave, false);
function dropdownClick() {
_("dropdown1").classList.toggle("show");
}
function dropdownMouseEnter() {
_("dropdown1").classList.add("show");
}
function dropdownMouseLeave() {
_("dropdown1").classList.remove("show");
}
<!-- language: lang-css -->
*, *::before, *::after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
font-weight: 500;
margin: 0;
padding: 0;
}
body {
background-color: #eee;
margin: 0.5rem;
}
.dropdown-wrap {
position: absolute;
}
.dropdown-wrap .menu-link {
padding: 1rem;
}
.dropdown-wrap .dropdown-select {
padding: 1rem;
cursor: pointer;
width: 7rem;
background-color: white;
border-radius: 0.8rem;
}
.dropdown {
min-width: 12rem;
text-align: left;
position: absolute;
opacity: 0;
display: flex;
flex-flow: column;
left: 0;
top: calc(100% + 0.5rem);
z-index: 3;
border-radius: 0.8rem;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
transform-origin: top left;
scale: 0;
}
.dropdown-wrap.show .dropdown {
scale: 1;
opacity: 1;
}
<!-- language: lang-html -->
<div id="dropdown1" class="dropdown-wrap">
<p class="dropdown-select">Item</p>
<div class="dropdown">
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
</div>
</div>
<!-- end snippet -->
英文:
It's an easy mistake:
The menu flickers because "mouseover" triggers every time the mouse moves over the element just by a tiny bit. so when you move the mouse over the dropdown menu, mouseover it's constantly calling the function which toggles the "display" class, so it opens, then it closes, then it opens again, and so on to infinity.
to fix it, you should try something like this:
document.getElementsByClassName("dropdown")[0].addEventListener("click", dropdownClick, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseenter", dropdownMouseEnter, false);
document.getElementsByClassName("dropdown")[0].addEventListener("mouseleave", dropdownMouseLeave, false);
function dropdownClick() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.toggle("display");
}
function dropdownMouseEnter() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.add("display");
}
function dropdownMouseLeave() {
var dropdown = document.getElementsByClassName("dropdown-menu")[0];
dropdown.classList.remove("display");
}
This is not the best way to go on about making a dropdown menu, but this will make what you have work a lot better and more like you first intended.
As said before mouseover will trigger every time the mouse cursor moves over the element, while mouseenter will trigger once on mouse first hovering the element, and mouseleave will trigger it once more when the mouse is no longer hovering the element.
I've taken the liberty to rework it a bit to make it more functional. See below for the result:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function _(id) { return document.getElementById(id); }
_("dropdown1").addEventListener("click", dropdownClick, false);
_("dropdown1").addEventListener("mouseenter", dropdownMouseEnter, false);
_("dropdown1").addEventListener("mouseleave", dropdownMouseLeave, false);
function dropdownClick() {
_("dropdown1").classList.toggle("show");
}
function dropdownMouseEnter() {
_("dropdown1").classList.add("show");
}
function dropdownMouseLeave() {
_("dropdown1").classList.remove("show");
}
<!-- language: lang-css -->
*, *::before, *::after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
font-weight: 500;
margin: 0;
padding: 0;
}
body {
background-color: #eee;
margin: 0.5rem;
}
.dropdown-wrap {
position: absolute;
}
.dropdown-wrap .menu-link {
padding: 1rem;
}
.dropdown-wrap .dropdown-select {
padding: 1rem;
cursor: pointer;
width: 7rem;
background-color: white;
border-radius: 0.8rem;
}
.dropdown {
min-width: 12rem;
text-align: left;
position: absolute;
opacity: 0;
display: flex;
flex-flow: column;
left: 0;
top: calc(100% + 0.5rem);
z-index: 3;
border-radius: 0.8rem;
transition: 0.2s;
background-color: white;
box-shadow: 2px 2px 10px lightgrey;
transform-origin: top left;
scale: 0;
}
.dropdown-wrap.show .dropdown {
scale: 1;
opacity: 1;
}
<!-- language: lang-html -->
<div id="dropdown1" class="dropdown-wrap">
<p class="dropdown-select">Item</p>
<div class="dropdown">
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./link.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
<p class="menu-link"><a href="./item.html">Item</a></p>
</div>
</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论