❓如何不使用input实现上传图片并预览

2,067 阅读2分钟

input方式上传图片

<input type="file" />

input 标签主要有以下几个属性

  • accept 设置上传文件的类型,默认为空,表示可以上传所有类型文件。常见的 MIME types
  • capture 摄像头,user 前置摄像头 environment 后置摄像头
  • multiple 是否可以选多个文件 默认false
  • webkitdirectory 是否可以选择文件夹

原生 JS 方式选择文件

showOpenFilePicker 选择文件。查看 MDN 的文档

showDirectoryPicker 选择文件夹。查看 MDN 的文档

👇 代码都是以 Vue3 为例

<button type="text" @click="uploadFile">原生JS选择文件</button>
const uploadFile = async () => {
    try {
        const fileHandleList = await window.showOpenFilePicker(options);
    } catch (error) {
        window.$message.error('该浏览器不支持showOpenFilePicker方法,请切换浏览器')
    }
};

options(可选参数)

  • multiple Boolean类型,是否可多选
  • excludeAcceptAllOption Boolean类型,是否排除允许全部类型选项,如下图
  • types Array类型,可选的文件类型数组。每个元素十个对象包含description和accept
    • description 文件类型的描述
    • accept 允许的文件类型对象,key为文件的MIME types,value为文件后缀名数组
const options = {
    types: [{
        description: '只允许上传图片文件',
        accept: {
            // "text/plain": [".txt"],
            // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
            // 'application/vnd.ms-excel': ['.xls'],
            'image/*': ['.png', '.gif', '.jpeg', '.jpg', '.webp']
        }
    }],
    multiple: true, // 是否允许上传多个文件,
    excludeAcceptAllOption: true // 是否排除允许全部类型选项
};

image.png

返回值

返回值是 FileSystemFileHandle 对象数组

属性

  • kind 文件或文件夹file directory
  • name 文件名

方法

  • queryPermission() 查询当前句柄的当前权限状态。
  • requestPermission() 请求文件句柄的读或读写权限。
  • getFile() 返回一个Promise,解析为一个File对象,表示句柄所代表的条目在磁盘上的状态。
  • createWritable() 返回一个Promise,解析为一个新创建的FileSystemWritableFileStream对象,该对象可用于写入文件。

选择并预览图片

<div class="img-wrap">
    <img v-for="(img, index) in imgSrcList" :key="index" :src="img" alt="">
</div>
const imgSrcList = [];
fileHandleList.forEach(async (fileHandle: any) => {
    const file = await fileHandle.getFile();
    const buffer = await file.arrayBuffer();
    const url = URL.createObjectURL(new Blob([buffer]));
    imgSrcList.push(url);
});

兼容性

image.png

这是个新的 API 兼容性不好,Safari 浏览器不支持。可以混合 input 标签使用。

文件下载

showSaveFilePicker 这个 API 可以下载文件,但还是推荐使用FileSaver.js

<button type="text" @click="saveFile">原生JS保存TXT文件</button>
const options = { 
    types: [{
        description: '只允许保存txt格式文件',
        accept: {
            "text/plain": [".txt"],
        }
    }]
}
const saveFile = async () => {
    const FileSystemFileHandle = await window.showSaveFilePicker(options);
    const w = await FileSystemFileHandle.createWritable();
    await w.write('new data');
    await w.close();
};

DEMO
GIT

参考文章 File System Access API