这里把 图片裁剪组件封装起来。参数展示的东西都用父组件提供:
<template id="vueImageEditor" v-cloak><div class="flex space-x-5"><div><div class="bg-[#ffffff] rounded-md w-390px p-6 shadow-md"><div class="min-h-80px max-h-261px h-[calc(100vh-600px)] rounded-md"style="box-shadow: 0 10px 8px rgba(0, 0, 0, 0.2);"><img :src="imageUrl" class="w-full h-full object-contain rounded" /></div><div class="mt-4 space-y-4 text-12px"><div class="flex item-center"><div class="w-100px text-left text-[#606266] pr-3 font-bold">File name</div><div class="flex-1"><span class="text-[#999] break-all">{{props.fileName}}</span></div></div><div class="flex item-center"><div class="w-100px text-left text-[#606266] pr-3 font-bold">URL</div><div class="flex-1"><a class="text-[#999] break-all hover:underline" :href="previewUrl" target="_blank">{{props.previewUrl}}</a></div></div></div></div><div class="bg-[#ffffff] rounded-md w-390px p-6 mt-4 shadow-md"><div class="flex items-center justify-between text-12px"><span class="w-16 border-1 border-blue-300 cursor-pointer text-center rounded-md py-1.5":class="item.ratio===currentRatio?'isCheck':''" v-for="item in ratios" :key="item.text"@click="handleChangeRatio(item.ratio)">{{item.text}}</span></div><div class="flex items-center my-4 space-x-2"><el-input v-model.number="size.width" class="mr-1 widthInput"@change="handleChangeWidth(size.width)"><template #append><span class="">X</span></template></el-input><el-icon class="text-lg"><Lock /></el-icon><el-input v-model.number="size.height" class="mr-1 heightInput" @change="handleChangeHeight"><template #append><span class="">Y</span></template></el-input><el-input v-model.number="angle" class="mr-1 angleInput" @change="handleChangeAngle"><template #append><span class=" absolute -top-2.5">。</span></template></el-input></div><div class="text-right"><el-button round type="primary" class="bg-[#409eff] text-[#ffffff] w-120px" size="large"@click="handleCrop">Crop</el-button></div></div></div><div class="rounded-md px-6 w-720px flex items-center justify-center h-auto shadow-md"><div class="flex justify-center min-h-300px min-w-300px max-h-562px"><cropper ref="cropper" :src="imageUrl" :stencil-props="{aspectRatio: currentRatio}"@change="handleChangeCrop"></cropper></div></div></div></template><script>const vueImageEditor = {template: '#vueImageEditor',components: {cropper: VueAdvancedCropper.Cropper,},props: {fileName: String,previewUrl: String,imageUrl:String,},emits: ['update:imageUrl'],setup(props, {emit}) {const {ref} = Vueconst size = ref({width: 0,height: 0,});const cropper = ref()const handleCrop = () => {console.log("cropper", cropper.value, cropper.value.getResult(), props);if (!cropper.value) {return;}const {canvas} = cropper.value.getResult();console.log(" canvas.toDataURL()", canvas.toDataURL());if (canvas) {emit("update:imageUrl", canvas.toDataURL());}}const handleChangeWidth = (width) => {const transform = {width,}if (currentRatio.value > 0) {transform.height = size.value.width * currentRatio.value;}cropper.value.setCoordinates(transform);}const handleChangeHeight = () => {if (currentRatio.value > 0) {const width = size.value.height * currentRatio.value;handleChangeWidth(width);} else {cropper.value.setCoordinates({height: size.value.height,});}}const handleChangeCrop = () => {setSize();}const ratios = [{text: "Free",ratio: 0,},{text: "16:9",ratio: 16 / 9,},{text: "4:3",ratio: 4 / 5,},{text: "1:1",ratio: 1 / 1,},{text: "2:3",ratio: 2 / 3,},];const angle = ref(0)const currentRatio = ref(0)const handleChangeRatio = (ratio) => {cropper.value.reset();currentRatio.value = ratio;setSize();}const setSize = () => {setTimeout(() => {if (cropper.value) {const {coordinates} = cropper.value.getResult();size.value.width = coordinates.width;size.value.height = coordinates.height;}}, 100);}let oldAngle = angle.value;const handleChangeAngle = () => {if (isNaN(angle.value)) {angle.value = oldAngle;return;}cropper.value.rotate(angle.value - oldAngle);oldAngle = angle.value;}return {size,cropper,handleCrop,ratios,handleChangeRatio,currentRatio,setSize,angle,handleChangeHeight,handleChangeWidth,handleChangeCrop,handleChangeAngle,oldAngle,props}}};</script>
父组件使用:
<vue-image-Editor :file-name="media.name" :preview-url="media.url" v-model:image-url="media.imageUrl"></vue-image-editor>