uniapp文件上传组件,支持图片、视频上传
html部分:
<template>
<view class="annex-wrap">
<view class="annex-box">
<view class="lab">上传附件</view>
<view class="file-list">
<view
class="file-list-item"
v-for="(item, index) in dataList"
:key="index"
>
<view class="file-list-item-inner">
<!--图片-->
<image
:src="item.tempFilePath"
class="upload-temp-img"
v-if="item.fileType === '1'"
mode="aspectFill"
@click="toPreview(item)"
></image>
<!--视频-->
<view v-if="item.fileType === '2'" class="file-area">
<view @click="toPreview(item)">
<u-icon
name="play-circle-fill"
color="#1890FF"
size="80"
></u-icon>
<view class="name">{{ item.fileName }}</view>
</view>
</view>
<view @click="removeFile(index)" class="close-btn">
<u-icon name="close" size="20"></u-icon>
</view>
</view>
</view>
<view class="file-list-item" @click="toShowChooseSheet()">
<view class="file-list-item-inner upload-btn">
<view>
<u-icon name="plus" color="#929AA5" size="36"></u-icon>
<view>{{ dataList.length }}/{{ maxFilesNum }}</view>
</view>
</view>
</view>
<u-empty
text="暂无数据"
mode="data"
v-if="dataList.length === 0"
></u-empty>
</view>
</view>
<u-action-sheet
:list="uploadTypeList"
v-model="showUploadTypeSheet"
:tips="uploadTypeTips"
:border-radius="20"
@click="chooseUploadType"
></u-action-sheet>
<u-popup
v-model="showPreview"
border-radius="14"
mode="center"
width="95%"
closeable
@close="closePreview"
>
<view class="preview-content">
<image
:src="previewItem.url"
mode="aspectFit"
style="width: 100%; height: 100%"
v-if="previewItem.fileType === '1'"
></image>
<video
:src="previewItem.url"
id="preview-video"
:autoplay="false"
controls
:show-progress="true"
:show-center-play-btn="true"
v-if="previewItem.fileType === '2'"
></video>
</view>
</u-popup>
</view>
</template>
css:
<style lang="scss" scoped>
.annex-wrap {
background: #f5f7fa;
.err-color {
color: #f00;
}
.border-dashed {
margin: 24rpx 0;
border: 1px dashed #eff0f2;
}
.icon-arrow {
margin-left: 12rpx;
}
.annex-box {
background: #ffffff;
border-radius: 10px;
margin-top: 24rpx;
color: #475569;
margin-top: 24rpx;
padding: 24rpx 34rpx;
position: relative;
overflow: hidden;
position: relative;
line-height: 1.6;
.lab {
font-size: 28rpx;
color: #475569;
padding: 10rpx;
}
&.select-box {
padding: 0 34rpx;
.u-form-item {
color: #475569;
padding: 16rpx 0;
}
}
.mt-10 {
margin-top: 10rpx;
}
.top {
position: relative;
.left {
margin-right: 150rpx;
}
.title {
font-size: 34rpx;
color: #303133;
font-weight: 550;
}
.desc {
color: #929aa5;
font-size: 24rpx;
}
.user-tag {
margin-left: 24rpx;
background-color: #f4f9ff;
color: #1890ff;
font-size: 22rpx;
display: inline-block;
border-radius: 6rpx;
padding: 4rpx 20rpx;
.text {
margin-left: 10rpx;
}
}
.right-icon {
position: absolute;
right: 0rpx;
top: -20rpx;
.icon {
width: 170rpx;
height: 170rpx;
}
}
.result-items {
overflow: hidden;
.result-item {
width: 33%;
float: left;
padding: 12rpx 0;
text-align: center;
position: relative;
.red {
color: #ff7676;
}
}
.result-item:after {
height: 60rpx;
width: 1px;
border-left: 1px solid #eff0f2;
content: "";
display: inline-block;
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
}
.result-item:nth-child(3n):after {
display: none;
}
.name {
color: #929aa5;
font-size: 24rpx;
}
.num {
color: #303133;
font-size: 30rpx;
}
}
}
}
.file-list-item {
width: 31%;
padding: 15.5% 0 15.5% 0;
margin-right: 3.5%;
position: relative;
display: inline-block;
overflow: hidden;
&-inner {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
.upload-temp-img {
max-width: 100%;
max-height: 100%;
border-radius: 10rpx;
}
}
.upload-btn {
border: 2px dashed #e2e8f0;
border-radius: 10rpx;
background: #fff;
text-align: center;
font-size: 26rpx;
color: #929aa5;
cursor: pointer;
}
&:nth-child(3n) {
margin-right: 0;
}
.file-area {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: rgba(77, 151, 255, 0.05);
text-align: center;
width: 100%;
border-radius: 10rpx;
.name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 160rpx;
}
.icon-file {
width: 60rpx;
height: 74rpx;
}
video {
width: 100%;
height: 100%;
}
}
.close-btn {
position: absolute;
right: 0;
top: 0;
background: rgba(71, 85, 105, 0.3);
border-radius: 0px 10rpx 0px 10rpx;
display: inline-block;
width: 40rpx;
height: 40rpx;
cursor: pointer;
text-align: center;
color: #fff;
z-index: 9;
}
}
}
.preview-content {
width: 100%;
height: 90vh;
padding-top: 80rpx;
padding-bottom: 20rpx;
text-align: center;
display: flex;
align-items: center;
video {
width: 100%;
height: 100%;
}
}
</style>
js:
data() {
return {
showPreview: false,
previewItem: {
url: "",
fileType: "",
},
dataList: [],
uploadTypeList: [
{
text: "图片",
},
{
text: "视频",
},
],
uploadTypeTips: {
text: "请选择上传文件类型",
color: "#909399",
fontSize: 32,
},
showUploadTypeSheet: false,
maxFilesNum: 20, //最大上传数
};
},
methods: {
// 获取附件列表-查看或编辑时候用
getFileList() {
let data = {
id: id,
};
getFileList(data).then((res) => {
if (res.code === 200) {
this.dataList = res.result;
this.dataList.forEach((item) => {
item,
(item.tempFilePath = `域名/file/downloadFile?filePath=${item.filePath}`);
//tempFilePath:文件的临时地址,或者拼一个获取文件临时地址的接口,临时文件地址才可以预览
});
}
});
},
// 打开预览
toPreview(item) {
if (item.fileType === "1") {
this.showPreview = true;
// 添加延时加载 避免popup不显示
setTimeout(() => {
this.previewItem = {
url: item.tempFilePath,
fileType: item.fileType,
};
}, 500);
} else if (item.fileType === "2") {
this.showPreview = true;
this.downloadVideo(item.tempFilePath);
}
},
// 关闭预览
closePreview() {
this.previewItem = {
url: "",
fileType: "",
};
},
// 移除文件
removeFile(index) {
let that = this;
uni.showModal({
title: "提示",
content: "确定删除此项吗?",
success: function (res) {
if (res.confirm) {
that.dataList.splice(index, 1);
}
},
});
},
// 上传图片
chooseImage() {
let that = this;
uni.chooseImage({
count: this.maxFilesNum - this.dataList.length, //默认100
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["album", "camera"],
success: (res) => {
const tempFilePaths = res.tempFilePaths;
let imgArr = [];
// 图片批量上传
for (let i = 0; i < tempFilePaths.length; i++) {
let obj = new Object();
obj.name = `files` + i;
obj.uri = tempFilePaths[i];
imgArr.push(obj);
obj = null;
}
uni.showLoading();
uni.uploadFile({
//url:上传文件接口,返回文件名、文件类型、文件大小、文件地址等
url: `域名/file/uploadFile`,
files: imgArr,
success: (uploadRes) => {
let data = JSON.parse(uploadRes.data);
if (data.code === 200) {
(data.result || []).forEach((item, index) => {
that.dataList.push({
fileType: "1",//1图片,2视频
fileName: item.fileName,
filePath: item.filePath,
fileSize: item.fileSize,
fileSuffix: item.fileSuffix,
tempFilePath: tempFilePaths[index],
});
});
} else {
uni.showToast({
icon: "none",
title: "上传失败",
});
}
},
complete: () => {
uni.hideLoading();
},
});
},
});
},
// 上传视频
chooseVideo() {
let that = this;
uni.chooseVideo({
sourceType: ["album", "camera"],
success: (res) => {
const tempFilePath = res.tempFilePath;
uni.showLoading();
uni.uploadFile({
//url:上传文件接口,返回文件名、文件类型、文件大小、文件地址等
url: `域名/file/uploadFile`,
filePath: tempFilePath,
name: "file",
success: (uploadRes) => {
let data = JSON.parse(uploadRes.data);
if (data.code === 200) {
that.dataList.push({
fileType: "2",
fileName: data.result.fileName,
filePath: data.result.filePath,
fileSize: data.result.fileSize,
fileSuffix: data.result.fileSuffix,
tempFilePath: `域名/file/downloadFile?filePath=${data.result.filePath}`,
//tempFilePath:文件的临时地址,或者拼一个获取文件临时地址的接口
});
} else {
uni.showToast({
icon: "none",
title: "上传失败",
});
}
},
complete: () => {
uni.hideLoading();
},
});
},
});
},
//查看-下载视频
downloadVideo(url) {
let that = this;
uni.showLoading({
title: "加载中",
});
uni.downloadFile({
url: url, //仅为示例,并非真实的资源
success: (res) => {
if (res.statusCode === 200) {
this.previewItem = {
url: res.tempFilePath,
fileType: "2",//1图片,2视频
};
// 自动播放
setTimeout(() => {
let videoContxt = uni.createVideoContext("preview-video", that);
videoContxt.play();
}, 500);
}
uni.hideLoading();
},
error: (e) => {
uni.hideLoading();
},
});
},
// 选择上传文件类型
chooseUploadType(index) {
if (index === 0) {
// 图片
this.chooseImage();
} else if (index === 1) {
// 视频
this.chooseVideo();
}
},
// 打开文件上传选择类型弹窗
toShowChooseSheet() {
if (this.dataList.length >= this.maxFilesNum) {
uni.showToast({
title: "最多只能上传20个附件",
icon: "none",
});
return false;
} else {
this.showUploadTypeSheet = true;
}
},
},
注意:图片或者视频预览的时候,需要一个文件的临时地址