我正在建立一个菜单栏。在栏中,每个菜单项都包含一个链接,而那些具有子菜单的菜单项也有一个可点击的区域来打开子菜单。显示和隐藏子菜单的逻辑是用JavaScript完成的,它主要通过click和mouseleave事件来切换元素的类名。
mouseleave事件已附加到所有子菜单元素,其中一个附加到其opener元素。这些事件负责在需要时隐藏子菜单。单击侦听器已附加到包含整个菜单栏的元素。此侦听器在需要时打开子菜单,或者在单击链接时关闭所有子菜单。
接下来发生的问题是:当用户点击链接时,通过将其类切换到设置display: none
的类来隐藏所有子类。当然这会触发mouseleave事件,基于类切换的逻辑会再次显示子菜单。
我试图通过设置一个标志来解决这个问题,该标志在mouseleave处理程序中进行了检查。如果已设置标志,则不执行任何操作。该标志将在短暂延迟后重置。
这适用于FF和Chrome,但在IE11和Edge中导致一个奇怪的问题:如果用户在点击链接后保持鼠标不动,并在延迟(500毫秒)后开始移动鼠标,则隐藏的子菜单会弹出再次进入屏幕。
这似乎发生了,因为mouseleave事件在隐藏元素上触发,甚至在延迟之后。如何修复代码,以便IE和Edge也可以隐藏子菜单?
您可以使用下面的堆栈代码重现IE11和Edge的问题,或使用fiddle进行播放。
var WWMainMenu = {
/// Hides all Submenus in Mainmenu
closeAllSubs: function () {
var subs = Array.prototype.slice.call(this.mainMenu.querySelectorAll('.ww-submenu-exp'));
subs.forEach(function (sub) {
sub.classList.toggle('ww-submenu');
sub.classList.toggle('ww-submenu-exp');
return;
});
return;
},
/// Hides a current Submenu when blurring the opener element
closeCurrent: function (e) {
var nextSub = e.target.nextElementSibling;
if (this.noLeave) {
return; /// Quit, toggling sub is not allowed
}
if (e.relatedTarget !== nextSub && nextSub.classList.contains('ww-submenu-exp')) {
nextSub.classList.toggle('ww-submenu');
nextSub.classList.toggle('ww-submenu-exp');
}
return;
},
/// Shows/hides Submenu
toggleSubmenu: function (e) {
var target = e.target,
that = this;
/// Hide all Submenus when clicking on links
if (target.tagName === 'A') {
this.closeAllSubs();
// Circumvent the race condition
this.noLeave = true;
window.setTimeout(function () {
that.noLeave = false;
}, 500);
return;
}
/// Validate the target
if (!target.classList.contains('ww-menuentry')) {
return;
} /// Quit, not clicked on a menuentry
/// Toggle the visibility of Submenu
target.nextElementSibling.classList.toggle('ww-submenu');
target.nextElementSibling.classList.toggle('ww-submenu-exp');
return;
},
/// Hides Submenu when blurring the menu itself
hideSubmenu: function (e) {
if (this.noLeave) {
return; /// Quit, toggling sub is not allowed
}
if (this.mainMenu.classList.contains('ww-show-menu')) {
return; /// Quit, no autoclose when on small screens
}
e.target.classList.toggle('ww-submenu');
e.target.classList.toggle('ww-submenu-exp');
return;
},
/// Initializes a WWMainmenu object
init: function (options) {
var subs, /// Stores all Submenu elements in Mainmenu [Array]
entries; /// Stores all Menuentry elements in Mainmenu [Array]
subs = Array.prototype.slice.call(options.menuBar.querySelectorAll('.ww-submenu'));
entries = Array.prototype.slice.call(options.menuBar.querySelectorAll('.ww-menuentry'));
/// Create prooperties
this.mainMenu = options.menuBar; /// Reference to the Mainmenu element [HTMLElement]
this.noLeave = false; /// Flag controlling mouseleave handling on Submenus and Menuentries
/// Add click listener for toggling Submenus
this.mainMenu.addEventListener('click', this.toggleSubmenu.bind(this));
/// Add blur listeners for Submenus
subs.forEach(function (sub) {
sub.addEventListener('mouseleave', this.hideSubmenu.bind(this));
return;
}, this);
/// Add blur listeners for Menuentries
entries.forEach(function (entry) {
entry.addEventListener('mouseleave', this.closeCurrent.bind(this));
return;
}, this);
return this;
}
}.init({
menuBar: document.querySelector('.ww-mainmenu-bar')
});
a {
text-decoration: none;
}
/* Menu system */
.ww-mainmenu-bar {
display: block;
background-color: rgba(64, 64, 64, 1);
font-size: 1.0em;
white-space: nowrap;
}
.ww-mainmenu {
display: inline-block;
white-space: nowrap;
color: rgba(255, 255, 255, 1);
}
.ww-menuentry, .ww-menuentry a, .ww-submenu-exp a {
color: rgba(255, 255, 255, 1);
}
.ww-menuentry {
padding: 5px;
}
.ww-menuentry:hover {
color: rgba(255, 255, 255, 1);
background: rgba(70, 130, 180, 1);
}
.ww-menuentry::after {
content: "\2261";
position: absolute;
right: 10px;
cursor: default;
color: rgba(255, 255, 255, 1);
}
.ww-mainmenu > .ww-menuentry::after {
position: relative;
content: "\2261";
right: 0px;
margin-left: 10px;
color: rgba(255, 255, 255, 1);
}
.ww-submenu, .ww-submenu-exp {
display: none;
position: absolute;
min-width: calc(160px);
background: rgba(64, 64, 64, 1);
font-size: 0.95em;
z-index: 20;
white-space: nowrap;
margin-left: 2em;
padding: 5px;
border: 1px solid rgba(0, 0, 0, 0.5);
}
.ww-submenu-exp {
display: block;
}
.ww-submenu-exp > a {
display: block;
padding: 5px;
}
.ww-submenu-exp > a:hover {
background: rgba(70, 130, 180, 1);
}
<!-- MAIN MENU -->
<nav class="ww-mainmenu-bar">
<div class="ww-mainmenu">
<div class="ww-menuentry"><a href="#">Main link</a></div>
<div class="ww-submenu">
<a href="#">Link 1</a>
<div class="ww-menuentry"><a href="#">Link 2</a></div>
<div class="ww-submenu">
<a href="#">Link 2.1</a>
<a href="#">Link 2.2</a>
</div>
<div class="ww-menuentry"><a href="#">Link 3</a></div>
<div class="ww-submenu">
<a href="#">Link 3.1</a>
<a href="#">Link 3.2</a>
</div>
</div>
</div>
</nav>
答案 0 :(得分:1)
在SELECT animation_id, animation_name, animation_group
FROM animations
WHERE animation_id = '45' OR active = true
ORDER BY animation_group, animation_name
函数中,为什么不明确地呼叫hideSubmenu
而不是hide()
?