在 IE 中单击 tabindex=0 的元素将导致该元素获得不可见的焦点。获得可见焦点的方法是在元素还没有不可见焦点时以编程方式调用 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')
})
如果child是inline或者是没有设置宽度的block,效果和直接点击parent是一样的。但是,如果子级是内联块或设置了宽度的块,并且父级已经具有焦点,则父级将在执行 mousedown 处理程序后立即 blur()。我们有三种不同的方式进行,有不同的权衡。
一种选择是仅使用 preventDefault() 来抑制模糊;这种方法的优点是 blur() 永远不会触发, focus() 不会冗余触发,这允许我们在 focus 和 blur 处理程序中编写简单的逻辑;这种方法的缺点是它禁用了文本选择:
$('#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')
})
如果我们不想禁用文本选择,另一种选择是从孩子的 mouseup 处理程序中关注父级;然而,这样父级会模糊然后再次聚焦,这使我们无法知道焦点或模糊何时是“真实的”,而不仅仅是我们的焦点传播逻辑的瞬态结果:
$('#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')
})
第三种选择具有上述两种方法的优点,但在逻辑上是最复杂的:
$('#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')
})