20240123----重返学习-原生js纯函数获取用户电脑上的文件

20240123----重返学习-原生js纯函数获取用户电脑上的文件

思路说明

  1. 通过外加点击后,通过监听这个DOM元素的change事件,在用户点击之后就能拿到用户电脑上的文件了。
  2. 通过原生js来动态创建type="file"的input元素,之后给监听该元素的change事件,同时手动用代码触发该元素的点击事件。后面在该元素的change事件中,就能拿到用户电脑上的文件。
  3. 但后面发现,用户打开弹窗但不先,并不会触发input元素的change事件,同时也不会触发type="file"的input元素的input事件。在MDN文档中,也没发现还有其它事件可以用。于是,在网上找到一个思路,就是用户选择文件或取消选择文件后,window会触发focus事件,可以在这里处理取消事件。
  4. 为让事件更纯粹,不造成负作用,要移除创建的input元素。同时,也要移除绑定到window上的focus事件。
  5. 为了稳定,返回的Promise的值一定会resolve掉,即如果用户不选或者选择文件出错,直接返回null。否则返回file类型的文件。

代码说明

  • 纯js版
// 调用后,会让用户选择一个文件;中间如果用户取消了,返回null;否则返回该文件;
const handleChooseFile = async function handleChooseFile() {
   
  // [input file 文件框“取消”按钮事件]( https://www.jianshu.com/p/b41a21a399e4 )
  // [如何检测 html 的 input file 控件在文件输入时,用户点击了“取消]( https://blog.csdn.net/yxp_xa/article/details/103696863 );
  // [监听 input type=file 文件上传取消事件]( https://blog.csdn.net/joe0235/article/details/130055087 );
  const thePromise = new Promise((resolve, reject) => {
   
    // 创建 input 元素
    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.style.display = 'none'; // 隐藏 input 元素

    document.body.appendChild(fileInput);

    // 用户取消选择或直接关闭,不会触发change事件;
    // 可以通过采取为当前window添加focus事件的方式来模拟取消事件,只要控制这个focus事件在change事件之后执行,就可以通过设置一个变量和setTimeout方法实现;
    const handleWindowFocus = () => {
   
      const handleFileCancel = () => {
   
        console.log('用户取消选择文件或选择文件出错');
        resolve(null);
        window.removeEventListener('focus', handleWindowFocus, false);
        if (document.body.contains(fileInput)) {
   
          document.body.removeChild(fileInput);
        }
      };
      setTimeout(handleFileCancel, 10000); //浏览器页面获取焦点事件早于onchange事件约20毫秒,需要页面绑定的事件滞后执行,使用 setTimeout 即可。
    };
    window.addEventListener('focus', handleWindowFocus, false); //文件选择对话框关闭(无论是确定还是取消),页面将重新获取焦点。

    const handleFileSelect = function handleFileSelect() {
   
      console.log(`handleFileSelect-->`);

      // 获取选择的文件
      const selectedFile = fileInput.files ? fileInput.files[0] : null;

      if (selectedFile) {
   
        // 打印文件信息,你可以在这里处理你的文件
        console.log('选择的文件:', selectedFile);
        resolve(selectedFile);

        if (document.body.contains(fileInput)) {
   
          document.body.removeChild(fileInput);
        }
        return;
      }

      // 用户取消选择文件或选择文件出错的情况
      console.log('用户取消选择文件或选择文件出错');
      resolve(null);

      if (document.body.contains(fileInput)) {
   
        document.body.removeChild(fileInput);
      }
    };
    // 监听 input 元素的 change 事件
    fileInput.addEventListener('change', handleFileSelect, false);

    // const handleFileInput = function handleFileInput() {
   
    //   console.log(`handleFileInput-->`);
    //   resolve(null);

    //   if (document.body.contains(fileInput)) {
   
    //     document.body.removeChild(fileInput);
    //   }
    // };
    // // 监听 input 元素的 input 事件
    // fileInput.addEventListener('input', handleFileInput, false);

    // 模拟触发 input 元素的点击事件
    fileInput.click();
  });
  return thePromise;
};

handleChooseFile();//调用,会返回一个Promise;中间如果用户取消了,返回null;否则返回该文件;
  • ts加类型版
