这篇文章主要介绍了javascript文件用什么打开,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。
在编写项目时,难免会遇到想要用户上传文件的场景。文件流处理之前的第一关是打开文件对话框让用户选取文件,本文主要讲解如何打开这个文件对话框,同时带来了一种对于文件系统操作的新概念 APIDeepl降重。
要明确一点的是文件对话框是浏览器的功能,开发者不能自定义文件对话框,或是直接操作用户目录文件,要做的只是指引用户打开文件对话框选中目录文件。
在网上搜索教程,想要打开文件对话框基本上都是使用 方案实现,不用感到奇怪,因为想在大多数浏览器上完全通过 JavaScript 脚本来控制文件对话框,只能通过这个方法。这种传统方案历史最久,最普遍,当然兼容性也是最好的。
通过脚本生成元素 并对其操作,就能显示文件对话框,同时生成的元素支持属性不变,利用
accept
和 multiple
属性能控制文件上传类型与多选。
<>
/**
* 打开文件选取对话框
* @param fn 选取文件后回调,接收event和filelist参数
* @param accept 文件类型
* @param multiple 是否多选
*/
function openFilePicker({fn, accept, multiple} = {}) {
const inpEle = document.createElement("input");
inpEle.id = `__file_${Math.trunc(Math.random() * 100000)}`;
inpEle.type = "file";
inpEle.style.display = "none";
// 文件类型限制
accept && (inpEle.accept = accept);
// 多选限制
multiple && (inpEle.multiple = multiple);
inpEle.addEventListener("change", event => fn.call(inpEle, event, inpEle.files), {once: true});
inpEle.click();
}
const btn = document.getElementById("open-file");
btn.addEventListener("click", () => {
openFilePicker({
fn: (e, files) => {
console.group("获取到的文件");
console.log("files", files);
console.groupEnd();
}
});
});
>
Promise
在用户取消选择文件抛出 reject
变的难以检测,如何监听取消行为在 stackoverflow 上貌似也没有什么好的解决办法,不过也不用慌张,大多数情况下只需处理文件获取后的行为。文件系统访问API是一个很新的概念,允许web应用程序直接读取或保存用户设备上的文件和文件夹的更改,此 API 目前纯粹是一个 JavaScript API,并且不与表单或输入元素集成,这和以往的不同。
window.showOpenFilePicker 方法能够直接调用文件对话框,一般配合aysnc/await
使用,获取到的是一个文件句柄对象数组。
参数:
里也存在一个类型属性 accept
,有意思的是只需要填入MIME类型即可,浏览器会自动识别对应的后缀文件,部分未认证或偏僻的MIME类型浏览器是识别不了,猜测是为了解决这个问题将此参数以这种形式编写。需要了解更多MIME类型,可以去查阅这篇文章『 『速查手册』MIME 多用途互联网邮件扩展 』」下述示例限制只能传图片类型文件,但事实上能支持的类型远远不止所设置的几个。注意:因为兼容性问题,运行下述代码请使用谷歌内核86+版本浏览器。
<>
const btn = document.getElementById("open-file");
btn.addEventListener("click", async () => {
// 单元素数组结构
const [fileHandle] = await window?.showOpenFilePicker({
types: [
{
deion: "图片类型",
accept: {"image/*": ['.png', '.gif', '.jpeg', '.jpg']}
}
]
});
// 获取文件File对象
const file = await fileHandle?.getFile();
console.group("获取到的文件");
console.log(fileHandle);
console.log(file);
console.groupEnd();
});
>
除了此方法外,文件系统访问 API 还存在 showSaveFilePicker、showDirectoryPicker 方法等,有兴趣可以去了解一下。
优缺点总结:
方式,简单便捷,极大程度上方便了 Web 应用的开发。
也需用户点击,对此影响并不大。注意:文件系统访问 API 它不是 W3C 标准,也不在 W3C 标准轨道上,在can i use上查询可知,在谷歌内核以及少部分的浏览器上支持此 API ,且版本要求苛刻。可以简单通俗的理解为,这可能只是谷歌的工程师为谷歌浏览器专门开发的(开发文档日志),在火狐浏览器控制台上,调用
window.showOpenFilePicker
API 时,返回的是未定义。
有句话说的好,小孩才做选择,大人两个都要,那么有没有什么办法可以实现传统方式与文件系统访问API相结合呢?答案是肯定的。
实现原理很简单,只需根据 window
对象下判断是否存在 showOpenFilePicker
方法即可。下述代码引用博主 开源项目 的源码供大家参考。因为是使用 TypeScript 编写,需要转换为 JavaScript 的同学需要使用 Node.js 安装 type
依赖。
npm i type
tsc 文件目录 --target esnext
/**
* 打开文件选择对话框
* 若浏览器不支持实验性方法:window.showOpenFilePicker,则采用input[type=file]元素进行兼容
* @param {string | string[]} accept 文件类型限制 ,默认全部
* @param {boolean} multiple 文件多选
* @param {boolean} webkitdirectory 只选择目录限制
* @param {number} compatible 兼容模式,默认开启
* @param {number} cancel 兼容取消控制,为0时候则取消文件时不抛出reject,❗在使用async/await时会造成阻塞
* @param {string} deion 文件或者文件夹的描述,可选
* @return {Promise}
*/
export async function openFileDialog(
{
accept = MIME.ALL,
compatible = true,
cancel = 300,
multiple,
webkitdirectory,
deion
}: FileDialogConfig = {}
): Promise {
accept.constructor === Array && (accept = accept.join(","));
// 实验性功能
if (!compatible && window.hasOwnProperty("showOpenFilePicker")) {
console.warn("Note that showOpenFilePicker is an experimental interface and is not supported by most browsers, so use it sparingly.");
const files = [];
const acceptMap: { [accept: string]: string[] } = {};
for (let a of (accept as string).split(",")) {
acceptMap[a] = [];
}
//@ts-ignore
const fileHandleList = await window.showOpenFilePicker?.({
multiple,
excludeAcceptAllOption: false,
types: [{
deion,
accept: acceptMap
}]
});
for (const f of fileHandleList) {
files.push(await f.getFile());
}
return files;
}
const inpEle = document.createElement("input");
inpEle.id = `__file_${Math.trunc(Math.random() * 100000)}`;
inpEle.type = "file";
inpEle.style.display = "none";
// 文件类型限制
inpEle.accept = accept as string;
// 多选限制
multiple && (inpEle.multiple = multiple);
// 选择目录限制
if (webkitdirectory) {
console.warn("该特性是非标准的,请尽量不要在生产环境中使用它!\n"
+ "This feature is non-standard, so try not to use it in a production environment!");
inpEle.webkitdirectory = webkitdirectory;
}
inpEle.click();
return await new Promise((resolve, reject) => {
let _isSelected = false;
const changeEvent = () => {
const files = inpEle.files;
if (files) {
_isSelected = true;
resolve(Array.from(files));
}
};
const focusEvent = (event: Event) => {
if (event.target?.constructor === Window) {
setTimeout(() => {
!_isSelected && reject("未选定文件\nUnselected file");
}, cancel);
}
};
inpEle.addEventListener("change", changeEvent, {once: true});
cancel && window.addEventListener("focus", focusEvent, {once: true});
});
}
因发布平台差异导致阅读体验不同,源文贴出:《JavaScript 两种方案打开文件对话框》