更加优雅的web端上传文件

本文探讨如何在Web端实现更优雅的文件上传功能,类似微信小程序的开发体验。通过动态创建并自动点击隐藏的input标签,监听上传结果,提供简洁的API。文章分析了初始化阶段调用无效的问题及无取消上传回调的解决方案,分享了具体实现和最终效果,适合前端开发者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

大家一起回想一下,我们在使用Element、Antd的时候,是如何实现图片、文件上传功能。

antd就不截图了,使用方法差不多,相信写过相关代码的同学,都会感觉比较繁琐。

  • 既要改html,还需要写JavaScript,开发效率低。
  • 组件API复杂,很多时候,并不需要那么多功能,心智负担重。
  • 等等

这时候,写过微信小程序的同学,心里肯定会想,小程序的上传图片API开发体验还可以,逻辑上也很直观,通过事件触发函数,函数内实现上传图片的逻辑,我们web端能否也能拥有类似的开发体验呢?

npm地址

以下内容为实现思路以及关键代码,如果您仅仅想使用的话,请直接到npmjs

文档地址:github.com/vkcyan/choo…

npm i choose-to-file 

需求分析

首先,web端使用文件上传功能,一般使用input标签进行实现

<input type ="file" onchange/> 

最后在onchangecallback中,获取本次的结果。

我们会发现,上传文件必须通过特定的标签才能触发。这么来看似乎与函数式相违背。

但这并不是死路一条,我们可以动态创建input标签,然后通过MouseEvent创建自动点击事件;核心逻辑就是这样。

实现思路

  • 函数触发的时候,在body标签尾部插入上传文件的<input />标签,同时样式上做隐藏处理。
  • 通过MouseEvent事件,自动触发<input />的点击事件。
  • 监听上传结果,并作为结果返回,同时对临时数据进行销毁。

具体实现

实现不与具体框架做绑定,我们基于原生逻辑进行开发,天然兼容web端框架。

理想使用方式

async function uploadImg() {try {let res = await chooseToFile()console.log('file', res)} catch (err) {console.log(err)}
} 

接下来开始实现chooseToFile,首先是在body底部插入input标签

let body = document.body
let input = document.createElement('input')
input.type = 'file'
input.style.position = 'absolute'
input.style.top = '0'
input.style.opacity = '0'
input.style.zIndex = '-9999'
body.appendChild(input) 

创建完成后,立刻执行自动点击事件

 var event = new MouseEvent('click')input.dispatchEvent(event) 

然后监听inputonchange callback,并通过Promise resolve进行返回。

input.onchange = (evt) => {
  removeInput(input) // 删除dom
  let { files } = evt.target as HTMLInputElement
  return resolve(files)
} 

至此,我们的核心逻辑就完成了,还是很简单的~

一些问题

初始化阶段调用无效,并且会弹出警告。

File chooser dialog can only be shown with a user activation. 

这是因为浏览器的安全限制,不允许用户在没有任何”激活行为“的情况下,JavaScript调用窗口,针对此问题官网有详细的说明user-activation

也就是说这是不允许的,大家开发中要规避这种行为。

无取消上传callback

当用户点击文件进行上传的时候,我们可以通过onchange组件进行获取,但是如果用户关闭了上传文件弹窗,或者点击”取消“按钮,input并未提供响应的回调函数。

如果无法监听取消上传,逻辑将不知道何时销毁临时标签input,查阅了一些资料后,找到了解决方案。

无论用户是否上传,只要当前用户有操作,上传行为结束,都会重新聚焦到body本身,也就会触发全局的focus方法,如果用户上传了文件则在onchange callback中将fileCancle赋值为false;

之后focus事件触发的时候则不会进入if内逻辑。

let fileCancle = true // 是否未上传文件
window.addEventListener(
  'focus',() => {
    setTimeout(() => {
      if (fileCancle) {
        removeInput(input)
        reject('upload canceled')
    }
  }, 500)}
) 

最终效果

  • 调用函数,打开文件管理器* 用户上传文件:.then触发,收到上传的文件信息* 用户取消上传:.catch触发,收到无文件上传错误

最后

功能的实现并不复杂,因为作者工作上vue用的较多,所以可以保证Vue是没问题,理论上React也是没问题的,欢迎大家体验,在使用中有任何问题,请评论区留言。

祝你开发愉快。

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值