考虑以下HTML& JavaScript,也在这里:http://jsfiddle.net/5CetH/
<!DOCTYPE html>
<html>
<head>
<title>Untitled Page</title>
<script type="text/javascript">
var i=0;
function _focus() {
var message = document.getElementById("message");
message.value = message.value + ++i + ". Focus\r\n";
}
function _blur() {
var message = document.getElementById("message");
message.value = message.value + ++i + ". Blur\r\n";
}
</script>
</head>
<body>
<div style="background-color: Aqua; width: 100px; height: 50px" onfocus="_focus()" onblur="_blur()" tabindex="0">
<input name="rb" type="radio" /><br />
<input name="rb" type="radio" />
</div>
<br />
<textarea id="message" rows="15" cols="50"></textarea>
</body>
</html>
我想要的行为如下:
它似乎在Chrome中运行良好,但不适用于FireFox 8或IE 9。
有关如何修复代码以使其正常工作的任何建议吗?
谢谢, 斯蒂芬
答案 0 :(得分:3)
只有一些元素可以被聚焦,例如<a>
和<input>
。对于其他元素,您必须自己实现它。
// window.addFocusToElem(elem, callbacks) - returns id for removeFocusFromElem
// window.removeFocusByID(id)
// in IE <= 8 the blur events get fired in the wrong order!
// callbacks: { onFocus: function(e) {}, onBlur: function(e) {} } - both methods are optional
(function() {
var addEvent, removeEvent;
(function() {
// sometimes in IE <= 8 the window.blur event isn't fired when the
// window loses the focus but instead it is fired when the window gets
// the focus back again. This requires some hacking - and because
// 'fireEvent' in window === false it even requires some more hacking.
var hasFocus = true;
var queue = [];
addEvent = function(node, evtType, callback) {
if('addEventListener' in node)
node.addEventListener(evtType, callback, false);
else { // IE <= 8
if(evtType === 'blur') {
queue.push(callback);
}
node.attachEvent('on' + evtType, callback);
}
}
removeEvent = function(node, evtType, callback) {
if('removeEventListener' in node)
node.removeEventListener(evtType, callback, false);
else { // IE <= 8
if(evtType === 'blur') {
var length = queue.length;
while(length--) {
if(callback === queue[ length ]) {
queue.splice(length, 1);
break;
}
}
}
node.detachEvent('on' + evtType, callback);
}
}
// IE <= 8
if('documentMode' in document && document.documentMode <= 8) {
setInterval(function() {
if(!document.hasFocus() && hasFocus) {
hasFocus = false;
for(var o in queue) {
queue[ o ](document.createEventObject());
}
}
}, 100);
addEvent(window, 'focus', function(e) {hasFocus = true;});
}
})();
function doClick(node, evtType) {
if('click' in node) { // most Browser (HTML-DOM)
node.click();
} else if('createEvent' in document) { // at least Chrome (16)
var e = document.createEvent('MouseEvents');
e.initEvent('click', true, true);
node.dispatchEvent(e);
} else {
}
}
var id = 0;
var queue = [];
window.addFocusToElem = function addFocusToElem(elem, callbacks) {
var _id = id++;
var entry = queue[ _id ] = {
elem: elem,
onFocus: function(e) {
removeEvent(entry.elem, 'click', entry.onFocus);
addEvent(document, 'click', entry.onBlur);
if('onFocus' in callbacks &&
typeof callbacks.onFocus === 'function') {
callbacks.onFocus(e);
}
},
onBlur: function(e) {
var node = 'target' in e ? e.target : e.srcElement;
while(node) {
if(node === entry.elem) {
break;
}
node = node.parentNode;
}
if(!node) {
removeEvent(document, 'click', entry.onBlur);
addEvent(area, 'click', entry.onFocus);
if('onBlur' in callbacks &&
typeof callbacks.onBlur === 'function') {
callbacks.onBlur(e);
}
}
}
};
addEvent(elem, 'click', entry.onFocus);
addEvent(window, 'blur', function(e) {
doClick(elem.parentNode);
});
addEvent(document, 'keyup', function(e) {
if(e.keyCode === 9) { // tab
var node = 'target' in e ? e.target : e.srcElement;
while(node) {
if(node === elem) {
doClick(elem);
break;
}
node = node.parentNode;
}
if(!node) {
doClick(elem.parentNode);
}
}
});
return _id;
};
window.removeFocusByID = function removeFocusByID(id) {
if(id in queue) {
var entry = queue[ id ];
removeEvent(entry.elem, 'click', entry.onFocus);
removeEvent(document, 'click', entry.onBlur);
delete queue[ id ];
return true;
}
return false;
};
})();
用法:
<div style="background-color: Aqua; width: 100px; height: 50px" id='area'>
<input name="rb" type="radio">Foo<br>
<input name="rb" type="radio">Bar
</div>
<script type='text/javascript'>
var id = addFocusToElem(document.getElementById('area'), {
onFocus: function(e) {
// statements
},
onBlur: function(e) {
// statements
}
});
// removeFocusByID(id);
</script>
答案 1 :(得分:0)
尽管我讨厌使用计时器,因为他们非常讨厌,这是我用计时器提出的解决方案。
这是如何工作的,它使用一个计时器来调用模糊事件并取消计时器,如果我对焦于我的一个单选按钮或包含单选按钮的div。
<!DOCTYPE html>
<html>
<head>
<title>Untitled Page</title>
<script type="text/javascript">
var i = 0;
var focused = false;
var blurTimer = null;
function startBlurTimer() {
blurTimer = window.setTimeout("blurTimerFinished()", 1);
}
function cancelBlurTimer() {
if (blurTimer != null) {
clearTimeout(blurTimer);
blurTimer = null;
}
}
function blurTimerFinished() {
cancelBlurTimer();
focused = false;
var message = document.getElementById("message");
message.value = message.value + ++i + ". Blur\r\n";
}
function _focus() {
if (blurTimer == null) {
focused = true;
var message = document.getElementById("message");
message.value = message.value + ++i + ". Focus\r\n";
}
else
cancelBlurTimer();
}
function _blur() {
if (focused) {
startBlurTimer();
}
}
</script>
</head>
<body>
<div style="background-color: Aqua; width: 100px; height: 50px" onfocus="_focus()" onblur="_blur()" tabindex="0">
<input onfocus="_focus()" onblur="_blur()" name="rb" type="radio" /><br />
<input onfocus="_focus()" onblur="_blur()" name="rb" type="radio" />
</div>
<br />
<textarea id="message" rows="15" cols="50"></textarea>
</body>
</html>
答案 2 :(得分:0)
另一种解决方案......
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
</head>
<body onload="test()">
<input>
<div style="background-color: Aqua; width: 100px; height: 50px" id='area'>
<input id="rb1" name="rb" type="radio">Foo<br>
<input id="rb2" name="rb" type="radio">Bar
</div>
<input>
<pre id='dump'></pre>
<script type='text/javascript'>
'use strict';
function dump(data) {
document.getElementById('dump').appendChild(document.createTextNode(data + '\n'));
}
function addEvent(node, evtType, callback)
{
if('addEventListener' in node)
node.addEventListener(evtType, callback, false);
}
function removeEvent(node, evtType, callback)
{
if('removeEventListener' in node)
node.removeEventListener(evtType, callback, false);
}
function addHandler(element, focus, blur)
{
var event = {
focused: false,
element: element,
focus: focus,
blur: blur,
onClick: function(e) {
event.targetNode(e).focus(); // Because Chrome doesn't focus when clicked
},
onFocus: function(e) {
if (event.focused)
return;
event.focused = true;
addEvent(document, 'click', event.onBlur);
addEvent(document, 'keyup', event.onBlurIfTab);
focus();
},
onBlur: function(e) {
if (!event.focused)
return;
if (event.thisElement(event.targetNode(e)))
return;
event.focused = false;
removeEvent(document, 'click', event.onBlur);
removeEvent(document, 'keyup', event.onBlurIfTab);
blur();
},
onBlurIfTab: function(e) {
if (e.keyCode === 9) { event.onBlur(e) }
},
targetNode: function(e) {
return 'target' in e ? e.target : e.srcElement;
},
thisElement: function(node) {
// Test to see if we're on the element node
while (node) {
if (node == event.element) {
return true;
}
node = node.parentNode;
}
return false;
},
findButtons: function() {
var buttons = [];
event.innerButtons(event.element, buttons);
return buttons;
},
innerButtons: function(node, results) {
if (node.nodeName == "INPUT") {
results.push(node);
}
else
if (node.childNodes) {
var children = node.childNodes;
for (var i in children)
event.innerButtons(children[i], results);
}
}
};
var buttons = event.findButtons();
for (var i = 0; i < buttons.length; i++) {
addEvent(buttons[i], 'focus', event.onFocus);
addEvent(buttons[i], 'click', event.onClick);
}
}
function focus()
{
dump('focus');
}
function blur()
{
dump('blur');
}
function test()
{
var area = document.getElementById('area');
addHandler(area, focus, blur);
}
</script>
</body>
</html>