H5实现图片上传
关于H5实现图片上传的需求中,下面记录的是使用该插件如何实现图片上传,过程中遇到的问题以及如何解决的。记录的目的一方面提醒自己不要再犯此类错误,一方面督促自己写博客。遇到问题记录下来,每天进步一点点!
首先我遇到的需求是一个提交表单,表单中包含图片上传的功能。使用的是vant ui 的upload插件,需求是可以多选图片,最多可上传三张,但是upload组件的多选属性multiple部分安卓手机不支持,也就改成单选了。
图片先上传upload组件的使用如下:
<van-uploader v-model="imageList" :beforeDelete="beforeDelete" @oversize="oversize" :afterRead="afterRead" :max-count="3" :max-size="1024 * 1024 * 5" :preview-size="preViewSize">
<van-button icon="plus" :style="uploadStyle"></van-button>
</van-uploader>
```javascript
export default {
data () {
return {
imageList: [], // 图片预览列表
uploadStyle: {
width: '100px',
height: '100px'
},
preViewSize: 100, // 图片预览尺寸
}
},
mounted () {
// 上传文件样式设置, 需求是最多可上传三张图片,针对不同机型对图片展示的宽度尺寸做适配
let deviceWidth = window.innerWidth
if (deviceWidth > 414) {
deviceWidth = 414
}
let uploadWidth = deviceWidth - 16 * 2 - 10 * 2
let width = uploadWidth / 3 - 8
this.preViewSize = width
this.uploadStyle = {
width: `${width}px`,
height: `${width}px`
}
},
methods: {
// 图片超出大小
oversize (file, detail) {
Notify({ type: 'warning', message: '图片不能超过5M~' })
},
// 删除图片
beforeDelete (file, detail) {
this.imageList.splice(detail.index, 1)
},
// 图片上传后,获取返回的参数,在提交时当做参数传递给后台,uploadImgList是图片上传后返回的图 片信息列表
afterRead (file, detail) {
// 上传图
file.status = 'uploading'
file.message = '上传中'
// 调用上传方法
this.upload(file.file).then(res => {
// 根据index来判断是哪个图片,这种导致后面删除前一张,index变化了,出现问题
file.url = res.data.downloadUrl
file.status = 'done'
file.message = ''
}).catch(rej => {
let item = {
status: 'failed'
}
file.status = 'failed'
file.message = '上传失败'
})
},
// 上传图片接口
upload (file) {
return new Promise((resolve, reject) => {
let formdata = new FormData()
formdata.append('filecontent', file)
$.ajax({
url: this.uploadUrl,
data: formdata,
type: 'post',
headers: {
// 添加一个mock 人,手机端之前没有加,导致失败了,根据自己的项目来判断是否要加
},
processData: false,
contentType: false,
success (res) {
res.data.name = file.name
resolve(res)
},
error (res) {
reject(res)
}
})
})
},
}
}
上面代码是根据index来删除和上传添加的,其实这样是不准确的,index不能作为唯一性标识。如果操作顺序为:第一张上传成功,第二张正在上传,删除第一张,此时index就变了,而afterRead方法中detail.index,为删除前的index,这样就导致不准确了。
解决办法:上传前添加唯一标识符,代码如下
// 添加唯一标识的方法
function onlymd() {
function s4 () {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1)
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4()
}
// afterRead方法和beforeDelete更改如下
// 删除图片
beforeDelete (file, detail) {
// 根据唯一标识来删除图片
this.imageList.forEach(item => {
if (item.md === file.md) {
this.imageList.splice(detail.index, 1)
}
})
},
// 图片上传后,获取返回的参数,在提交时当做参数传递给后台,uploadImgList是图片上传后返回的图 片信息列表
afterRead (file, detail) {
// 添加唯一标识
file.md = this.onlymd()
// 上传图
file.status = 'uploading'
file.message = '上传中'
// 调用上传方法
this.upload(file.file).then(res => {
// 根据唯一标识来判断是哪张图片的返回结果
this.imageList.forEach(item => {
if (item.md === file.md) {
//找到图片进行数据处理
}
})
file.status = 'done'
file.message = ''
}).catch(rej => {
let item = {
status: 'failed'
}
// 由于删除的时候uploadImgList和imageList 的index要相对应,所以即使失败了,也要添加一项进去,这部之前没做处理导致删除项对应不上
file.status = 'failed'
file.message = '上传失败'
this.uploadImgList.push(item)
})
},
最后是提交的时候,之前出现问题图片没有上传完成,就点了提交按钮,这就导致了,提交时图片的参数没有携带上去,出现错误。
解决办法
图片上传时不允许提交,提交按钮置于不可操作的状态
在提交时对就是对uploadImageList参数做处理,用的是数组的filter方法,把status为failed的过滤出去,这里就不贴代码了。
总结,注意的点:
1.一定要确保图片上传完成后,再提交。如果有失败的给与提示,删除或者重新上传
2.index不能作为唯一标识,没有唯一标识的要手动加上,确保删除的时候是删除的那一项,图片上传成功后也要找到上传前的唯一标识去进行数据处理
最后,遇到问题不要慌,找到问题的所在点,然后去解决,实战中学习,加油!