一、技术概述
- 为什么要使用这个技术?
我们团队做的产品是社团相关的服务平台,那么一个社团肯定需要一个相册来存储一些用以记录的相片以便可以用走马灯的形式展示在社团首页,学生们可以了解这个社团近期举办了哪些活动,那么如何上传这些图片是一个需要去实现的技术。
- 学习该技术的原因
完成社团图片的上传任务和展示在走马灯中。
- 技术的难点
- 图片的格式都是不一样的,需要做好约束
- 图片的大小不一,需要设定限定值
- 传给后端的格式不能是路径形式的,需要是multipartfile类型的文件,需要做转化
- 图片传递之后,如果要修改,到底是采用覆盖形式呢还是采用追加的形式呢
二、技术详述
我们可以先根据难点构架出如下流程图
然后我们可以逐步解决
选定合适的上传图片组件
在这里我选择的是element-ui中现成的组件el-upload中的照片墙形式
不同于一般的上传组件,我们只需要将list-type改为“picture-card即可”
list-type="picture-card"
隐藏默认的上传终点,上传前自定义设置
因为我们选择的图片需要经过处理和过滤,不能直接上传到服务器,因此我这里打算先关闭目标服务器,自定义上传前处理方法
:http-request="uploadFile"
在这里这个处理方法的名称就叫uploadFile
限定图片的格式
我们有如下两种方法来限定图片的格式
- 在uploadFile中进行限定
const isValidStyle = file.type === 'image/jpeg' || file.type === 'image/jpg' ||
file.type === 'image/png' || file.type === 'image/svg' || file.type === 'image/gif'
可以通过判定isValidStyle来判断是不是合适的文件类型,但是这种方法有一个缺点就是,在选择图片的时候,若选择word、txt等格式的非图片文件,也是可以拿到的
- 直接采用组件的属性
upload组件是有一个accept属性,如下只需要定义需要的图片格式,那么在选择的时候就只有定义过的格式才能成为选择目标,我推荐采用这种方式来进行图片格式的限定
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"
限制图片的大小
同样我们在uploadFile中加上如下一句话即可
const isLt2M = file.size / 1024 / 1024 < 2
这样即可将图片大小限制在2M之内
将图片收集到一个数组中
因为我们拿到的都是图片的路径,都是url类型,但是这不是我们想要的,我们需要的是能够为后端所能接收的multipartFile类型,所以在这一步我们先把图片存放到一个数组中
this.fileList.push(file.file)
转化图片格式为后端能够接收的格式
const fd = new FormData()
for (var i = 0; i < this.fileList.length; ++i) {
fd.append('image', this.fileList[i])
fd.append('index', i.toString())
}
这一步就是先构造FormData对象,然后将字符串数组中的每个元素一个一个的加进去
发起请求
uploadLocalImages(this.clubId, fd).then(response => {
// console.log(response)
this.imgsUrl = response.data
this.$message.success('上传成功')
this.getClubImgs()
})
技术使用中遇到的问题和解决过程
Q: el-upload组件的使用方式应该是要直接填写服务器接口地址,然后选择一个图片同时即可上传到相应的地方,但是我们团队采用的接口API的形式来接收图片,这就意味着我们不能单纯的照搬上传组件,而必须进行自定义的调整
A:解决的方法在上面也提到过了,就是关闭默认的上传机制,设置自定义的上传前方法,并且增加一个上传按钮用来控制上传
Q:单图上传的话比较容易,直接在选择图片的时候就转化为合适的格式,但是多图上传没办法做到选一张处理一张,需要一起集中处理
A:解决的方法很简单,我们在选择图片的时候就先存储在一个数组中,然后在上传按钮的点击事件中,处理成相对应的格式发送给后端
addEnsure: function () {
if (!this.uploadComplete) {
this.$message.error('图片正在上传,请稍等')
return
}
const fd = new FormData()
for (var i = 0; i < this.fileList.length; ++i) {
fd.append('image', this.fileList[i])
fd.append('index', i.toString())
}
uploadLocalImages(this.clubId, fd).then(response => {
this.imgsUrl = response.data
this.$message.success('上传成功')
this.getClubImgs()
})
}
总结
这次的图片上传其实难到我了,因为在element-ui组件库的官方文档中其实都是默认使用上传服务器url的方式来上传图片,但是我们团队比较特殊,讨论决定使用的方式是接口API,那么在官方文档中没有介绍该怎么使用,于是我就只能去网上查找博客,但很多博客都大不相同,使用的方法也都不一样,有些方法在我这是跑不了的,因此折腾了很久,后面和队友交流了一下,一步一步的锁定了流程,针对一篇博客看懂其中的原理,自己尝试几次就出来,还是算一个比较难的点,卡了挺久的,好在自己比较积极,而且队友也乐意帮助我,才能好好的完成这个技术。
参考文献、参考博客
vue中el-upload上传多图片且携带参数,批量而不是一张一张的解决方案
关于使用el-upload组件上传多张图片的问题