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; } }, },
复制
注意:图片或者视频预览的时候,需要一个文件的临时地址