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

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

思路说明

  1. 通过<input type="file"/>进行点击后,通过监听这个DOM元素的change事件,在用户点击之后就能拿到用户电脑上的文件了。
  2. 通过原生js来动态创建type="file"的input元素,之后给监听该元素的change事件,同时手动用代码触发该元素的点击事件。后面在该元素的change事件中,就能拿到用户电脑上的文件。
  3. 但后面发现,用户打开弹窗但不选用户电脑上的文件,并不会触发input元素的change事件,同时也不会触发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 文件上传取消事件;
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值