IE click on child does not focus parent, parent ha

2019-04-29 03:50发布

EDIT: See my own answer below: https://stackoverflow.com/a/25953721/674863

Demo: http://jsfiddle.net/fergal_doyle/anXM3/1/

I have a div with tabindex=0, and a child div with a fixed width. When I click on the child div I expect the outer div to recieve focus. This works fine with Firefox and Chrome, and only works with Internet Explorer (7 to 10) when the child div has no width applied.

With a width, clicking the child (white) div does not give focus to the outer one, and if the outer one previously had focus, clicking the child causes the outer to blur, which is a pain for what I want to do.

HTML:

<div tabindex="0" id="test">
    <div>Click</div>
</div> 

CSS:

div {
    border:1px solid #000;
    padding:20px;
    background-color:red;
}
div div {
    padding:8px;
    background-color:#FFF;
    cursor:default;
    width:200px;
}

JS:

var $div = $("#test"),
    $inner = $("#test > div");

$div.on("blur", function (e) {
    console.log("blur");
})
    .on("focus", function (e) {
    console.log("focus")
});

5条回答
时光不老,我们不散
2楼-- · 2019-04-29 04:30

Have you tried to add :

$inner.click(function() {
  $div.focus();
});

and to prevent the outer div to blur after a focus use e.stopPropagation()

UPDATE: Since the click event fires after the blur I used the Mousedown event, because it fires before blur.

PS: Don't forget to handle keyboard events keydown if you want also to catch blurs fired by the keyboard.

http://jsfiddle.net/ouadie/x4nAX/

查看更多
混吃等死
3楼-- · 2019-04-29 04:45

This question is old, but I just came across this problem and the following solution works in IE11 and is much simpler than any other:

.iesux {
     border:1px solid #000;
     display:block;
     padding:8px;
     background-color:#FFF;
     cursor:default;
     width:200px;
     pointer-events: none;
}

It's not supported in IE<11 unfortunately but if you can get away with that it's by far the easiest.

http://jsfiddle.net/anXM3/22/

查看更多
孤傲高冷的网名
4楼-- · 2019-04-29 04:46

Clicking on an element with tabindex=0 in IE will result in the element gaining invisible focus. The way to gain visible focus is by programmatically calling focus() while the element does not already have invisible focus. Since focus happens right after mousedown, this means we need:

$('#parent').mousedown(function(e){
    var parent = $(e.currentTarget)
    if (!parent.is(':focus')) {
        parent.focus()
    }
}).focus(function(e){
    console.log('focused')
}).blur(function(e){
    console.log('blurred')
})

If the child is inline or a block with no width set, the effect is the same as clicking directly on the parent. However, if the child is an inline-block or a block with a width set, and the parent already had focus, then the parent will blur() right after the mousedown handlers are executed. We have three different ways to proceed, with different tradeoffs.

One option is to merely suppress the blur with preventDefault(); the virtue of this approach is that blur() will never fire and focus() will not fire redundantly, which allows us to write straightforward logic in our focus and blur handlers; the vice of this approach is that it disables text selection:

$('#child').mousedown(function(e){
    e.preventDefault()
})
$('#parent').mousedown(function(e){
    var parent = $(e.currentTarget)
    if (!parent.is(':focus')) {
        parent.focus()
    }
}).focus(function(e){
    console.log('focused')
}).blur(function(e){
    console.log('blurred')
})

If we don't want to disable text selection, another option is to focus on the parent from the child's mouseup handler; however, this way the parent will blur and then focus again, which prevents us from knowing when a focus or blur is "real" rather than merely a transient consequence of our focus-propagation logic:

$('#child').mouseup(function(e){
    $(e.currentTarget).closest('[tabindex]').focus()
})
$('#parent').mousedown(function(e){
    var parent = $(e.currentTarget)
    if (!parent.is(':focus')) {
        parent.focus()
    }
}).focus(function(e){
    console.log('focused')
}).blur(function(e){
    console.log('blurred')
})

The third option has the virtues of both of the above approaches, but is the most complicated logically:

$('#parent').mousedown(function(e){
    var parent = $(e.currentTarget)
    var parentWasClicked = parent.is(e.target)
    var parentHasFocus = parent.is(':focus')
    if (parentWasClicked && !parentHasFocus) {
        parent.focus()
    } else if (parentHasFocus && !parentWasClicked) {
        window.ignoreFocusChanges = true
    }
})
.mouseup(function(e){
    var parent = $(e.currentTarget)
    if (!parent.is(':focus')) {
        parent.focus()
    }
})
.blur(function(e){
    if (window.ignoreFocusChanges) {
        return
    }
    console.log('blurred')
})
.focus(function(e){
    if (window.ignoreFocusChanges) {
        window.ignoreFocusChanges = false
        return
    }
    console.log('focused')
})
查看更多
别忘想泡老子
5楼-- · 2019-04-29 04:46

Let root be your #test div

function prevent_blur_in_subtree = function (event) {
  if (event.originalEvent && event.target != root.get(0) && $(event.target).closest(root).size() == 1) {
        $(window).one("mousedown", prevent_blur_in_subtree);
        event.stopPropagation();
        event.preventDefault();
        return false;
    }
}
root.bind("click", function () {
  if (!$(this).is(":focus")) {
    $(this).trigger("focus");
  }
})
.bind("focus", function () {
   $(window).one("mousedown", prevent_blur_in_subtree);
});

You should use event.stopPropagation() in any click in root, that should not force focus event.

This problem is one of the great amount of problems in any IE (5-11). You can see that IE's source code was not cleaned since 1999. I am laughing when people are talking about "IE 11 is a modern browser" or "IE 11 care about standards".

查看更多
欢心
6楼-- · 2019-04-29 04:55

Intercepting events and using JS to set focus ended up causing more problems.

I eventually figured out that using "normal" tags like divs or spans makes IE behave incorrectly. But use something like var or any custom tag and IE starts to behave like a proper browser.

See updated example: http://jsfiddle.net/fergal_doyle/anXM3/16/

HTML:

<div tabindex="0" id="test">
     <var class="iesux">Works</var>
     <foo class="iesux">Works</foo>
     <div class="iesux">Doesn't work in IE</div>
     <span class="iesux">Doesn't work in IE</span>
</div>

CSS:

div {
     border:1px solid #000;
     padding:20px;
     background-color:red;
}
.iesux {
     border:1px solid #000;
     display:block;
     padding:8px;
     background-color:#FFF;
     cursor:default;
     width:200px;
}

JS:

document.createElement("foo");

var $div = $("#test");

$div.on("blur", function (e) {
     console.log("blur");
})
     .on("focus", function (e) {
     console.log("focus")
});
查看更多
登录 后发表回答