gpt4 book ai didi

javascript - 纯 JS 滑动菜单,能够关闭它 "on click outside of the menu"

转载 作者:太空狗 更新时间:2023-10-29 13:12:17 25 4
gpt4 key购买 nike

我正在尝试重新表述我的问题,并将完成我所做的所有步骤,尤其是我失败的地方。我对 JS 没有很深的了解,但有通过实践学习的意愿以及社区的帮助。

我偶然发现了 this answer并实现了效益。因为我不想使用 jQuery,所以我开始用 JS 重写它。

  1. 第一步是编写一个基本的简单函数,使用 blur() 在“单击”时打开菜单,并在单击焦点元素外部时关闭它;方法。

引用来自 @zzzzBov 的 jQuery 代码:

$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});

$('div').on('focusout', function () {
$(this).removeClass('active');
});

我的 JS 代码:

var navToggle = document.getElementsByClassName('js-site-nav-btn--toggle')[0];
var navMenu = document.getElementsByClassName('js-site-nav')[0];

navToggle.addEventListener('click', function() {
this.focus();
navMenu.classList.toggle('js-site-nav--open');
});

navMenu.addEventListener('blur', function() {
this.classList.remove('js-site-nav--open');
}, true);

打开菜单有效,问题是如果之前单击一次聚焦元素(菜单),它只会在菜单外的“单击”时关闭:

var navToggle = document.getElementsByClassName('js-site-nav-btn--toggle')[0];
var navMenu = document.getElementsByClassName('js-site-nav')[0];

navToggle.addEventListener('click', function() {
this.focus();
navMenu.classList.toggle('js-site-nav--open');
});

navMenu.addEventListener('blur', function() {
this.classList.remove('js-site-nav--open');
}, true);
.c-site-nav {
color: black;
list-style-type: none;
padding-top: 20px;
position: fixed;
overflow: hidden;
top: 0;
right: -200px;
width: 200px;
height: 100%;
transition: right .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
opacity: .9;
background-color: green;
}
.js-site-nav--open {
right: 0;
}
.c-site-nav-btn:hover {
cursor: pointer;
background-color: red;
}
.c-site-nav-btn {
position: fixed;
top: 20px;
right: 20px;
border: 0;
outline: 0;
background-color: black;
position: fixed;
width: 40px;
height: 40px;
}
.c-site-nav-btn__line {
width: 20px;
height: 2px;
background-color: white;
display: block;
margin: 5px auto;
}
<button class="c-site-nav-btn js-site-nav-btn--toggle">
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
</button>
<nav class="c-site-nav js-site-nav" tabindex="-1" role="navigation">
<ul class="c-site-nav__menu">
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">TOPMENU</a>
</li>
<li>SUBMENU
<ul>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
</ul>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/portfolio">TOPMENU</a>
</li>
</ul>
</nav>

  1. 我尝试继续第二步,即解决两个主要问题:

The first is that the link in the dialog isn't clickable. Attempting to click on it or tab to it will lead to the dialog closing before the interaction takes place. This is because focusing the inner element triggers a focusout event before triggering a focusin event again.

The fix is to queue the state change on the event loop. This can be done by using setImmediate(...), or setTimeout(..., 0) for browsers that don't support setImmediate. Once queued it can be cancelled by a subsequent focusin:

The second issue is that the dialog won't close when the link is pressed again. This is because the dialog loses focus, triggering the close behavior, after which the link click triggers the dialog to reopen.

Similar to the previous issue, the focus state needs to be managed. Given that the state change has already been queued, it's just a matter of handling focus events on the dialog triggers:

引用来自 @zzzzBov 的 jQuery 代码:

$('a').on('click', function () {
$(this.hash).toggleClass('active').focus();
});

