我这里是循环出多个上传对象,样式已经简化
<span
v-for="(item, index) in attachInfoList"
:key="index + '-wrap'"
//设置捕获事件.
//当一个父元素div1 包裹着一个子元素div2 同时有点击事件。
//我们希望点击从外面执行到里面,先触发父元素再触发子元素。
//我们可以在父元素的点击事件加上@click.capture
@click.capture="changeCurImage(index)"
>
<img
@click.stop="showChooseMethod"
:src="item.showImage"
/>
//由于安卓手机适配问题,没有自带拍照功能,所以需要自己写一个选择弹窗
//来和苹果手机保持一致
<div v-if="item.isShowChoose">
<ul>
<li @click="uploadFileMethod" class="choose-div-li">
<span> 相册 </span>
</li>
<li @click="makePhotoMethod" class="choose-div-li">
<span> 拍照 </span>
</li>
<li @click="uploadFileMethod" class="choose-div-li">
<span> 浏览 </span>
</li>
</ul>
</div>
//上传文件的input元素,注意accept="*.*",从而支持所有类型文件
<input
ref="uploadFile"
type="file"
@change="onImageChange($event)"
accept="*.*"
/>
//此input元素为了支持上面提到的安卓拍照上传功能
//注意capture="camera"和accept="image/*"
<input
ref="uploadPhoto"
capture="camera"
type="file"
accept="image/*"
@change="onImageChange($event)"
/>
<div >{{ item.fildName }} </div>
</span>
下面是各个方法
import lrz from 'lrz';
changeCurImage(index) {
//记录当前点击的input元素序号
this.curImageIndex = index;
},
onImageChange(event) {
if (event.target.files[0].type.indexOf('image') != '-1') {
//说明上传的是图片
this.attachInfoList[this.curImageIndex].file = event.target.files;
//将图片内容进行压缩
lrz(this.attachInfoList[this.curImageIndex].file[0], {
width: 1000,
})
.then((res) => {
//得到压缩后的图片base64编码
this.attachInfoList[this.curImageIndex].showImage = res.base64;
let file = [{url: res.base64,file: { name: res.origin.name,},},];
//调用后端上传文件接口
this.uploadChange(file);
})
.catch((error) => {
//失败清除数据
this.attachInfoList[this.curImageIndex].file = [];
this.attachInfoList[this.curImageIndex].successFile = {};
this.$toast('文件压缩失败' + error);
});
} else {
//说明上传的是文件,由于后端接口限制,需要将图片转化成base64编码
var files = new File(event.target.files, 'r');
this.attachInfoList[this.curImageIndex].file = event.target.files;
var reader = new FileReader();
reader.readAsDataURL(files);
reader.onload = () => {
// 文件转换为base64格式
let file = [{url: reader.result,file: {name: event.target.files[0].name,}, },];
//调用后端上传文件接口
this.uploadChange(file);
};
reader.onerror = function (error) {
this.$toast.fail('文件转换失败,请稍后再试');
};
}
},
uploadChange(file) {
this.$http.uploadBase64(file).then((res) => {
this.attachInfoList[this.curImageIndex].successFile = res;
this.$toast('文件上传成功');
})
.catch((msg) => {
this.attachInfoList[this.curImageIndex].file = [];
this.attachInfoList[this.curImageIndex].successFile = {};
this.$toast.fail('文件上传失败');
});
},
showChooseMethod() {
//如果是ios系统,则采用原生方法
if (this.isiOS) {
this.$nextTick(() => {
//ios系统显示原生弹框,所以将自己写的隐藏
this.attachInfoList[this.curImageIndex].isShowChoose = false;
//选中dom元素并且触发click事件
this.$refs.uploadFile[this.curImageIndex].click();
});
} else {
//如果是安卓系统,则显示自己写的弹框
this.attachInfoList = this.attachInfoList.map((item) => {
item.isShowChoose = false;
return item;
});
this.attachInfoList[this.curImageIndex].isShowChoose = true;
},
//点击相册和浏览时,隐藏选择弹框,触发普通上传input元素
uploadFileMethod() {
this.$nextTick(() => {
this.attachInfoList[this.curImageIndex].isShowChoose = false;
this.$refs.uploadFile[this.curImageIndex].click();
});
},
//点击拍照时,隐藏选择弹框,触发capture="camera"的input元素
makePhotoMethod() {
this.$nextTick(() => {
this.attachInfoList[this.curImageIndex].isShowChoose = false;
this.$refs.uploadPhoto[this.curImageIndex].click();
});
},
目前只是在文件中使用,还未封装成组件,但是基本功能都实现啦