Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有一种使用JavaScript处理文件选择对话框的现代/新方法?_Javascript_Html_Html Input - Fatal编程技术网

是否有一种使用JavaScript处理文件选择对话框的现代/新方法?

是否有一种使用JavaScript处理文件选择对话框的现代/新方法?,javascript,html,html-input,Javascript,Html,Html Input,这是我的特定用例:我想点击文件对话框的“取消”按钮。原因是我经常使用承诺,我希望在选择文件时解析承诺,但在取消对话框时拒绝承诺(或使用null解析承诺) 然而,我在这里和其他地方找到的这个问题的每一个“解决方案”几乎都只是一个(大多不可靠)的解决办法,比如捕捉主体的焦点事件。 我自己的解决方法是将当前的Promissions reject函数保存在(module local)全局变量中,并在第二次调用该函数时调用它,这样至少可以在第二个对话框中选择文件时实现该承诺 问题是:是否有一种现代的、可用

这是我的特定用例:我想点击文件对话框的“取消”按钮。原因是我经常使用承诺,我希望在选择文件时解析承诺,但在取消对话框时拒绝承诺(或使用null解析承诺)

然而,我在这里和其他地方找到的这个问题的每一个“解决方案”几乎都只是一个(大多不可靠)的解决办法,比如捕捉
主体的焦点事件。
我自己的解决方法是将当前的Promissions reject函数保存在(module local)全局变量中,并在第二次调用该函数时调用它,这样至少可以在第二个对话框中选择文件时实现该承诺

问题是:是否有一种现代的、可用的方法来处理这个案件,而不是一种变通方法?如果是,是什么

这是我当前的代码,使用TypeScript和JQuery:

export function selectJsonFile() {
    return new Promise<File>((resolve, reject) => {
        let $input = $(`<input type="file" accept=".json">`);
        $input.hide().change(() => {
            let file = (<HTMLInputElement>$input[0]).files[0];
            if (file)
                resolve(file);
            else
                reject();
            $input.remove();
        }).appendTo($("body")).click();
    });
}

现在,有没有一个很好的处理方法?我找不到任何消息。

即使在2018年,也无法知道用户是否单击了“取消”,只能在对话框打开时跟踪您是否看到来自页面上任何位置的用户事件

当文件对话框处于打开状态时,页面应处于完全非活动状态,因此设置一些指示用户单击文件输入元素时对话框处于打开状态的内容,然后监视对话框打开时不可能出现的一组详尽的用户输入事件。如果该监视器看到任何事件,那么您知道用户实际上没有查看文件对话框,因此我们可以推断他们取消了该对话框。此时,您可以触发“file dialog Get cancelled”处理程序函数,并解除事件监视器的绑定

让我们编写一个监视器:

class EventMonitor {
  constructor(dialogWasCancelled) {
    this.dialogWasCancelled = dialogWasCancelled;
    // don't use a class function here, since we need to
    // unregister the exact function handle later, and we
    // don't get those if we use e=>this.x() for listening.
    this.x = (function() {
      this.dialogWasCancelled();
      this.unregister();
    }).bind(this);
    this.register();
  }
  register() {
    document.addEventListener("mousemove", this.x);
    document.addEventListener("touchstart", this.x);
    document.addEventListener("keypress", this.x);
    window.addEventListener("scroll", this.x);
  }
  unregister() {
    document.removeEventListener("mousemove", this.x);
    document.removeEventListener("touchstart", this.x);
    document.removeEventListener("keypress", this.x);
    window.removeEventListener("scroll", this.x);
  }
}
虽然body
focus
事件不是超级可靠的,但是
鼠标向下
触摸启动
滚动
按键
事件是超级可靠的。当您看到这些内容时,您就知道用户正在查看您的页面,而不是应用程序文件对话框。你想要这四个,因为你可能有传统的桌面或触摸/移动用户,即使是传统的桌面用户,也有很多人出于各种原因只能使用键盘。最后,您还需要检查滚动,因为这取决于输入设备,因为这是最常见的用户交互,并且之前可能根本没有任何鼠标、触摸或按键事件

这样,我们可以可靠地监视页面,以确定是否选择了文件,或者用户是否取消了对话框:

let monitor = false;

function handleFiles(evt) {
  // some browsers _will_ kick in a change event if
  // you had a file, then "cancel"ed it on a second
  // select. Chrome, for instance, considers that
  // an action that empties the selection again.
  let files = evt.target.files;
  if (files.length === 0) return dialogCancelled(evt);
  console.log("user selected a file");
  monitor = monitor.unregister();
}

function dialogCancelled(evt) {
  console.log("user did not select a file");
  monitor = monitor.unregister();
}

let fileInput = document.querySelector("input[type=file]")

fileInput.addEventListener("change", e => handleFiles(e));
fileInput.addEventListener("click", e => (monitor = new EventMonitor(dialogCancelled)));

你可以亲自测试代码,我会创建一个上传模式,上面有“确认”或“取消”。。。然后你就可以使用按钮上的事件或模式隐藏。不需要滚动自定义对话框。您可以可靠地得到有关是否单击了“取消”的答案,但您确实需要监视正确的事件。
focus
事件基本上是完全无用的,您想要的是监视用户交互,因为当对话框打开时,用户不能进行任何页面交互。因此,这意味着临时监控初始鼠标/触摸事件,以及滚动事件(因为浏览器在某些条件下,尤其是在移动设备上,会将一个切换到另一个)。我想引用它作为特定问题的副本,我不认为引用它对任何人都有任何帮助,因为那里的答案正是我不想使用的变通方法,它们是我问这个问题的最初原因。另外,现在这里有一个更好的答案。感谢您提供迄今为止最可靠的解决方案!下面是我如何在我的项目中实现它的(同样,TS/JQuery):是的,这似乎是一个相当合理的实现。使用承诺可以使它更优雅,例如,而不是一个评论,如果它比既定的答案更有用,那么做出一个新的答案(即使晚了几年)是很好的。作为一种评论,你基本上是说你不在乎别人是否看到它,这将是一种耻辱,因为我不是需要知道这一点的人=)(另外,在本质上是2021年,我建议异步/等待而不是简单的承诺)
let monitor = false;

function handleFiles(evt) {
  // some browsers _will_ kick in a change event if
  // you had a file, then "cancel"ed it on a second
  // select. Chrome, for instance, considers that
  // an action that empties the selection again.
  let files = evt.target.files;
  if (files.length === 0) return dialogCancelled(evt);
  console.log("user selected a file");
  monitor = monitor.unregister();
}

function dialogCancelled(evt) {
  console.log("user did not select a file");
  monitor = monitor.unregister();
}

let fileInput = document.querySelector("input[type=file]")

fileInput.addEventListener("change", e => handleFiles(e));
fileInput.addEventListener("click", e => (monitor = new EventMonitor(dialogCancelled)));