uniapp实现图片和视频上传

此代码段展示了在uni-app中如何处理文件上传,包括图片和视频的预览、删除以及限制最大上传数量。使用了腾讯云COSSDK进行文件上传,并提供了选择文件类型的弹窗。当用户点击文件时,可以预览图片或播放视频。此外,还支持从相册或相机选择图片和视频。
摘要由CSDN通过智能技术生成

模板部分

<template>
	<view class="annex-wrap ">
		<view class="annex-box">
			<view class="file-list flex-wrap">
				<view class="file-list-item" v-for="(item, index) in dataList" :key="index">
					<view class="file-list-item-inner">
						<!--图片-->
						<view class="" @tap.stop="toPreview(item)" style="position: relative;height: 100%;width: 100%;">
							<image :src="item.type === 'image' ? item.url : `${item.url}?x-oss-process=video/snapshot,t_0,f_jpg`" class="upload-temp-img" mode="aspectFill"
								 />
							<!--视频-->
							<!-- <view v-if="item.type === 'video'" class="file-area">
								<view @tap.stop="toPreview(item)">
									<view class="name">{{ item.fileName }}</view>
								</view>
							</view> -->
							<u-icon name="play-circle-fill" color="#00000080" size="40" v-if="item.type === 'video'" style="position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);"></u-icon>
						</view>
						
						<view @tap.stop="removeFile(index)" class="close-btn">
							<u-icon name="close" size="20"></u-icon>
						</view>
					</view>
				</view>
				<view class="file-list-item" @tap.stop="toShowChooseSheet" v-if="dataList.length<maxFilesNum">
					<view class="file-list-item-inner upload-btn flex-center">
						<view class="flex-center" style="flex-direction: column;">
							<u-icon name="plus" color="#929AA5" size="36"></u-icon>
							<view>{{ dataList.length }}/{{ maxFilesNum }}</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<u-action-sheet :actions="uploadTypeList" :show="showUploadTypeSheet" title="请选择上传文件类型"
			@close='showUploadTypeSheet=false' :round="20" closeOnClickOverlay cancelText='取消'
			@select="chooseUploadType"></u-action-sheet>
		<u-popup :show="showPreview" mode="center" width="95%" @close="closePreview" v-if="play" class="pop" closeOnClickOverlay>
			<view class="preview-content flex-center">
				<image :src="previewItem.url" mode="widthFix" v-if="previewItem.type === 'image'" style="width: 80%;"></image>
				<video :src="previewItem.url" id="preview-video" :autoplay="false" controls :show-progress="true" style=" height: 400px;width: 100vw;"
					:show-center-play-btn="true" v-if="previewItem.type === 'video'"></video>
			</view>
		</u-popup>
	</view>
</template>

js部分