// 调用后,会让用户选择一个文件;中间如果用户取消了,返回null;否则返回该文件;
const handleChooseFile = async function handleChooseFile() {
   
  // [input file 文件框“取消”按钮事件]( https://www.jianshu.com/p/b41a21a399e4 )
  // [如何检测 html 的 input file 控件在文件输入时,用户点击了“取消]( https://blog.csdn.net/yxp_xa/article/details/103696863 );
  // [监听 input type=file 文件上传取消事件]( https://blog.csdn.net/joe0235/article/details/130055087 );
  const thePromise = new Promise<File | null>((resolve, reject) => {
   
    // 创建 input 元素
    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.style.display = 'none'; // 隐藏 input 元素

    document.body.appendChild(fileInput);

    // 用户取消选择或直接关闭,不会触发change事件;
    // 可以通过采取为当前window添加focus事件的方式来模拟取消事件,只要控制这个focus事件在change事件之后执行,就可以通过设置一个变量和setTimeout方法实现;
    const handleWindowFocus = () => {
   
      const handleFileCancel = () => {
   
        console.log('用户取消选择文件或选择文件出错');
        resolve(null);
        window.removeEventListener('focus', handleWindowFocus, false);
        if (document.body.contains(fileInput)) {
   
          document.body.removeChild(fileInput);
        }
      };
      setTimeout(handleFileCancel, 10000); //浏览器页面获取焦点事件早于onchange事件约20毫秒,需要页面绑定的事件滞后执行,使用 setTimeout 即可。
    };
    window.addEventListener('focus', handleWindowFocus, false); //文件选择对话框关闭(无论是确定还是取消),页面将重新获取焦点。

    const handleFileSelect = function handleFileSelect() {
   
      console.log(`handleFileSelect-->`);

      // 获取选择的文件
      const selectedFile = fileInput.files ? fileInput.files[0] : null;

      if (selectedFile) {
   
        // 打印文件信息,你可以在这里处理你的文件
        console.log('选择的文件:', selectedFile);
        resolve(selectedFile);

        if (document.body.contains(fileInput)) {
   
          document.body.removeChild(fileInput);
        }
        return;
      }

      // 用户取消选择文件或选择文件出错的情况
      console.log('用户取消选择文件或选择文件出错');
      resolve(null);

      if (document.body.contains(fileInput)) {
   
        document.body.removeChild(fileInput);
      }
    };
    // 监听 input 元素的 change 事件
    fileInput.addEventListener('change', handleFileSelect, false);

    // const handleFileInput = function handleFileInput() {
   
    //   console.log(`handleFileInput-->`);
    //   resolve(null);

    //   if (document.body.contains(fileInput)) {
   
    //     document.body.removeChild(fileInput);
    //   }
    // };
    // // 监听 input 元素的 input 事件
    // fileInput.addEventListener('input', handleFileInput, false);

    // 模拟触发 input 元素的点击事件
    fileInput.click();
  });
  return thePromise;
};
handleChooseFile();//调用,会返回一个Promise;中间如果用户取消了,返回null;否则返回该文件;

进阶参考

  1. input file 文件框“取消”按钮事件
  2. 如何检测 html 的 input file 控件在文件输入时,用户点击了“取消;
  3. 监听 input type=file 文件上传取消事件;

最近更新

  1. TCP协议是安全的吗?

    2024-01-24 15:20:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-24 15:20:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-24 15:20:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-24 15:20:03       20 阅读

热门阅读

  1. Dart/Flutter工具模块:the_utils

    2024-01-24 15:20:03       40 阅读
  2. 《设计模式的艺术》笔记 - 备忘录模式

    2024-01-24 15:20:03       32 阅读
  3. Oracle中TO_DATE与TO_CHAR区别

    2024-01-24 15:20:03       38 阅读
  4. Oracle 数据库恢复删除的数据

    2024-01-24 15:20:03       41 阅读
  5. 软件工程测试3

    2024-01-24 15:20:03       35 阅读
  6. 融资项目——EasyExcel将Excel文件保存至数据库

    2024-01-24 15:20:03       35 阅读