我知道这是一个常见的问题,但我所看到的所有答案都解决不了我的问题,如果我错过了一个问题,很抱歉,这个问题可以被删除/标记为重复。
标记
<div class="has-dropdown">
<button class="js-dropdown-trigger">
Dropdown
</button>
<div class="dropdown">
<div class="dropdown__item">
Some random text with a <a href="#" class="stop-propagation">link</a> in it.
</div>
<div class="dropdown__divider"></div>
<div class="dropdown__item">
<a href="#">Item One</a>
</div>
<div class="dropdown__item">
<a href="#">Item Two</a>
</div>
<div class="dropdown__item">
<a href="#">Item Three</a>
</div>
</div>
</div>
脚本
$('.has-dropdown').off().on('click', '.js-dropdown-trigger', (event) => {
const $dropdown = $(event.currentTarget).next('.dropdown');
if (!$dropdown.hasClass('is-active')) {
$dropdown.addClass('is-active');
} else {
$dropdown.removeClass('is-active');
}
});
$('.has-dropdown').on('focusout', (event) => {
const $dropdown = $(event.currentTarget).children('.dropdown');
$dropdown.removeClass('is-active');
});
造型
.has-dropdown {
display: inline-flex;
position: relative;
}
.dropdown {
background-color: #eee;
border: 1px solid #999;
display: none;
flex-direction: column;
position: absolute;
top: 100%;
left: 0;
width: 300px;
margin-top: 5px;
}
.dropdown.is-active {
display: flex;
}
.dropdown__item {
padding: 10px;
}
.dropdown__divider {
border-bottom: 1px solid #999;
}
Fiddle
http://jsfiddle.net/joemottershaw/3yzadmek/
它非常简单,单击js-dropdown-trigger
可以很好地切换is-active
下拉类,单击has-dropdown
容器外部也可以删除is-active
下拉类。
但是,我期望发生的是关注has-dropdown
元素的子类元素(单击或制表符),这意味着不应该触发focusout
事件处理程序,因为您仍然关注于has-dropdown
容器的子类元素。
当
focusout
事件(或其中的任何元素)失去焦点时,它将被发送到元素。这与模糊事件不同,因为它支持检测后代元素的焦点丢失()。
我知道我可以删除focusout
事件处理程序并使用如下内容:
$(document).on('click', (event) =>{
const $dropdownContainer = $('.has-dropdown');
if (!$dropdownContainer.is(event.target) && $dropdownContainer.has(event.target).length === 0) {
$dropdownContainer.find('.dropdown').removeClass('is-active');
}
});
这是可行的,但如果您要单击触发器,然后通过链接选项卡,当您通过最后一个链接时,下拉式仍然是可见的。只是努力寻找最好的解决方案来保持事物的可访问性。
如果可能的话,我想坚持使用focusout
方法。
基于 darshanags 应答的改进
虽然更新后的脚本适用于单个元素,但将其他元素添加到body
中将导致focusout
不再按预期工作。我认为这是因为if
语句似乎是正确的,即使焦点应用于has-dropdown
容器之后的任何元素,而不仅仅是后代?因为如果要更新HTML并在下拉列表后添加更多可聚焦的元素,例如输入。当从has-dropdown
容器中的最后一个可聚焦元素选项卡到输入时,下拉列表保持活动状态。只有当下拉列表是DOM中的最后一个元素,并且只有当焦点完全丢失在DOM上时,它才能工作。
发布于 2018-08-13 03:35:54
您几乎可以使用您的代码了--但是我认为,需要更清楚地说明focusout
如何与本机非聚焦元素(即div,p)及其后代一起工作,这些元素可以是可聚焦的元素(输入、锚)。
当容器绑定到包含可聚焦元素的focusout
事件时,每当focusout
事件中的任何一个可聚焦子元素失去焦点时,都会触发事件--这可能是通过键盘导航或单击另一个子元素或容器本身来实现的。我设置了一个小提琴,演示了这一点:每次容器获得或丢失焦点时,都会发送https://jsfiddle.net/darshanags/v5gk2cz8/ -控制台消息。
问:那么,为什么菜单隐藏在问题中给出的示例中呢?
A:当单击按钮时,菜单变得可见,单击按钮会使按钮获得焦点。但是,一旦单击菜单或菜单元素中的锚,按钮就会失去焦点--这反过来会触发父元素的“焦点”事件,并导致菜单自身隐藏。这是因为focusout
事件支持事件冒泡。
问:我们怎么解决这个问题?
A1.1:通过给父元素提供一个表索引:,使它具有可聚焦性
<div class="has-dropdown" tabindex="0">
这涉及到几件重要的事情:
div
元素一个焦点轮廓-这反过来又增强了元素的可访问性。div
元素上注册与焦点相关的事件-在本例中,这将是focusout
。如果省略了tabindex
,我们将需要添加额外的JavaScript来补偿功能的丢失。focusout
A1.2:在事件处理程序中,我们检查获得焦点的元素是否为父元素的后代,如果是,则不会从菜单中删除 is-active
类。
完整示例代码:
$('.has-dropdown').off().on('click', '.js-dropdown-trigger', (event) => {
const $dropdown = $(event.currentTarget).next('.dropdown');
if (!$dropdown.hasClass('is-active')) {
$dropdown.addClass('is-active');
} else {
$dropdown.removeClass('is-active');
}
});
$('.has-dropdown').on('focusout', function(event) {
const $reltarget = $(event.relatedTarget);
const $currenttarget = $(event.currentTarget);
const $dropdown = $currenttarget.children('.dropdown');
// remove 'is-active' class only if the element
// that is gaining focus is not a child of the parent.
// parent = div.has-dropdown
if (!$reltarget.closest('.has-dropdown').is($currenttarget)) {
$dropdown.removeClass('is-active');
}
});
.has-dropdown {
display: inline-flex;
position: relative;
}
.dropdown {
background-color: #eee;
border: 1px solid #999;
display: none;
flex-direction: column;
position: absolute;
top: 100%;
left: 0;
width: 300px;
margin-top: 5px;
}
.dropdown.is-active {
display: flex;
}
.dropdown__item {
padding: 10px;
}
.dropdown__divider {
border-bottom: 1px solid #999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="has-dropdown" tabindex="0">
<button class="js-dropdown-trigger">
Dropdown
</button>
<div class="dropdown">
<div class="dropdown__item">
Some random text with a <a href="#" class="stop-propagation">link</a> in it.
</div>
<div class="dropdown__divider"></div>
<div class="dropdown__item">
<a href="#">Item One</a>
</div>
<div class="dropdown__item">
<a href="#">Item Two</a>
</div>
<div class="dropdown__item">
<a href="#">Item Three</a>
</div>
</div>
</div>
<div class="has-dropdown" tabindex="0">
<button class="js-dropdown-trigger">
Dropdown
</button>
<div class="dropdown">
<div class="dropdown__item">
Some random text with a <a href="#" class="stop-propagation">link</a> in it.
</div>
<div class="dropdown__divider"></div>
<div class="dropdown__item">
<a href="#">Item One</a>
</div>
<div class="dropdown__item">
<a href="#">Item Two</a>
</div>
<div class="dropdown__item">
<a href="#">Item Three</a>
</div>
</div>
</div>
<input name="tf" type="text"/>
我把原来的小提琴叉了一下,并对它进行了修改,以显示它的作用。你可以在这里找到修改过的小提琴:http://jsfiddle.net/darshanags/60jnusvk/。
其他有用信息:
我使用event.relatedTarget
来确定每次触发focusout
事件时获得焦点的元素。有关event.relatedTarget
的更多信息可以在这里找到:https://api.jquery.com/event.relatedTarget/。
更新
我已经重构了一些我的原始代码,它现在更简单了:http://jsfiddle.net/darshanags/60jnusvk/24/。我会留下这把小提琴和原件作为参考。
https://stackoverflow.com/questions/51765288
复制相似问题