javascript - 支持用escape取消DHTML对话框

标签 javascript onkeydown

想象一个带有以下标记的 DHTML 对话框:

<div id="someDialog" class="dialog">
    <h2>Title of dialog</h2>

    Lots: <input ...>
    of: <select ...>
    controls: <textarea ...>

    <input type="submit" value="OK">
    <input type="reset" value="Cancel">
</div>

用户会期望点击 escape 来取消对话框。这本身并不难——只需将 keydown 事件处理程序添加到 document.documentElement 以检查 ev.keyCode == 27,并使用它关闭页面上最顶部的对话框。

问题是——在某些情况下,浏览器首先看到转义键是很重要的。例如,如果浏览器提示 <input type="text"> 的自动完成菜单, 按 escape 应该取消它,而不是取消对话框。如果您调出 <select> 的下拉/弹出菜单, 按 escape 应该关闭它,而不是对话框。

当且仅当浏览器不需要为某些东西使用转义键时,您如何安排处理窗口的转义键?


编辑:Stack Exchange 本身就有这个错误。如果我单击“您希望通过电子邮件将对您的问题的答复发送给您吗?”链接,打开一个 DHTML 对话框,然后选择频率下拉菜单,按 alt-down 打开下拉菜单,然后退出关闭下拉菜单,整个对话框关闭。这不应该发生。在这些情况下,浏览器的控件实现应该首先选择转义键。

最佳答案

经过一些体面的研究和试错,这里最好/唯一的解决方案似乎是创建您自己的自定义表单控件。


以下是解决问题失败的尝试。

http://jsfiddle.net/CoryDanielson/4jBgs/10/

基本原理如下。


首先,有一个 activeInput 变量,它存储用户关注的输入的 DOMElement。 (仅当输入可转义时)

var activeInput = false;

为了填充此变量,我创建了一个您提到的可以转义的 DOMElement 数组(具有自动完成功能的文本框,选择元素)

var escapableElements = [];
escapableElements = escapableElements.concat(
    Array.prototype.slice.call(document.getElementsByTagName('select')),
    Array.prototype.slice.call(document.getElementsByTagName('input'))
    //add more elements here
);

然后遍历数组并为 focusblur(失去焦点)事件附加 eventListeners。 (我在这篇文章的底部包含了每个函数)

forEach(escapableElements, function() {
    this.addEventListener('focus', registerActiveElement);
    this.addEventListener('blur', deregisterActiveElement);
});

function registerActiveElement() {
    if (!activeInput)
        activeInput = this;
    //console.log('registered'); //testing only
}

function deregisterActiveElement() {
    if (activeInput)
        activeInput = false;
    //console.log('deregistered'); //testing only
}

之后,我为 keydown 事件连接了一个 eventListener。在其中,我检查是否有 activeInput 如果有,我只是 return true; 这会让浏览器做它想做的事(从自动完成中逃脱,等)如果没有 activeInput,我检查是否按下了 ESC 并调用 hide_dialog_box(event.keyCode);

与您问题中有关处理 ESC 按键的段落的唯一区别是,我事先检查了是否有 activeInput。如果有 activeInput,我什么都不做(让浏览器本地处理 ESC)如果没有 activeInput 我调用了 event.preventDefault()将取消浏览器对 ESC 的 native 处理,然后调用函数 hide_dialog_box(keyCode) 然后执行 return false; 这也有助于防止浏览器处理 ESC 按键。

document.addEventListener('keydown', function(event) {
    if (!activeInput) {
        if (event.keyCode == 27) { //esc
            event.preventDefault();
            hide_dialog_box(event.keyCode);
            return false;
        }
    } else {
        return true; //if active input, let browser function
    }
    /*
        if the browser prompts with an autocomplete menu for 
        <input type="text">, or options on a <select> drop down
        pressing escape will cancel that, not cancel the dialog. 
    */
});

代码的最后 2 个片段是函数 hide_dialog_box(keyCode) 和我编写的用于循环遍历 NodeList 的函数,称为 escapableElements

function hide_dialog_box(keyCode) {
    var dialog_box = document.getElementById('dialog_box');
        dialog_box.style.display = 'none';
}

function forEach(list, callback) {
    for (var i = 0; i < list.length; i++)
    {
        //calls the callback function, but places list[i] as the 'this'
        callback.call(list[i]);
    }
}

关于javascript - 支持用escape取消DHTML对话框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10178793/

相关文章:

javascript - 如何知道何时向下滚动?

javascript - 为什么这个简单的backbone.js 应用程序不能持久保存并读取到本地存储?

Javascript:将 onkeydown 事件添加到提示()

javascript - CKEditor 键事件未正确更新文本

javascript - 简单的javascript击键计数

javascript - 为什么 keydown 监听器在 IE 中不起作用

javascript - 如何获取jquery Nice select的值

javascript - 错误 JSON.parse : unexpected end of data at line 1 column 1 of the JSON data

javascript - HTML 在新窗口中

android - 假 KeyEvent 不能*完全*像 "real"按钮一样工作。为什么?