vue-cropper裁剪个人图像

需求:1.点击修改图像按钮,弹出修改图像弹窗
2.图片都是上传到oss上面
3.上传图像右侧有个原型和方型图像展示实时效果
在这里插入图片描述
1.安装vue-cropper

npm install vue-cropper

2.组件内引入

import { VueCropper } from 'vue-cropper';

3.封装组件

<template>
	<div>
		<el-dialog width="500px" :title="dialogTitle" :visible.sync="visible" append-to-body :close-on-click-modal="false" :before-close="close" class="dialog-container">
			<div v-loading="loading">
				<div class="body">
					<div class="cropp-content container">
						<div class="bg-white">
							<div class="cropper-cont">
								<vue-cropper
									ref="cropper"
									:img="option.img"
									:outputSize="option.size"
									:outputType="option.outputType"
									:info="true"
									:full="option.full"
									:canMove="option.canMove"
									:canMoveBox="option.canMoveBox"
									:fixedBox="option.fixedBox"
									:original="option.original"
									:autoCrop="option.autoCrop"
									:autoCropWidth="option.autoCropWidth"
									:autoCropHeight="option.autoCropHeight"
									:centerBox="option.centerBox"
									:high="option.high"
									:infoTrue="option.infoTrue"
									@realTime="realTime"
									@imgLoad="imgLoad"
									@cropMoving="cropMoving"
									:enlarge="option.enlarge"></vue-cropper>
							</div>

							<div class="pre mt8">
								<section class="pre-item">
									<div :style="previewStyle1">
										<div :style="previews.div">
											<img :src="previews.url" :style="previews.img" />
										</div>
									</div>
								</section>
								<section class="pre-item">
									<div :style="previewStyle2">
										<div :style="previews.div">
											<img :src="previews.url" :style="previews.img" />
										</div>
									</div>
								</section>
							</div>
						</div>
						<div class="test-button mt8">
							<el-button type="primary" style="margin-right: 20px">
								<label class="btn" for="uploads">选择图片</label>
							</el-button>
							<input type="file" id="uploads" style="position: absolute; clip: rect(0 0 0 0)" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event, 1)" ref="uploadImg" />
							<el-button type="primary" @click="finish('blob')">
								<label class="btn">上传并保存</label>
							</el-button>
						</div>
					</div>
				</div>
			</div>
		</el-dialog>
	</div>
</template>

