查找是否取消'点击了文件输入

时间:2014-04-06 19:27:14

标签: javascript html file input

我尝试使用在不同位置描述的黑客使用:

document.body.onfocus = checkOnCancel();

一个例子:

var fileSelectEle = document.getElementById('fileinput');

fileSelectEle.onclick = charge;

function charge()
{
    document.body.onfocus = checkOnCancel;
}

function checkOnCancel()
{
    alert("FileName:" + fileSelectEle.value + "; Length: " + fileSelectEle.value.length);
    if(fileSelectEle.value.length == 0) alert('You clicked cancel!')
    else alert('You selected a file!');
    document.body.onfocus = null;
}

这里有什么不对吗?因为fileSelectedEle.value始终返回先前的执行值而不是用户选择的值。 这是输入文件的预期行为吗?如何解决此问题以阅读所选的实际文件?

http://jsfiddle.net/smV9c/2/

您可以通过以下方式重现错误:

步骤1:SelectFile - 一些选择一些文件(并注意输出)

步骤2:选择文件 - 按取消(并注意输出)

5 个答案:

答案 0 :(得分:10)

一种解决方案是使用onchange的{​​{1}}事件。

input

这可以正确响应所选文件名中的更改,因为您可以在此处测试:http://jsfiddle.net/munderwood/6h2r7/1/

与您尝试执行此操作的方式唯一不同的是,如果您立即取消,或连续两次取消,或连续两次选择相同的文件,则该事件将不会触发。但是,每次文件名实际更改时,您都会正确检测到它。

我不确定为什么你的原始尝试不起作用,尽管我最好的猜测是var fileSelectEle = document.getElementById('fileinput'); fileSelectEle.onchange = function () { if(fileSelectEle.value.length == 0) { alert('You clicked cancel - ' + "FileName:" + fileSelectEle.value + "; Length: " + fileSelectEle.value.length); } else { alert('You selected a file - ' + "FileName:" + fileSelectEle.value + "; Length: " + fileSelectEle.value.length); } } 事件异步触发,在onfocus控件的属性之前是时间问题已完成更新。

更新:要确定用户每次关闭文件对话框时选择的内容,即使没有任何更改,也可以通过在再次接收焦点之间添加短暂延迟来避开时间问题,检查文件输入的值。以下版本的input不会在收到焦点后立即调用checkOnCancel,而是会在之后的十分之一秒内调用它。

charge

这是一个有效的版本:http://jsfiddle.net/munderwood/6h2r7/2/

答案 1 :(得分:0)

  

这里有什么不对吗?因为fileSelectedEle.value始终返回先前的执行值而不是用户选择的值。这是输入文件的预期行为吗?如何解决此问题以读取所选的实际文件?

没有错,这是预期的行为。如果用户取消了文件选择过程,那么它就好像从未启动它一样。因此,之前的值保留不变。

答案 2 :(得分:0)

您可以挂钩window.focus事件,当它们取消窗口的文件选择框时会被触发。然后检查它是否确实选择了文件。

答案 3 :(得分:0)

//此代码在chrome中适用于文件选择,请尝试

     <--write this line in HTML code-->
     <input type='file' id='theFile' onclick="initialize()" />  
    var theFile = document.getElementById('theFile');
    function initialize() {
        document.body.onfocus = checkIt;
        console.log('initializing');
    }

    function checkIt() {
        setTimeout(function() {
            theFile = document.getElementById('theFile');
            if (theFile.value.length) {
                alert('Files Loaded');
            } else {
                alert('Cancel clicked');
            }
            document.body.onfocus = null;
            console.log('checked');
        }, 500);
    }

答案 4 :(得分:0)

处理用户可以取消文件输入的所有各种方式变得很棘手。

  • 在大多数浏览器上,文件选择器会立即打开并将用户带出浏览器。我们可以使用 window.focus 事件来检测他们何时回来,而无需选择任何东西来检测取消
  • 在 ios 浏览器上,用户首先会看到一个 ios 模式,让他们可以在相机 - 与图库之间进行选择。用户可以通过单击远离模式从这里取消。因此,我们可以使用 window.touchend 来检测这一点
  • 可能还有其他浏览器和案例在取消时表现不同,这也尚未发现

实现明智,您可以使用 addEventListener 来确保您不会替换可能已经在窗口上的其他事件侦听器 - 并在触发后轻松清理事件侦听器。例如:

window.addEventListener('focus', () => console.log('no file selected'), { once: true });

下面是一个示例,说明如何使用它以编程方式获取图像,处理上面列出的注意事项(打字稿):

/**
 * opens the user OS's native file picker, returning the selected images. gracefully handles cancellation
 */
export const getImageFilesFromUser = async ({ multiple = true }: { multiple?: boolean } = {}) =>
  new Promise<File[]>((resolve) => {
    // define the input element that we'll use to trigger the input ui
    const fileInput = document.createElement('input');
    fileInput.setAttribute('style', 'visibility: hidden'); // make the input invisible
    let inputIsAttached = false;
    const addInputToDom = () => {
      document.body.appendChild(fileInput); // required for IOS to actually fire the onchange event; https://stackoverflow.com/questions/47664777/javascript-file-input-onchange-not-working-ios-safari-only
      inputIsAttached = true;
    };
    const removeInputFromDom = () => {
      if (inputIsAttached) document.body.removeChild(fileInput);
      inputIsAttached = false;
    };

    // define what type of files we want the user to pick
    fileInput.type = 'file';
    fileInput.multiple = multiple;
    fileInput.accept = 'image/*';

    // add our event listeners to handle selection and canceling
    const onCancelListener = async () => {
      await sleep(50); // wait a beat, so that if onchange is firing simultaneously, it takes precedent
      resolve([]);
      removeInputFromDom();
    };
    fileInput.onchange = (event: any) => {
      window.removeEventListener('focus', onCancelListener); // remove the event listener since we dont need it anymore, to cleanup resources
      window.removeEventListener('touchend', onCancelListener); // remove the event listener since we dont need it anymore, to cleanup resources
      resolve([...(event.target!.files as FileList)]); // and resolve the files that the user picked
      removeInputFromDom();
    };
    window.addEventListener('focus', onCancelListener, { once: true }); // detect when the window is refocused without file being selected first, which is a sign that user canceled (e.g., user left window into the file system's file picker)
    window.addEventListener('touchend', onCancelListener, { once: true }); // detect when the window is touched without a file being selected, which is a sign that user canceled (e.g., user did not leave window - but instead canceled the modal that lets you choose where to get photo from on ios)

    // and trigger the file selection ui
    addInputToDom();
    fileInput.click();
  });