【发布时间】:2012-05-05 23:12:06
【问题描述】:
我有一个模态 jQuery 对话框和另一个在对话框后面接受 ESC 键事件的元素。当 jQuery 对话框启动时,我不希望这个 ESC 键事件传播。现在发生的情况是,当我点击 ESC 时,它会关闭对话框并触发背景元素上的 ESC 事件处理程序。
当一个 jQuery 对话框被关闭时,我如何吃掉 ESC 键事件?
【问题讨论】:
标签: jquery jquery-ui jquery-ui-dialog
我有一个模态 jQuery 对话框和另一个在对话框后面接受 ESC 键事件的元素。当 jQuery 对话框启动时,我不希望这个 ESC 键事件传播。现在发生的情况是,当我点击 ESC 时,它会关闭对话框并触发背景元素上的 ESC 事件处理程序。
当一个 jQuery 对话框被关闭时,我如何吃掉 ESC 键事件?
【问题讨论】:
标签: jquery jquery-ui jquery-ui-dialog
在内部,jQuery UI 的对话框的closeOnEscape 选项是通过将keydown 侦听器附加到文档本身来实现的。因此,一旦 keydown 事件一直冒泡到顶层,对话框就会关闭。
因此,如果您想继续使用转义键关闭对话框,并且希望阻止转义键传播到父节点,您需要自己实现 closeOnEscape 功能以及使用事件对象上的stopPropagation 方法(参见MDN article on event.stopPropagation)。
(function() {
var dialog = $('whatever-selector-you-need')
.dialog()
.on('keydown', function(evt) {
if (evt.keyCode === $.ui.keyCode.ESCAPE) {
dialog.dialog('close');
}
evt.stopPropagation();
});
}());
它的作用是监听对话框中发生的所有 keydown 事件。如果按下的键是转义键,您将照常关闭对话框,并且无论 evt.stopPropagation 调用如何,都会阻止 keydown 冒泡到父节点。
我在这里有一个活生生的例子 - http://jsfiddle.net/ud9KL/2/。
【讨论】:
closeOnEscape: false,否则对话框仍然会安装自己的处理程序并导致问题。
你需要 closeOnEscape...
示例代码:
$(function() {
$("#popup").dialog({
height: 200,
width: 400,
resizable: false,
autoOpen: true,
modal: true,
closeOnEscape: false
});
});
【讨论】:
你可以使用下面的
$(document).keyup(function (e) {
if (e.keyCode == 27) {
$('#YourDialogID').dialog('close')
}
});
【讨论】:
您需要修改对话框后面的元素的代码,以查看对话框是否已打开并且是否按下了转义键并忽略这种情况。
【讨论】:
因此,如果模态窗口在 ui 对话框顶部打开,则 ESC 必须只关闭模态窗口并使 ui 对话框保持打开状态。我不想为对话框禁用 closeOnEscape,如果另一个模态在它上面打开,只需抑制它。
我对 jquery-ui-1.12.1 中的 $(document).on("keydown", ...) 或 $dialog.on("keydown", ...) 不满意。我调用小部件方法 _off 和 _on 来删除原始 keydown 事件并将其替换为我自己的拦截事件,在该事件中我可以什么都不做或运行原始处理程序代码。
可能有一种更优雅的方式来调用原始 keydown 事件而不复制代码,但我还没有想出来。
我在使用 $dialog.dialog(...) 创建 PatchCloseOnEscape($dialog) 之后调用它。
/**
* Tedium required to prevent the jQuery-UI dialog closing when we hit the ESC key to close
* a modal window opened from the dialog while the dialog is still open.
*/
private static PatchCloseOnEscape($dialog: JQuery): void
{
// Get dialog widget
let dialog = $dialog.data("ui-dialog");
// Remove original keydown event
dialog._off(dialog.uiDialog, "keydown");
// Add our new keydown event
dialog._on(dialog.uiDialog, {
keydown: function (event)
{
// Only close on escape if a modal window is not showing.
if (<check if modal window is open> == true)
{
return;
}
////////////////////////////////////////////////////////////////////////////////
// Copied from original keydown event in jquery-ui-1.12.1.js line 12278 - 12305
if (this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
event.keyCode === (<any>$).ui.keyCode.ESCAPE)
{
event.preventDefault();
this.close(event);
return;
}
// Prevent tabbing out of dialogs
if (event.keyCode !== (<any>$).ui.keyCode.TAB || event.isDefaultPrevented())
{
return;
}
var tabbables = this.uiDialog.find(":tabbable"),
first = tabbables.filter(":first"),
last = tabbables.filter(":last");
if ((event.target === last[0] || event.target === this.uiDialog[0]) &&
!event.shiftKey)
{
this._delay(function ()
{
first.trigger("focus");
});
event.preventDefault();
} else if ((event.target === first[0] ||
event.target === this.uiDialog[0]) && event.shiftKey)
{
this._delay(function ()
{
last.trigger("focus");
});
event.preventDefault();
}
////////////////////////////////////////////////////////////////////////////////
}
});
}
【讨论】: