基于vue和FormData实现的无刷新头像上传(非插件),前端+后端处理简单处理方案。

15 篇文章 0 订阅
6 篇文章 0 订阅

场景描述:上传用户头像,一直是图片上传应用的经典场景,以前总是用其他库类中封装好的插件实现,没有深入的了解它的前端和后端实现原理。如果让自己不依靠框架和插件,八成都不知道该如何下手,昨天晚上想起来这个问题,觉得还是好好研究一下!

在这里插入图片描述
为什么这里要特意提到无刷新呢?因为基于html的form表单提交的方式,默认是会导致页面重定向的。造成的影响就是页面看起来像是刷新过一样。
在这里插入图片描述
解决的办法有很多,有使用隐藏的iframe来提交,具体的原理是form表单提交到iframe里面处理,而这个iframe是隐藏的,所以提交表单的时候当前页面没有发生任何变化。最重要的就是form的target属性指向iframe的name值,这样就实现了提交到隐藏的iframe中。
在这里插入图片描述
这样就能实现无刷新。
在这里插入图片描述

但是iframes有着阻塞页面加载,影响网页加载速度等一系列问题。而现在有h5的FormData对象,可以更简单的实现无刷新上传功能。所以iframe这种方法一般作为无法使用h5的FormData时的一种替换方案。

使用FormData实现无刷新图片上传。

之前使用过element-ui中的upload功能,非常简单好用。但是如果要定制属于自己的用户头像上传组件怎么办?
其实只要涉及到文件上传,它的底层一定是使用input表单实现!因为只有<input type=“file”> 才具有这种选择文件的功能。
明白了这一点,我们就可以来着手设计。因为原生的<input type=“file”>非常丑,所以一般都将它隐藏起来(设置宽高为0,display:none就可以),然后使用其他的标签来模拟触发点击事件。
在这里插入图片描述
在input上绑定一个change事件。
在这里插入图片描述
当选择的文件发生变化时,向服务器发送请求,上传头像。
需要注意的是,图片和文件类的文件传输时,需要设置请求消息头headers中的Content-Type为multipart/form-data,可以用于传送二进制类型数据;该属性默认是application/x-www-urlencoded,一般用于传输字符类型数据或者文本类型数据。
之前做过的电子签名功能,由于使用canvas绘图完成后,直接转换成了base64字符串格式,所以可以直接使用application/x-www-urlencoded的请求头。但是这里使用input type=file选择的图片,是以二进制数据保存的。所以必须设置Content-Type为multipart/form-data。
在这里插入图片描述
同样的,在使用form表单时设置enctype也是为了达到同样的效果。如果是上传图片,那么必须设置enctype=multipart/form-data
在这里插入图片描述
formData.append(‘file’,event.target.files[0]),这里讲一下。虽然使用formdata对象不需要使用form标签,但是它的原理其实是以虚拟form标签的形式实现,所以需要在formdata中通过append方法,添加内容到虚拟form标签中,这样虚拟form中才有虚拟input type=file ,而file的内容是event.target.files[0]二进制数据流。
设置好了formdata之后,就可以通过axios将数据通过请求发送到服务器。发送之前需要按照前面讲的,设置好请求头。前端axios设置请求头的方法,可以参阅一下axios官方文档,我也是看了文档才知道如何设置的。

到这里,前端的代码设置基本结束了。大家可以看到这里我为图片url后面加了一个随机的时间戳,因为我这里服务器返回的图片路径其实是固定的,每次服务器接受到了数据,就将该路径对应的图片进行重写操作。虽然图片的内容发生了变化,但是系统认为路径没有变,所以展示出来的是系统缓存中的图片,无论你如何改变都是缓存中的样子。只有刷新或者重启,这样太麻烦。
所以虽然图片路径是一样的,但是我给图片路径后面加上一串随机的数字,这样系统就会认为每一次获取的图片路径不一样,就不会从缓存中获取图片,而是使用服务器端返回的图片,这样才能成功显示!

nodejs后端处理formdata格式的图片数据。

nodejs后端要接受formdata格式的图片数据,并存储下来,需要使用connect-multiparty中间件。
使用以下命令来安装,并添加到package.json中。

npm i connect-multiparty -s

在app.js中引入,然后可以通过中间件设置文件存放的地址。如果不设置,会默认存到c盘的临时文件区域。这里最好是设置一下,因为如果项目在线上环境运营,而一些第三方服务器用的系统可能和你用的不一样,到之后处理起来就麻烦了。

const multiparty = require('connect-multiparty');

app.use(multiparty({
  uploadDir: './public/miniCloud/image'
})); //设置上传文件存放的地址

如果是在路由文件中写的接口,那么在对应路由文件中引入:

var multiparty = require('connect-multiparty');
var multipartyMiddleware = multiparty();

router.post('/uploadAvatar', multipartyMiddleware, (req, res) => {
	console.log(req.body)//返回请求主体
	console.log(req.files)//文件属性,包含文件的所有信息。
	console.log(req.files.file.path)//文件路径。
})

这里我将文件通过fs模块,写入到了一个指定的路径中。所以每次返回的其实是相同的路径,所以前端代码中才需要添加时间戳来解决图片缓存问题。
在这里插入图片描述

至此,前后端图片上传全部处理完毕,一些样式也可以自己修改。
看下效果。
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值