前言
我们需要上传图片,然后弹框进行裁剪(放大、缩小)。
效果
实现
裁剪组件.vue
<template>
<div>
<!--裁剪图片-->
<el-dialog v-model="tailorDialogVisible" @open="onTailorDialogOpen" @close="onTailorDialogCancel" title="编辑图片" width="680" align-center>
<div style=" width: 550px; height: 450px; margin: 30px auto;" v-loading="loading"
element-loading-text="Loading...">
<vue-cropper ref="cropper"
:img="tailorOption.img"
:output-type="tailorOption.outputType"
:full="tailorOption.full"
:auto-crop="tailorOption.autoCrop"
:auto-crop-width="tailorOption.autoCropWidth"
:auto-crop-height="tailorOption.autoCropHeight"
:center-box="tailorOption.centerBox"
:max-img-size="tailorOption.max"
mode="cover"
@imgLoad="onTailorLoad"
></vue-cropper>
</div>
<div style="display: flex; margin: 0 200px; justify-content: center; align-items: center">
<div style="width: 40px;text-align: left; cursor: pointer;">
<!-- <el-icon @click="onScaleMinus(0.1)" :size="16"><Minus /></el-icon> -->
<span @click="onScaleMinus(0.1)">-号</span>
</div>
<div style="flex: 1">
<el-slider v-model="tailorAmplificationValue" :min="1" :max="3" :step="0.1" @change="onChangTailorAmplificationSlider" />
</div>
<div style="width: 40px;text-align: right; cursor: pointer;">
<!-- <el-icon @click="onScaleAdd(0.1)" :size="16"><Plus /></el-icon> -->
<span @click="onScaleAdd(0.1)">+号</span>
</div>
</div>
<div style="display: flex; margin: 10px 200px 40px 200px; justify-content: center; align-items: center">
<div style="width: 40px;text-align: left; cursor: pointer;">
<span @click="onRotateLeft">左旋</span>
<!-- <el-icon @click="onRotateLeft" :size="16"><Plus /></el-icon> -->
<!-- <img @click="onRotateLeft" style="width: 14px; height: 14px" src="../../../public/img/recipeManage/left_rotate.png" alt=""> -->
</div>
<div style="flex: 1">
<el-slider v-model="tailorSpinValue" :min="-180" :max="180" :step="90" @change="onChangTailorSpinSlider" />
</div>
<div style="width: 40px;text-align: right; cursor: pointer;">
<span @click="onRotateRight">右旋</span>
<!-- <el-icon @click="onRotateRight" :size="16"><Plus /></el-icon> -->
<!-- <img @click="onRotateRight" style="width: 14px; height: 14px" src="../../../public/img/recipeManage/right_rotate.png" alt=""> -->
</div>
</div>
<div style="padding-top: 20px;" class="recipeManage_border_top">
<div style="display: flex; align-items: center; justify-content: center">
<div>
<el-button type="primary" plain @click="onTailorDialogCancel">取消</el-button>
</div>
<div style="margin-left: 20px">
<el-button type="primary" @click="onTailorDialogSubmit">确认</el-button>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import 'vue-cropper/dist/index.css'
import { VueCropper } from "vue-cropper";
// import { postImgData } from '@/api/base/public';
import { ref, defineProps, toRefs, defineEmits } from 'vue';
const emit = defineEmits(['close', 'submit']);
const props = defineProps({
tailorDialogImg: {
default: ''
},
autoCropWidth: {
default: 180
},
autoCropHeight: {
default: 180
},
tailorDialogVisible: {
type: Boolean,
required: true,
default: false
},
});
const { tailorDialogVisible, tailorDialogImg, autoCropWidth, autoCropHeight } = toRefs(props);
const loading = ref(false);
// 裁剪图片
const cropper = ref("");
// const tailorDialogVisible = ref(visible.value);
const tailorAmplificationValue = ref(0);
const tailorSpinValue = ref(0);
const tailorOption = ref({
img: "",
full: false,
outputType: 'png',
autoCrop: true,
autoCropWidth: 180,
autoCropHeight: 180,
centerBox: true,
max: 99999,
});
// 放大
let oldTailorAmplificationValue = 0;
const onScaleAdd = (num) => {
if (tailorAmplificationValue.value === 3) return;
// tailorAmplificationValue.value = Number(parseFloat(tailorAmplificationValue.value + num).toFixed(1));
tailorAmplificationValue.value = +(parseFloat(tailorAmplificationValue.value + num).toFixed(1));
oldTailorAmplificationValue = tailorAmplificationValue.value;
cropper.value.changeScale(tailorAmplificationValue.value);
};
const onScaleMinus = (num) => {
if (tailorAmplificationValue.value === 1) return;
tailorAmplificationValue.value = tailorAmplificationValue.value - num;
oldTailorAmplificationValue = -tailorAmplificationValue.value;
cropper.value.changeScale(-tailorAmplificationValue.value);
};
const onChangTailorAmplificationSlider = (value) => {
if (oldTailorAmplificationValue > value) {
cropper.value.changeScale(-value);
} else {
cropper.value.changeScale(value);
}
oldTailorAmplificationValue = value;
};
// 旋转
let oldTailorRotateValue = 0;
const onChangTailorSpinSlider = (value) => {
if (value > 0) {
cropper.value.rotateRight();
} else {
cropper.value.rotateLeft();
}
};
const onRotateLeft = () => {
if (cropper.value.rotate === -2) return false;
cropper.value.rotateLeft();
oldTailorRotateValue = cropper.value.rotate * 90
console.log("===oldTailorRotateValue===", oldTailorRotateValue)
tailorSpinValue.value = cropper.value.rotate * 90
};
const onRotateRight = () => {
if (cropper.value.rotate === 2) return false;
cropper.value.rotateRight();
oldTailorRotateValue = cropper.value.rotate * 90
console.log("===oldTailorRotateValue===", oldTailorRotateValue)
tailorSpinValue.value = cropper.value.rotate * 90
};
const onTailorDialogOpen = () => {
console.log("===弹框打开===");
loading.value = true;
tailorOption.value.img = tailorDialogImg.value;
tailorOption.value.autoCropWidth = autoCropWidth.value;
tailorOption.value.autoCropHeight = autoCropHeight.value;
};
const onTailorLoad = (msg) => {
console.log("===msg===", msg)
loading.value = false;
};
const onTailorDialogCancel = () => {
emit('close');
loading.value = false;
tailorOption.value.img = "";
tailorAmplificationValue.value = 0;
tailorSpinValue.value = 0;
};
const onTailorDialogSubmit = () => {
cropper.value.getCropData(data => {
tailorAmplificationValue.value = 0;
tailorSpinValue.value = 0;
tailorOption.value.img = "";
emit('submit', data);
})
// cropper.value.getCropBlob(data => {
// // 创建 FormData 对象并添加 Blob 对象
// const formData = new FormData();
// formData.append('file', data, '1.png');
// // postImgData(formData).then((res) => {
// // if (res.data.code === 200) {
// // emit('submit', res.data.data);
// // }
// // }).catch(err => {});
// tailorAmplificationValue.value = 0;
// tailorSpinValue.value = 0;
// tailorOption.value.img = "";
// emit('submit', '');
// })
// let blob = await cropper.value.getCropBlob();
// // 创建 FormData 对象并添加 Blob 对象
// const formData = new FormData();
// formData.append('file', blob, '1.png');
// let res = postImgData(formData);
//
// emit('submit', res.data.data);
//
// tailorAmplificationValue.value = 0;
// tailorSpinValue.value = 0;
// tailorOption.value.img = "";
};
</script>
<style>
</style>
使用组件.vue
<template>
<div>
<el-upload action="#" :http-request="onImgRequest" :show-file-list="false" :before-upload="(file) => onImgUpload(file)">
<div style="height: 100px; width: 100px; background-color: red;">上传</div>
</el-upload>
<el-image v-if="imagesUrl" :src="imagesUrl"></el-image>
<tailorImage :tailorDialogVisible="tailorDialogVisible" :tailorDialogImg="tailorDialogImg" @submit="tailorDialogImgSucc"></tailorImage>
<!-- <el-image :src="src" /> -->
</div>
</template>
<script setup>
import tailorImage from "./components/TailorImage.vue"
import {ref} from "vue"
import { ElMessage } from 'element-plus';
const tailorDialogVisible = ref(false)
const tailorDialogImg = ref("")
const imagesUrl = ref("")
const onImgRequest = () => {};
const onImgUpload = (rawFile) => {
if (rawFile.type.indexOf('image/') === -1) {
ElMessage.error('文件格式错误,请上传图片类型,如: JPG,PNG后缀的文件');
return false;
} else {
const reader = new FileReader();
reader.readAsDataURL(rawFile);
reader.onload = () => {
tailorDialogImg.value = reader.result;
tailorDialogVisible.value = true;
};
}
};
const tailorDialogImgSucc = (data) => {
// console.log("===tailorDialogImgSucc===", data)
imagesUrl.value = data;
tailorDialogVisible.value = false;
tailorDialogImg.value = "";
}
// const test = () => {
// tailorDialogVisible.value = true
// console.log("===裁剪图片====");
// }
</script>
<style>
</style>