uniapp小程序图片上传组件,可配置上传前是否添加水印、文本展示,图片可预览

uploadImage.vue内容:

<view class="flex-tab upload-img-box">
		<view v-for="(img,cur) in data" :key="cur" class="upload-tab">
			<image :src="isObjectArr?img.imgUrl:img" @tap="lookImgFuc(data,cur)"></image>
			<image v-if="isUpload" @click="deleteImgFuc(cur)" class="delete-btn" src="https://25s1xcx2-1331094596.cos.ap-guangzhou.myqcloud.com/canteen/2025/02/19/f6a029d052784eff88cef361622ec48e.png"></image>
			<view v-if="isText" class="img-text">{{img[textKey]}}</view>
			<view v-if="isMoreText" class="img-text more-text">
				<view v-for="ele in moreTextKey"><text>{{ele.label}}</text><text :class="ele.label!==''?'font-gray':''">{{img[ele.key]||'-'}}</text></view>
			</view>
		</view>
		<view class="upload-tab upload-add" @click="takePhoto" v-if="isUpload">
			<uni-icons class="plusempty-btn" type="plusempty" size="32"></uni-icons>
		</view>
		
		<imgSyTab ref="imgSyRef" @save="saveSy"></imgSyTab>
		<receiptsNews ref="receiptsNewsRef" :data="lookImgs"></receiptsNews>
</view>
		props:{
			data:{
				type:Array,
				default:[]
			},
			//是否可以上传
			isUpload:{
				type:Boolean,
				default:true
			},
			//是否给图片添加水印
			isSy:{
				type:Boolean,
				default:false
			},
			//是否在多条数据下上传
			isMoreUpload:{
				type:Boolean,
				default:false
			},
			//当前第几条数据下
			current:{
				type:Number,
				default:0
			},
			//是否为对象数组
			isObjectArr:{
				type:Boolean,
				default:false
			},
			//是否有文本
			isText:{
				type:Boolean,
				default:false
			},
			//是否多个文本
			isMoreText:{
				type:Boolean,
				default:false
			},
			textKey:{
				type:String,
				default:'text'
			},
			moreTextKey:{
				type:Array,
				default:[]
			}
		},
		data(){
			return{
				lookImgs:[]
			}
		},
		methods:{
			//删除上传照片
			deleteImgFuc(cur){
				this.$emit('delete',this.current,cur)
			},
			takePhoto() {
				let that = this;
			    uni.chooseImage({
			        count: 1, // 默认9,设置图片的数量
					mediaType: ['image'],
			        sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
			        sourceType: ['camera'], // 可以指定来源是相机还是相册,默认二者都有
			        success: (res) => {
			          // 成功选择图片后上传图片
			          const tempFilePaths = res.tempFilePaths;
					  if(that.isSy){
						  that.$refs.imgSyRef.addWaterMarking(res.tempFilePaths[0])
					  }else{
						  that.uploadImageFunc(res.tempFilePaths[0])
					  }
			        },
			        fail: (err) => {
			          console.log('Error while choosing image:', err);
			        }
			    });
			},
			saveSy(src){
				if(this.isMoreUpload){
					this.$emit('success',src,this.current,-1)
				}else{
					this.$emit('success',src)
				}
			},
			uploadImageFunc(imagePath) {
				let that = this;
				// 转换文件为Base64
				uni.getFileSystemManager().readFile({
				  filePath: imagePath,
				  encoding: 'base64',
				  success: res => {
				    // 成功获取Base64字符串
				    let base64Data = res.data;
					yourApi({base64:base64Data,type:'2'}).then(r=>{
						if(that.isMoreUpload){
							that.$emit('success',r.url,that.current,-1)
						}else{
							that.$emit('success',r.url)
						}
					})
				  },
				  fail: err => {
				    // 转换失败的处理
				    console.error(err);
				  }
				});
			},
			//预览图片
			lookImgFuc(imgs,index){
				if(this.isObjectArr){
					this.lookImgs = imgs
				}else{
					this.lookImgs = imgs.map(ele=>{
						return {imgUrl:ele}
					});
				}
				this.$refs.receiptsNewsRef.openFuc(index);
			},
		}
.upload-img-box{
		flex-wrap: wrap;
	}
	.upload-tab{
		width: calc((100% - 64rpx)/4);
		text-align: center;
		border-radius: 16rpx;
		position: relative;
		margin-right: 16rpx;
		margin-top: 16rpx;
		&:nth-child(4n){
			margin-right: 0;
		}
		.img-text{
			font-size: 28rpx;
			line-height: 42rpx;
			color: #374151;
			&.more-text{
				text-align: left;
				.font-gray{
					margin-left: 4rpx;
					color: #8A949F;
				}
			}
		}
		image{
			width: 100%;
			height: 148rpx;
			border-radius: 16rpx;
			border: 4rpx solid #eeeeee;
		}
		.delete-btn{
			position: absolute;
			top: -16rpx;
			right: -8rpx;
			width: 42rpx;
			height: 42rpx;
			border:none;
		}
		.plusempty-btn{
			color: #000000 !important;
		}
	}
	
	.upload-add{
		background-color: #f5f5f5;
		border-color: #f5f5f5;
		height: 148rpx;
		line-height: 148rpx;
		border: 4rpx solid #eeeeee;
	}
	.more-text{
		min-height: 214rpx;
	}

