我正在尝试创建一条帮助消息,当用户单击切换按钮以显示帮助消息或通过单击页面上的其他位置单击以消失时,该消息将消失。解决方法似乎是查看relatedTarget
事件的onblur
属性,并在onblur
是切换帮助消息的按钮时阻止relatedTarget
处理程序运行。这似乎在Chrome中有效,但是在Firefox和Safari中,relatedTarget
属性设置为容器div
而不是按钮,这使得无法区分切换按钮的单击和“单击”。
我创建了一个简单的演示程序来说明问题:
let openState = false;
let contentDiv = document.getElementById("show-hide-content");
let accordionDiv = document.getElementById("accordion");
let showHideButton = document.getElementById("show-hide-toggle");
function setOpenState(state) {
openState = state;
if(openState) {
contentDiv.style.visibility = "visible";
contentDiv.focus();
}
else {
contentDiv.style.visibility = "hidden";
}
}
function toggleVisibility(override) {
if (typeof override === "boolean") {
setOpenState(override);
}
else {
setOpenState(!openState);
}
}
function buttonClickHandler(event) {
toggleVisibility();
}
function contentBlurHandler(event) {
if(!accordionDiv.contains(event.relatedTarget)) {
toggleVisibility(false);
}
}
showHideButton.onclick = buttonClickHandler;
contentDiv.onblur = contentBlurHandler;
.parent {
display: flex;
width: 100vw;
height: 100vh;
flex-direction: row;
background-color: #409958;
}
.accordion {
background-color: #28a7c9;
}
.show-hide-content {
visibility: hidden;
background-color: #c91e63;
}
<h1>Show/Hide Test</h1>
<div class="parent">
<div class="drawer">
<div class="accordion" id="accordion">
<button class="show-hide-toggle" id="show-hide-toggle">Show/Hide</button>
<div class="show-hide-content" id="show-hide-content" tabindex="-1">
<p>This is some content that should be shown or hidden depending on the toggle.</p>
</div>
</div>
<div class="spacer">
</div>
</div>
</div>
此代码可在Chrome中正常运行。但是,在Firefox中,单击“显示/隐藏”按钮将显示隐藏的内容,但是在再次单击该按钮时不会将其隐藏。据我所知,这是因为
onblur
处理程序隐藏了div,然后onclick
处理程序再次将其切换为打开状态,即使我正在检查onblur.relatedTarget
来确保它不在内部。抽屉。在Firefox中检测点击的正确方法是什么?
最佳答案
问题在于clicking the <button>
doesn't focus it on some browser/OS combinations(尤其是在Chrome之外的macOS上,尤其是在macOS上),因此onblur
的event.relatedTarget
是null
,因为页面上没有任何内容获得焦点。如果您从<div id="show-hide-content">
进行SHIFT + TAB键,则会看到relatedTarget
已按预期设置,因为在这种情况下该按钮确实获得了焦点。
我将运行代码以使div暂时隐藏div,以使click
处理程序有机会先运行。
在下面的示例中,我实现了此建议,并添加了一些日志记录,以更轻松地了解正在发生的情况:
let openState = false;
let contentDiv = document.getElementById("show-hide-content");
let accordionDiv = document.getElementById("accordion");
let showHideButton = document.getElementById("show-hide-toggle");
function setOpenState(state) {
openState = state;
if(openState) {
contentDiv.style.visibility = "visible";
contentDiv.focus();
}
else {
contentDiv.style.visibility = "hidden";
}
}
function buttonClickHandler(event) {
console.log("click, setting openState to", !openState);
setOpenState(!openState);
}
function contentBlurHandler(event) {
console.log("blur, relatedTarget is", event.relatedTarget);
setTimeout(function() {
console.log("blur, after timeout, openState is", openState);
setOpenState(false);
}, 100);
}
showHideButton.onclick = buttonClickHandler;
showHideButton.onmousedown = function() {console.log("button mousedown"); };
contentDiv.onblur = contentBlurHandler;
showHideButton.onfocus = function(ev) { console.log("button onfocus"); }
.parent {
display: flex;
width: 100vw;
height: 100vh;
flex-direction: row;
background-color: #409958;
}
.accordion {
background-color: #28a7c9;
}
.show-hide-content {
visibility: hidden;
background-color: #c91e63;
}
<h1>Show/Hide Test</h1>
<div class="parent">
<div class="drawer">
<div class="accordion" id="accordion">
<button class="show-hide-toggle" id="show-hide-toggle">Show/Hide</button>
<div class="show-hide-content" id="show-hide-content" tabindex="-1">
<p>This is some content that should be shown or hidden depending on the toggle.</p>
</div>
</div>
<div class="spacer">
</div>
</div>
</div>
关于javascript - 当调用onBlur时,Firefox中relatedTarget为null,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57695377/