<script>
	import COS from 'cos-wx-sdk-v5'
	import {
		coskey
	} from '@/api/common'
	import {
		qcloudTempSecreKey
	} from '@/api/newApi/mine'
	export default {
		props: {
			maxFilesNum: {
				type: Number,
				default: 1
			},
			play: {
				type: Boolean,
				default: false
			},
			videoCount:{
				type: Number,
				default: 1,
			}
		},
		data() {
			return {
				showPreview: false,
				previewItem: {
					url: "",
					type: "",
				},
				uploadTypeList: [{
						name: "图片",
						id: 1,
					},
					{
						name: "视频",
						id: 2,
					},
				],
				dataList: [],
				showUploadTypeSheet: false,
			};
		},
		created() {
			this.getCosFun()
		},
		methods: {
			//获取腾讯云配置
			getCosFun() {
				const fun = () => this.isMall ? qcloudTempSecreKey() : coskey({
					custom: {
						auth: true
					}
				})
				fun().then(res => {
					this.$u.vuex('vuex_coskey', res)
					const {
						credentials,
						expiredTime
					} = res
					this.$u.vuex('vuex_cosapi', new COS({
						ForcePathStyle: true,
						getAuthorization: (options, callback) => {
							callback({
								TmpSecretId: credentials.tmpSecretId,
								TmpSecretKey: credentials.tmpSecretKey,
								XCosSecurityToken: credentials.sessionToken,
								ExpiredTime: expiredTime
							});
						}
					}))
				})
			},
			// 获取附件列表-查看或编辑时候用
			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) {
				this.showPreview = true;
				this.previewItem = {
					url: item.url,
					type: item.type,
				};
			},
			// 关闭预览
			closePreview() {
				console.log(1111)
				this.showPreview = false
				this.previewItem = {
					url: "",
					fileType: "",
				};
			},
			// 移除文件
			removeFile(index) {
				let that = this;
				uni.showModal({
					title: "提示",
					content: "确定删除此项吗?",
					success: function(res) {
						if (res.confirm) {
							that.dataList.splice(index, 1);
							that.$emit('success', that.dataList)
						}
					},
				});
			},
			// 上传图片
			chooseImage() {
				let that = this;
				uni.chooseImage({
					count: this.maxFilesNum - this.dataList.length, //默认100
					sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
					sourceType: ["album", "camera"],
					success: ({
						tempFiles
					}) => {
						//   图片批量上传
						tempFiles.map(({
							path,
							name,
							type,
							size
						}) => {
							this.uploadFilePromise({
								url: path,
								name,
								type: 'image',
								size
							}).then(result => {
								this.dataList.push(result)
								this.$emit('success', this.dataList)
							})
						})
					},
				});
			},
			// 上传视频
			chooseVideo() {
				let that = this;
				uni.chooseVideo({
					sourceType: ["album", "camera"],
					success: ({
						tempFile,
						duration,
						tempFilePath,
						size,
						name
					}) => {
						console.log({
						tempFile,
						duration,
						tempFilePath,
						size,
						name
					})
						this.uploadFilePromise({
							url: tempFilePath,
							name,
							type: 'video',
							size
						}).then(result => {
							console.log('result', result)
							this.dataList.push(result)
							this.$emit('success', this.dataList)
						})
					},
				});
			},
			// 选择上传文件类型
			chooseUploadType({
				id
			}) {
				if (id === 1) {
					// 图片
					this.chooseImage();
				} else if (id === 2) {
					// 视频
					
					if(this.dataList.filter(ele=>ele.type == 'video').length < this.videoCount) this.chooseVideo()
					else uni.showToast({ title: `最多只能上传${this.videoCount}个视频`, icon: "none", });
				}
			},
			//  打开文件上传选择类型弹窗
			toShowChooseSheet() {
				if (this.dataList.length >= this.maxFilesNum) {
					uni.showToast({
						title: `最多只能上传${this.maxFilesNum}个文件`,
						icon: "none",
					});
					return false;
				} else {
					console.log(33333, '++++++++++', this.dataList.length, this.maxFilesNum)
					this.showUploadTypeSheet = true;
				}
			},
			uploadFilePromise({
				url,
				name,
				type
			}) {
				return new Promise((resolve, reject) => {
					if (url) {
						var oldStr = url.match('[^/]+(?!.*/)')[0]
						var newStr = this.vuex_coskey.tempUploadPath + oldStr
						// #ifdef H5
						newStr += name.slice(-4)
						// #endif
						this.vuex_cosapi.postObject({
							Bucket: this.vuex_coskey.bucket,
							Region: this.vuex_coskey.region,
							Key: newStr,
							FilePath: url
						}, (err, data) => {
							console.log('+++++++++++++++++++++++++++++++++++', newStr,data)
							if (data) resolve({
								url: `https://${data.Location}`,
								temp: newStr,
								type
							})
							else uni.showToast({
								icon: 'none',
								position: 'center',
								title: '上传失败,请重新上传'
							})
						})
					}
				})
			},
		},
	}
</script>
<style lang="scss" scoped>
	.annex-wrap {
		width: 100%;

		.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: 172rpx;
			padding: 20rpx;
			height: 172rpx;
			margin-right: 10rpx;
			position: relative;
			display: inline-block;
			margin-bottom: 30rpx;
			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: 2rpx solid #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;
			}
		}
		.file-list-item:nth-child(3n){
			margin-right: 0;
		}
		.file-list-item:last-child:nth-child(3n-1){
			margin-right: 240rpx;
		}
	}

	.preview-content {
		width: 100vw;
		// height: 90vh;
		text-align: center;
		display: flex;
		align-items: center;

		video {
			width: 100%;
			height: 100%;
		}
	}

	/deep/ .pop {
		.u-popup__content {
			background-color: unset;
		}
	}
	
	.file-list{
		justify-content: space-between;
	}
</style>

使用

<template>
	<view class="containerbox">
		<my-upload :maxFilesNum='6' width="65.2" height="65.2" @success='uploadSuccess' :videoCount="3"></my-upload>
	</view>
</template>

<script>
	import myUpload from '@/pages/newPages/mall/music/components/my-upload.vue'
	import form from './form'
	export default {
		components: { myUpload },
		methods: {
            uploadSuccess(e){
				console.log(e)
			}
        }
    }
</script>

效果展示

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值