<script>
	import API from '@/api/persional';
	import { VueCropper } from 'vue-cropper';
	export default {
		props: {
			dialogVisible: {
				type: Boolean,
				default: false
			},
			dialogTitle: {
				type: String,
				default: ''
			},
			persionImg: {
				type: String,
				default: ''
			}
		},
		components: { VueCropper },
		computed: {
			visible: function () {
				return this.dialogVisible;
			}
		},
		watch: {
			persionImg: {
				handler(nv) {
					this.option.img = nv;
					console.log(nv, 'nnn');
				},
				immediate: true
			}
		},
		data() {
			return {
				loading: false,
				model: false,
				modelSrc: '',
				previews: {},
				option: {
					img: '', //裁剪图片的地址 默认空,可选值url地址, base64, blob
					outputSize: 0.8, //裁剪生成图片的质量 默认1 可选0.1 ~ 1
					outputType: 'image/jpg,image/png', //裁剪生成图片的格式 jpg (jpg 需要传入jpeg) 可选:jpeg, png, webp
					info: true, //裁剪框的大小信息 默认:true
					canScale: false, //图片是否允许滚轮缩放
					autoCrop: true, //是否默认生成截图框
					// autoCropWidth: 80%, //默认生成截图框宽度 默认:80% 可选:0-max
					//autoCropHeight: 80%, //默认生成截图框高度 默认:80% 可选:0-max
					fixed: true, //是否开启截图框宽高固定比例
					fixedNumber: [1, 1], //截图框的宽高比例 [1, 1]-[ 宽度 , 高度 ]
					full: true, //是否输出原图比例的截图
					fixedBox: false, //固定截图框大小 默认不允许改变 可选:false
					//canMove: true,//上传图片是否可以移动
					canMoveBox: false, //截图框能否拖动
					original: false, //上传图片按照原始比例渲染
					canterBox: false, //截图框是否被限制在图片里面
					//high: true,//是否按照设备的dpr 输出等比例图片
					infoTrue: true //true 为展示真实输出图片宽高 false 展示看到的截图框宽高
					// maxImgSize: 2000 //限制图片最大宽度和高度 可选:0 ~ max
					//enlarge: 1, //图片根据截图框输出比例倍数 默认1 可选:0 ~ max(建议不要太大不然会卡死的呢)
					//mode: contain //contain , cover, 100px, 100% auto
				},
				example2: {
					img: 'http://cdn.xyxiao.cn/Landscape_2.jpg',
					info: true,
					size: 1,
					outputType: 'jpeg',
					canScale: true,
					autoCrop: true,
					// 只有自动截图开启 宽度高度才生效
					autoCropWidth: 300,
					autoCropHeight: 250,
					fixed: true,
					// 真实的输出宽高
					infoTrue: true,
					fixedNumber: [4, 3]
				},
				previewStyle1: {},
				previewStyle2: {}
			};
		},
		methods: {
			// 选择图片
			uploadImg(e, num) {
				// 上传图片
				// this.option.img
				let file = e.target.files[0];
				const reg = /\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/;
				if (!reg.test(e.target.value)) {
					this.$message.warning('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种');
					return;
				}
				let reader = new FileReader();
				reader.onload = ev => {
					let data;
					if (typeof ev.target.result === 'object') {
						// 把Array Buffer转化为blob 如果是base64不需要
						data = window.URL.createObjectURL(new Blob([ev.target.result]));
					} else {
						data = ev.target.result;
					}
					if (num === 1) {
						this.option.img = data;
					} else if (num === 2) {
						this.example2.img = data;
					}
					this.$refs.uploadImg.value = '';
				};
				// 转化为base64
				// reader.readAsDataURL(file)
				// 转化为blob
				console.log(file, 'file');
				reader.readAsArrayBuffer(file);
			},
			// 上传并且保存
			finish(type) {
				// 输出
				// var test = window.open('about:blank')
				// test.document.body.innerHTML = '图片生成中..'
				if (type === 'blob') {
					this.$refs.cropper.getCropBlob(data => {
						let img = window.URL.createObjectURL(data);
						this.model = true;
						this.modelSrc = img; //blob:http://localhost:10228/785ae593-ed77-40c8-8134-c836da6bc9bb
						console.log(data, 'data'); //Blob
						//data是Blob格式,转成file格式
						const file = new File([data], '');
						let formData = new FormData();
						console.log(file, 'file');
						formData.append('file', file);
						this.loading = true;
						API.getuploadHeadPortrait(formData)
							.then(res => {
								this.loading = false;
								console.log(res, 'rrr');
								this.$message.success(`${this.$t('change')}${this.$t('success')}`);
								this.$emit('close', 'success');
							})
							.catch(() => {
								this.loading = false;
							});
						console.log(this.modelSrc, 'this.modelSrc');
					});
				} else {
					this.$refs.cropper.getCropData(data => {
						this.model = true;
						this.modelSrc = data;
					});
				}
			},
			// 关闭弹窗
			close() {
				this.$emit('close', 'close');
			},
			// 实时预览函数--右侧展示样式
			realTime(data) {
				let previews = data;
				let h = 0.6; //高度固定,不然右侧预览会变形
				// let w = 0.2;
				this.previewStyle1 = {
					width: previews.w + 'px',
					height: previews.h + 'px',
					overflow: 'hidden',
					margin: '0',
					zoom: h,
					borderRadius: '50%'
				};

				this.previewStyle2 = {
					width: previews.w + 'px',
					height: previews.h + 'px',
					overflow: 'hidden',
					margin: '0',
					zoom: h
				};
				this.previews = data;
			},
			imgLoad(msg) {
				console.log(msg);
			},
			cropMoving(data) {
				this.option.cropData = data;
			}
		}
	};
</script>

<style scoped lang="scss">
	.dialog-container {
		.bg-white {
			display: flex;
			justify-content: space-around;
			margin-bottom: 30px;
			.cropper-cont {
				width: 274px;
				height: 274px;
			}
			.pre {
				display: flex;
				flex-direction: column;
				justify-content: space-around;
				align-content: space-around;
			}
		}
		.test-button {
			display: flex;
			justify-content: flex-end;
			align-items: center;
		}
		.pre-item {
			padding-right: 20px;
		}
	}
</style>

4.组件引用

<template>
<image-cropper v-if="imagecropperShow" :dialogVisible="imagecropperShow" :persionImg="persionPic" ref="addDialog" @close="onCloseDialog"></image-cropper>
</template>
<script>
import ImageCropper from '@/components/cropper/index';
data() {
			return {
				imagecropperShow: false,
				persionPic: '' // 图象接口返回的base64
			};
		},
		methods: {
			// 关闭裁剪弹窗
			async onCloseDialog(val) {
				if (val === 'success') {
					await this.serchMessage();
					console.log('修改');
				}
				this.imagecropperShow = false;
			},
			
			// 修改图象
			updatePersionalImage() {
		     	//oss图片请第二次,会报跨域,需要转成base64回显
				const fileKey = this.ruleForm.headPortrait;
				API.postBase64ByFileKey({ fileKey })
					.then(res => (this.persionPic = 'data:image/jpg;base64,' + res.data))
					.catch(err => {
						this.loading = false;
						this.$message.error(err.msg || '请求失败');
					});
				setTimeout(() => {
					this.imagecropperShow = true;
				}, 300);
			}
		}
</script>

总结:1.原始图像是oss,短时间请求两次,会报跨域,第二次回显图像编辑时,可让后端提供一个接口转成base64
2.option里面注释的属性,如果需要放开使用,在vue-cropper需要加入属性
3.获取的是Blob格式图片,需要转成file,const file = new File([data], ''); let formData = new FormData(); formData.append('file', file);
4.右侧预览需要固定宽或者高,不然选择裁剪高宽小于预览宽高,会变成椭圆,在realTime方法里

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值