$('div').on({
focusout: function () {
$(this).data('timer', setTimeout(function () {
$(this).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this).data('timer'));
}
});

$('a').on({
focusout: function () {
$(this.hash).data('timer', setTimeout(function () {
$(this.hash).removeClass('active');
}.bind(this), 0));
},
focusin: function () {
clearTimeout($(this.hash).data('timer'));
}
});

我的 JS 代码:

var navToggle = document.getElementsByClassName('js-site-nav-btn--toggle')[0];
var navMenu = document.getElementsByClassName('js-site-nav')[0];
var navLink = document.getElementsByClassName('js-site-nav__item')[0];

navToggle.addEventListener('click', function() {
this.focus();
navMenu.classList.toggle('js-site-nav--open');
});

navMenu.addEventListener('focus', function() {
this.blur(function() {
setTimeout(function() {
this.classList.remove('js-site-nav--open');
}.bind(this), 0);
});
this.focus(function() {
clearTimeout();
});
});

navLink.addEventListener('blur', function() {
navLink.blur(function() {
setTimeout(function() {
navMenu.classList.remove('js-site-nav--open');
}.bind(), 0);
});
navLink.focus(function() {
clearTimeout();
});
});

打开菜单仍然有效,但关闭点击外部停止工作,经过研究我认为模糊和聚焦是正确的方法,但我想我遗漏了一些重要的东西。

var navToggle = document.getElementsByClassName('js-site-nav-btn--toggle')[0];
var navMenu = document.getElementsByClassName('js-site-nav')[0];
var navLink = document.getElementsByClassName('js-site-nav__item')[0];

navToggle.addEventListener('click', function() {
this.focus();
navMenu.classList.toggle('js-site-nav--open');
});

navMenu.addEventListener('focus', function() {
this.blur(function() {
setTimeout(function() {
this.classList.remove('js-site-nav--open');
}.bind(this), 0);
});
this.focus(function() {
clearTimeout();
});
});

navLink.addEventListener('blur', function() {
navLink.blur(function() {
setTimeout(function() {
navMenu.classList.remove('js-site-nav--open');
}.bind(), 0);
});
navLink.focus(function() {
clearTimeout();
});
});
.c-site-nav {
color: black;
list-style-type: none;
padding-top: 20px;
position: fixed;
overflow: hidden;
top: 0;
right: -200px;
width: 200px;
height: 100%;
transition: right .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
opacity: .9;
background-color: green;
}
.js-site-nav--open {
right: 0;
}
.c-site-nav-btn:hover {
cursor: pointer;
background-color: red;
}
.c-site-nav-btn {
position: fixed;
top: 20px;
right: 20px;
border: 0;
outline: 0;
background-color: black;
position: fixed;
width: 40px;
height: 40px;
z-index:9999;
}
.c-site-nav-btn__line {
width: 20px;
height: 2px;
background-color: white;
display: block;
margin: 5px auto;
}
<button class="c-site-nav-btn js-site-nav-btn--toggle">
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
</button>
<nav class="c-site-nav js-site-nav" tabindex="-1" role="navigation">
<ul class="c-site-nav__menu">
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">TOPMENU</a>
</li>
<li>SUBMENU
<ul>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
</ul>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/portfolio">TOPMENU</a>
</li>
</ul>
</nav>

我确信我还有很多东西要学,但我将不胜感激。非常感谢大家。

最佳答案

您可以在 navmenu 显示时立即将其设置为焦点。如果用户在其外部单击,将触发 blur 事件并删除菜单。由于单击链接也会触发 blur 事件,因此当用户单击菜单内的任意位置时,我们必须将菜单保留在屏幕上。这可以通过 isMouseDown 标志进行监控。

这是您问题的第 1 部分中给出的代码片段的增强版本。

var navToggle = document.getElementsByClassName('js-site-nav-btn--toggle')[0];
var navMenu = document.getElementsByClassName('js-site-nav')[0];
var isMouseDown = false;

navToggle.addEventListener('click', function() {
this.focus();
navMenu.classList.toggle('js-site-nav--open');
navMenu.focus();
});

navMenu.addEventListener('mousedown', function() {
isMouseDown = true;
});

navMenu.addEventListener('mouseup', function() {
isMouseDown = false;
});

navMenu.addEventListener('mouseleave', function() {
isMouseDown = false;
});

navMenu.addEventListener('blur', function() {
if (!isMouseDown) {
navMenu.classList.remove('js-site-nav--open');
}
}, true);
.c-site-nav {
color: black;
list-style-type: none;
padding-top: 20px;
position: fixed;
overflow: hidden;
top: 0;
right: -200px;
width: 200px;
height: 100%;
transition: right .6s cubic-bezier(0.190, 1.000, 0.220, 1.000);
opacity: .9;
background-color: green;
}
.js-site-nav--open {
right: 0;
}
.c-site-nav-btn:hover {
cursor: pointer;
background-color: red;
}
.c-site-nav-btn {
position: fixed;
top: 20px;
right: 20px;
border: 0;
outline: 0;
background-color: black;
position: fixed;
width: 40px;
height: 40px;
}
.c-site-nav-btn__line {
width: 20px;
height: 2px;
background-color: white;
display: block;
margin: 5px auto;
}
<button class="c-site-nav-btn js-site-nav-btn--toggle">
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
<span class="c-site-nav-btn__line"></span>
</button>
<nav class="c-site-nav js-site-nav" tabindex="-1" role="navigation">
<ul class="c-site-nav__menu">
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">TOPMENU</a>
</li>
<li>SUBMENU
<ul>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/">MENU</a>
</li>
</ul>
</li>
<li>
<a class="c-site-nav__item js-site-nav__item" href="/portfolio">TOPMENU</a>
</li>
</ul>
</nav>

关于javascript - 纯 JS 滑动菜单,能够关闭它 "on click outside of the menu",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41447827/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com