vue使用vue-advance-cropper图片裁剪插件

这里把 图片裁剪组件封装起来。参数展示的东西都用父组件提供:

<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} = Vue

            const 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>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值