水印内容imgSyTab.vue

<view class="img-sy">
		<canvas canvas-id="img-canvas" class="canvas-img-box" disable-scroll="true" :style="'width:'+imgWidth+';height:'+imgHeight"></canvas>
</view>
		data(){
			return{
				imgWidth:0,
				imgHeight:0
			}
		},
		methods:{
			timeFunc(time){
				let y = time.getFullYear(),m = time.getMonth()+1,d = time.getDate(),h = time.getHours(),miu = time.getMinutes(),sec = time.getSeconds();
				m = m>9?m:'0'+m;
				d = d>9?d:'0'+d;
				h = h>9?h:'0'+h;
				miu = miu>9?miu:'0'+miu;
				sec = sec>9?sec:'0'+sec;
				let timeA = y+'-'+m+'-'+d+' '+h+':'+miu+':'+sec;
				return timeA
			},
			uploadImageFunc(imagePath) {
				let that = this;
				// 转换文件为Base64
				uni.getFileSystemManager().readFile({
				  filePath: imagePath,
				  encoding: 'base64',
				  success: res => {
				    // 成功获取Base64字符串
				    let base64Data = res.data;
					yourApi({base64:base64Data,type:'2'}).then(r=>{
						that.$emit('save',r.url)
					})
				  },
				  fail: err => {
				    // 转换失败的处理
				    console.error(err);
				  }
				});
			},
			addWaterMarking(imageUrl) {
				console.log(imageUrl);
				let _this = this;
				//获取原图片信息
				uni.getImageInfo({
					src: imageUrl,
					success: async (res) => {
						const imgWidth = res.width; // 图片的宽
						const imgHeight = res.height; // 图片的高
						_this.imgWidth = imgWidth+'px';
						_this.imgHeight = imgHeight+'px';
						const canvas = uni.createCanvasContext('img-canvas', this)
						
						// 图片对象
						const image = res.path
						// 将图片绘制到 canvas 上
						canvas.drawImage(res.path, 0, 0, imgWidth, imgHeight)
						// 设置水印颜色
						canvas.setFillStyle('rgba(0,0,0,0.8)');
						canvas.setFontSize(36);
						var text = _this.timeFunc(new Date());
						var textWidth = canvas.measureText(text).width;
						var x = 24;
						var y = 88; // 文本的基线位置
						canvas.fillText(text, x, y);
						canvas.draw();
						// 某些平台 canvas 绘制比较慢,需要等待绘制完成
						await _this.sleep(500)
						// 将 canvas 画布转换为图片地址
						uni.canvasToTempFilePath({
							destWidth: imgWidth,
							destHeight: imgHeight,
							fileType: 'jpg',
							canvasId: 'img-canvas',
							success: async (res) => {
								// 上传图片操作
								_this.uploadImageFunc(res.tempFilePath)
							}
						},_this)
					}
				})
			},
			sleep(millisecond) {
				return new Promise((resolve) => {
					setTimeout(resolve, millisecond)
				})
			},
		}
.canvas-img-box{
		position: fixed;
		top: -99999rpx;
		left: -99999rpx;
		z-index: -99999;
	}

图片预览receiptsNews.vue

<view>
		<view class="news-dia" v-if="diaShow" @tap="diaShow=false">
			<view class="news-dia-content" @tap.stop="diaShow=true">
				<swiper class="swiper" circular :indicator-dots="true" :autoplay="false"
					:current="curIndex">
					<swiper-item v-for="(item,index) in data" :key="index">
						<view class="swiper-item">
							<view class="news-img" style="heigh:880rpx">	<image :src="item.imgUrl" mode="widthFix"></image></view>
						</view>
					</swiper-item>
				</swiper>
			</view>
		</view>
	</view>
		props:{
			//数据
			data:{
				type:Array,
				default:[]
			}
		},
		data(){
			return{
				diaShow:false,
				curIndex:0
			}
		},
		methods:{
			openFuc(curIndex){
				this.diaShow = true;
				this.curIndex = curIndex;
			},
			closeFuc(){
				this.diaShow = false;
			}
		}
.news-dia{
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background-color: rgba(0,0,0,0.6);
		z-index: 99999;
		display: flex;
		align-items: center;
		justify-content: center;
		.news-dia-content{
			background-color: #ffffff;
			border-radius: 44rpx;
			width: 90%;
			height: 948rpx;
			overflow: hidden;
			.swiper{
				height: 100%;
			}
			.news-img{
				height: 600rpx;
				image{
					width: 100%;
				}
			}
			.news-tabs{
				padding: 24rpx 32rpx;
			}
			.news-tab{
				margin-top: 24rpx;
				font-size: 32rpx;
				color: #333333;
			}
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值