惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
Last Week in AI
Last Week in AI
T
Tailwind CSS Blog
V
Visual Studio Blog
Jina AI
Jina AI
博客园 - 司徒正美
The Cloudflare Blog
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
小众软件
小众软件
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
美团技术团队
博客园 - 【当耐特】
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
WordPress大学
WordPress大学
爱范儿
爱范儿
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏

kshao-blog-前端知识记录

win or mac clash 无 TUN 让 Antigravity、Chrome 强制 proxy(解决 Antigravity 无法加载选择 model、自动更新无法登录、跳转) 【大杂烩】在 pnpm 中直接修改 node_modules(.pnpm) 中的依赖项,项目中持久化 - pnpm 中的依赖处理、幽灵依赖、寻址规则等 在 html 中直接使用 Esm、Jsx 脚本快速调试和使用 React@19 和 Vue@3 源码,解决 React19 UMD 构建等问题 一键在本地批量检测并升级更新 package.json 中的模块依赖,ncu(npm-check-updates)在 npm、pnpm 或 workspace 项目中的使用教程 解决 Mac Docker Desktop 中启动出现的问题合集 通过阿里云、腾讯云无服务器搭建自定义的企业域名邮箱,实现在 QQ邮箱 收发等功能(附腾讯 SMTP 和 IMAP) 解决使用代理(clash 等)进行 SSH 连接(如 Github ssh key clone/push)出现 kex_exchange_identification 错误 静态文件资源 cdnjs, jsdelivr 抖音字节国内快速 CDN 镜像推荐【2025】- 仍在使用 bootcdn 和 staticfile CDN 请注意验证资源的完整性(SRI) pnpm monorepo 中管理依赖的最佳实践,与 Catalogs(目录)协议的使用(monorepo 中统一版本管理) Web 安全中的 Secure Contexts(安全上下文)- 解决在本地中使用 clipboard 或 Crypto 等 API 限制或关闭上下文限制 使用 serve 配合 openssl 或 mkcert 创建本地自签名可信任的证书 - 创建本地 TLS\SSL https 协议服务 利用 Github Actions 和 Acme 自动申请、更新和部署至阿里云、腾讯云 CDN Lets Encrypt SSl\TLS ECC RSA 双证书 【CSS】解决在 flex 容器中使用 align-content 或 justify-content 属性 center 居中时的溢出滚动和截断问题 - 理解 safe 关键字 在线工具 - 一键获取下载抖音无水印视频、抖音去水印解析工具、下载抖音无水印高清图集【2025 最新】 【React Router】v6 data router 在非组件(或工具方法)中如何优雅的跳转路由 【React】为什么路由跳转时页面滚动高度不会被重置(保留上个页面高度)?理解 history scrollRestoration 的场景与使用,以及如何使用 React Router 重置和跳转前保留滚动高度 【React】在本地 Html 中快速 debug(调试)React 源码 【React】结合源码和 EventLoop 分析 - 为什么 useLayoutEffect 会阻止 DOM 重绘(而 useEffect 闪烁)?为什么其内部 useState 会“同步”执行? React Compiler - 解放在函数中编程时的性能焦虑(React Conf 2024)附 Next 在线演示 在 github actions 中获取时间,并转换为中国标准时间(中国时区) 【npm】npm ci - npm clean install,在 CI、CD 中保持构建的一致性和可重复性 eslint 9.x 升级或使用指南,eslint.config.js 配置,包含 react、typescript、prettier 等常用配置升级迁移 使用 Spicetify 自定义 Spotify - 歌词翻译、全屏展示、主题替换 在 node 中快速代理请求(Proxy),解决跨域或请求转发问题 - http-proxy-middleware 修改请求体和返回 在 Hexo 中使用 AI(Gemini、deepseek、Azure)生成文章摘要,支持自定义模板。hexo-ai-summaries 插件文档(默认适配主题 Butterfly) 解决在 webstorm 或 idea 等 jetbrains 工具中遇到 Git 无法 force push,或 force push 灰色禁用无法点击(protected branches) hexo-seo-submit,Hexo 博客 SEO 优化插件 - 每日定时自动或手动提交链接至百度、Bing、Google,支持 Github Actions 和 Coding Jenkins 等CI(Hexo 插件编写) 一文吃透 pnpm 如何使用 workspace 构建 monorepo,与 npm、yarn 的用法对比(pnpm 9.x 内部安装依赖问题 link-workspace-packages) 【Node】Corepack - 解决 pnpm 或 yarn 的多版本管理、解决本地版本与 packageManager 中的版本一致性问题 解决 npm、cnpm 或 pnpm install 遇到 certificate has expired (证书已过期)
javaScript 文件上传 - input 上传 和 webAPi 上传(解决上传...
kshao · 2022-02-15 · via kshao-blog-前端知识记录

Input type=”file”

回顾下 Input type=”file” 的使用

<input type="file" name="" id="">

type=”file” 时的属性

accept

它定义了文件 input 应该接受的文件类型。这个字符串是一个以逗号为分隔的 唯一文件类型说明符 列表。由于给定的文件类型可以用多种方式指定,因此当你需要给定格式的文件时,提供一组完整的类型指定符是非常有用的。

<input type="file" id="docpicker"
  accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document">

capture

如果 accept 属性指出了 input 是图片或者视频类型,则它指定了使用哪个摄像头去这些数据。值 user 表示应该使用前置摄像头和/或麦克风。值 environment 表示应该使用后置摄像头和/或麦克风。如果缺少此属性,则 user agent 可以自由决定做什么。如果请求的前置模式不可用,则用户代理可能退回到其首选的默认模式。

multiple

当指定布尔类型属性 multiple, 文件 input 允许用户选择多个文件。

files

对象每个已选择的文件。如果 multiple 属性没有指定,则这个列表只有一个成员。

webkitdirectory (非标准属性,只能选择文件夹)

一个布尔值,表示是否仅允许用户选择一个目录(或多个目录,如果 multiple 也出现的话)

<input type="file" webkitdirectory >

use Web Api

大部分场景下使用 input 上传文件都会去选择隐藏 input 再 diy ui 很是麻烦,学会下面的 Api 将事半功倍(兼容堪忧请注意!:can i use)。

  • window.showOpenFilePicker()
  • window.showDirectoryPicker()
  • window.showSaveFilePicker()
<button id="upload">upload/save</button>

window.showOpenFilePicker

const upload = document.getElementById("upload");

const fileOptions = {
	types: [
		{
			description: '这只是一个描述', // 在选择文件时的格式描述
			accept: {
				'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
				// "text/plain": [".txt"],
				// 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx']
			}
		},
		{
			description: '上传 dmg',
			accept: {
				'text/plain': ['.dmg'],
			},
		},
	],
	excludeAcceptAllOption: true, // 为 true 时则不展示切换格式的选项(仅测试 Mac)
	multiple: true,
};

div.addEventListener('click', async () => {
	const result = await window.showOpenFilePicker(fileOptions);
	console.log(result);
	console.log(await result[0].getFile()); // file 信息 promise
})

options

  1. excludeAcceptAllOption

excludeAcceptAllOption:boolean 默认 false,为 true 时隐藏选项按钮及格式描述

  1. multiple:同,多选

  2. types

types 数组类型,表示允许保存的文件类型列表。数组中的每一项是包含以下属性的配置对象。

  • description(可选):用于描述允许保存文件类型类别
  • accept:是一个对象,该对象的 key 是 MIME 类型,值是文件扩展名列表。

window.showDirectoryPicker()

同上

window.showSaveFilePicker()

该 Api 为 window 接口中定义的方法,调用方法后会弹出可选择保存路径的文件选择器。

const FileSystemFileHandle = Window.showSaveFilePicker(options);

调用 showSaveFilePicker 方法之后会返回一个 FileSystemFileHandle 对象,可使用该方法上的 createWritable 方法写入数据至文件中。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>showSaveFileDemo</title>
</head>
<body>
  <div>
    <button id="upload-btn">upload file</button>
  </div>

  <hr>

  <div>
    <button id="save-btn">save file</button>
  </div>
</body>

<script>
  const uploadBtn = document.getElementById('upload-btn');
  const saveBtn = document.getElementById('save-btn');

  let fileInfo = {};

  uploadBtn.addEventListener('click', async () => {
    try {
      const uploadFileOption = {
        types: [
          {
            description: '请上传 png',
            accept: {
              'text/plain': ['.png'],
            }
          }
        ],
        excludeAcceptAllOption: false,
      };

      const files = await window.showOpenFilePicker(uploadFileOption);
      const file = await files[0].getFile();
      if (file) fileInfo = file;
    } catch (e) {
      console.error(e, 'upload fail');
    }
  })

  const getFileBlob = (file) => new Promise(resolve => {
    resolve(new Blob([file]), { type: file.type });
  })

  saveBtn.addEventListener('click', async () => {
    try {
      const { name } = fileInfo;
      const fileName = name?.split('.')?.[0];
      const fileSuffix = name?.split('.')?.[1];

      const saveFileOption = {
        suggestedName: `${fileName}-${Date.now()}`, // 文件名称
        types: [
          {
            description: `保存为 ${fileSuffix}`,
            accept: {
              ['text/plain']: [`.${fileSuffix}`]
            }
          }
        ],
        excludeAcceptAllOption: false,
      };

      const handle = await window.showSaveFilePicker(saveFileOption);
      const writable = await handle.createWritable();
      await writable.write(await getFileBlob(fileInfo));
      await writable.close();
    } catch (e) {
      console.error(e, 'save fail')
    }
  });
</script>
</html>

Demo

上传和保存文件的 Demo,纯 js 可放心测试