一个简单的 html 页面只包含两个控件,一个文本框和一个按钮。页面加载后,如果用户单击文本框内并按“alt”+p(按钮快捷键),则消息应显示为“我来自按键!!!”但如果用户单击文本框内部以外的任何位置,则消息应显示为“仅当焦点位于文本框外部时才应调用我!!!”。完整代码如下所示:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function keyDown() {
if (event.altKey && event.keyCode == 80) {
event.returnValue = false;
event.cancelBubble = true;
event.keyCode = 0;
alert("I'm from key down!!!");
}
}
function clickMe() {
alert("I should be called only when the focus is outside the textbox!!!");
}
</script>
</head>
<body>
<div>
<input type="text" onkeydown ="keyDown();" />
<input type="button" value="Click me" accesskey="p" onclick="clickMe();" />
</div>
</body>
</html>
在 IE10 及以下版本中运行良好。但它在 IE11 和 Chrome 中不起作用,而是相继显示两条警报消息,例如“我从按键按下了!!!”和“只有当焦点位于文本框之外时才应该调用我!!!”这是不可取的。因此,keyDown()
事件处理程序已更改为支持 IE10+ 和 Chrome,例如
function keyDown() {
if (event.altKey && event.keyCode == 80) {
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);
event.keyCode = 0;
alert("I'm from key down!!!");
}
}
但是在这种情况下 event.stopPropagation() 不起作用,知道为什么吗?
最佳答案
accesskey
事件总是被触发
(除非您暂时禁用它)
大多数浏览器总是会触发绑定(bind)到 accesskey
属性的事件,即使其他绑定(bind)事件处理程序使用常见策略,例如 return false
、stopPropagation
、 stopImmediatePropagation
、preventDefault
、cancelBubble
等,这些在正常情况下可有效阻止事件冒泡和默认行为。
但在您的情况下,您有一个处理程序检查与您通过 accesskey
绑定(bind)到另一个元素的相同的按键组合。因此,每次在文本字段具有焦点时输入组合键时,两个处理程序都会被触发:首先在 keyDown
处理程序中,然后无论任何尝试阻止该事件冒泡,clickMe
处理程序被触发,因为它是由 accesskey
激活的。
一种解决方案是,当您不想收听 accesskey
属性时(例如当您的文本输入具有焦点时),暂时删除它们,然后在您不想忽略时恢复它们它们不再存在(例如当您的文本输入失去焦点时)。
参见 this answer for a jQuery powered solution您可以使用它作为跳板来创建一个简单的 JS 解决方案来满足您的需求。
示例:
<script type="text/javascript">
/* Function to cache accesskey attributes */
function cacheAccessKeys() {
/* Get all elements with accesskeys
// This could be modified to select a smaller subset of elements */
var akEls = document.querySelectorAll('[accesskey]');
/* Iterate over each element in the set of matched elements */
Array.prototype.forEach.call(akEls, function (el, i) {
/* Set the value of data-accesskey to the value of accesskey */
el.setAttribute('data-accesskey', el.getAttribute('accesskey'));
/* Remove the accesskey attribute
// to temporarily disable accesskey binding */
el.removeAttribute('accesskey');
});
}
/* Function to restore accesskey attributes */
function restoreAccessKeys() {
/* Get all elements with accesskeys
// This could be modified to select a smaller subset of elements */
var akEls = document.querySelectorAll('[data-accesskey]');
/* Iterate over each element in the set of matched elements */
Array.prototype.forEach.call(akEls, function (el, i) {
/* Set the value of accesskey to the value of data-accesskey
// to restore accesskey binding */
el.setAttribute('accesskey', el.getAttribute('data-accesskey'));
/* Clean-up (perhaps unnecessary)
// In case the accesskey attributes are set dynamically elsewhere,
// this prevents mismatched caching. */
el.removeAttribute('data-accesskey');
});
}
function keyDown(e) {
if (e.altKey && e.keyCode === 80) {
console.log("I'm from key down!!!");
}
}
function clickMe() {
console.log("I should be called only when the focus is outside the textbox!!!");
}
</script>
<div>
<!-- On focus: Cache/remove accesskey attributes -->
<!-- On keydown: Now the key combo in here won't trigger other handlers. -->
<!-- On blur: Restore accesskey attributes -->
<input type="text"
onfocus="cacheAccessKeys();"
onkeydown="keyDown(event);"
onblur="restoreAccessKeys();"
/>
<!-- On click: Activated by Alt + p access key combo
//-- only when text field does NOT have focus. -->
<input type="button"
accesskey="p"
value="Click me"
onclick="clickMe();"
/>
</div>
关于Javascript event.stopPropagation() 不适用于 `accesskey` 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34006721/