当调用onBlur时,Firefox中relatedTarget为null [英] relatedTarget is null in Firefox when onBlur is called

查看:132
本文介绍了当调用onBlur时,Firefox中relatedTarget为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一条帮助消息,当用户单击切换按钮以显示帮助消息或通过单击页面上的其他位置单击以消失时,该消息将消失.解决方法似乎是查看onblur事件的relatedTarget属性,并在relatedTarget是切换帮助消息的按钮时阻止onblur处理程序运行.这似乎在Chrome中可行,但是在Firefox和Safari中,relatedTarget属性设置为容器div而不是按钮,这使得无法区分切换按钮的单击和单击". /p>

我创建了一个简单的演示程序来说明问题:

 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中检测点击的正确方法是什么?

解决方案

问题是按住SHIFT + TAB键,则会看到relatedTarget已按预期设置,因为在这种情况下该按钮确实获得了焦点.

我将运行代码以将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> 

I'm trying to create a help message that will disappear when the user either clicks the toggle button to display the help message or clicks away by clicking elsewhere on the page. The solution appears to be to look at the relatedTarget property of the onblur event and prevent the onblur handler from running when the relatedTarget is the button to toggle the help message. This seems to work in Chrome, but in Firefox and Safari, the relatedTarget property is set to the container div rather than the button, which makes it impossible to distinguish between the toggle button click and a "click away".

I've created a simple demonstrator that illustrates the problem:

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>

This code works correctly in Chrome. However, in Firefox, clicking the "Show/Hide" button displays the hidden content, but doesn't hide it when the button is clicked again. As far as I can tell, this is because the onblur handler is hiding the div, and then the onclick handler is toggling it open again, even though I'm checking onblur.relatedTarget to ensure that it's not anywhere inside the drawer.

What is the correct way to detect click-away in Firefox?

解决方案

The problem is that clicking the <button> doesn't focus it on some browser/OS combinations (notably on macOS except in Chrome), so onblur's event.relatedTarget is null as nothing on the page receives focus. If you SHIFT+TAB from the <div id="show-hide-content">, you'll see that relatedTarget is set as you expect, as the button does receive focus in this scenario.

I would run the code to hide the div off a small timeout, to give the click handler a chance to run first.

In the example below I implemented this suggestion and added some logging to make it easier to see what's going on:

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>

这篇关于当调用onBlur时,Firefox中relatedTarget为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