首页/文章列表/文章详情

vue3和ts和vue-cropper 实现图片裁剪预览

编程知识552025-05-22评论

​​Vue-Cropper​​ 是一个基于 Vue.js 的图片裁剪组件库,专为 Web 应用设计。当你在网上搜索的时候发现还有一个叫cropper的库,下面是他们的区别:

二、快速上手

//npm 安装npm install vue-cropper//yarn 安装yarn add vue-cropper

对该插件进行封装,使用vue3 + ts

<script lang="ts" setup>import'vue-cropper/dist/index.css'import { VueCropper } from 'vue-cropper'const emit = defineEmits(['realTime'])const props = defineProps({ width: { type: Number, default: 640 }, height: { type: Number, default: 740 }})const options = reactive({ img: '', autoCrop: true, autoCropWidth: 640, autoCropHeight: 740, fillColor: '#fff',//裁剪框填充颜色fixedBox:true//固定裁剪框})const cropperInstance = ref()const blobData = ref(new Blob())const init = () => { options.img = ''}const selectImg = async (e: Event) => { const file = (e.target as HTMLInputElement).files?.[0]if(!file)return const reader =new FileReader() reader.onload = async e => { const img =new Image() img.onload = async () =>{//强制放大到最小尺寸 const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d')! // 设置 canvas 尺寸 canvas.width = img.width canvas.height = img.height ctx.drawImage(img, 0, 0, canvas.width, canvas.height) options.img = canvas.toDataURL() await nextTick() // 等待 DOM 更新后设置裁剪框 setFixedCropBox() } img.src = e.target!.result as string } reader.readAsDataURL(file)}const setFixedCropBox = () =>{if(!cropperInstance.value?.cropper)return//正确访问cropper实例 const cropper =cropperInstance.value.cropper//获取容器真实尺寸 const containerWidth = cropper.containerData.width const containerHeight =cropper.containerData.height//计算居中位置 const left = (containerWidth - props.width) / 2 const top = (containerHeight - props.height) / 2 //正确调用方法 cropper.setCropBoxData({ width: props.width, height: props.height, left, top })}//实时预览const realTime = (data: any) => { emit('realTime', data.html)}// 获取截图的数据 getCropBlob => blob数据const tailoring = (): Promise<Blob> =>{returnnew Promise((resolve, reject) =>{if(!cropperInstance.value) { reject(newError('裁剪组件未初始化'))return } cropperInstance.value.getCropBlob((data: Blob) =>{if (data) { blobData.value = data resolve(data) } else { reject(new Error('裁剪失败,未获取到 Blob')) } }) })}//旋转const rotateLeft = () =>{if(!cropperInstance.value)return cropperInstance.value.rotateLeft()}const rotateRight = () =>{if(!cropperInstance.value)returncropperInstance.value.rotateRight()}onMounted(()=>{if (props.width && props.height) { options.autoCropWidth = props.width options.autoCropHeight = props.height }})defineExpose({ options, selectImg, realTime, tailoring, blobData, init, rotateLeft, rotateRight })</script><template> <vue-cropper ref="cropperInstance":img="options.img":autoCrop="options.autoCrop":autoCropWidth="options.autoCropWidth":autoCropHeight="options.autoCropHeight":fixedBox="options.fixedBox":fillColor="options.fillColor"@real-time="realTime" /></template>

父组件进行使用

  
   <el-form-item>
            <div class="flex items-center gap-10px">
                <span>公告图片</span>
                <!-- <el-button size="small" type="primary" class="mx-0" @click="openUpload">
                    <el-icon class="mr-3px"><Upload /></el-icon> 上传</el-button
                > -->
                <el-button :type="form.backgroundImage ? 'success' : 'primary'" @click="openUpload">
                    <el-icon class="mr-3px"><Upload /></el-icon>
                    {{ form.backgroundImage ? '重新上传' : '上传' }}</el-button
                >
                <el-button class="mx-0" type="danger" :icon="Delete" @click="form.backgroundImage = ''"></el-button>
                <div class="text-slate text-xs">建议:宽高640*740,png或jpg/jpeg格式,小于2M</div>
            </div>
            <input type="file" name="" ref="uploadRef" class="hidden" @change="handleCaptureUpload" />
        </el-form-item>

        <!-- 图片预览裁剪 -->
        <el-dialog
            v-model="showCaptureVisible"
            title="图片预览裁剪"
            width="50%"
            @close="closeCapture"
            top="5vh"
            draggable
            destroy-on-close
        >
            <div class="w-full h-78vh mt-10px flex justify-center items-center">
                <Cropper ref="cropper" :height="740" :width="640"></Cropper>
            </div>
            <template #footer>
                <span class="dialog-footer">
                    <el-button :icon="RefreshRight" type="info" @click="handleRotateRight"></el-button>
                    <el-button :icon="RefreshLeft" type="info" @click="handleRotateLeft"></el-button>
                    <el-button type="info" @click="closeCapture">关闭</el-button>
                    <el-button type="primary" @click="tailoring" :loading="cropperLoading">确定</el-button>
                </span>
            </template>
        </el-dialog>

<script setup lang="ts">
 
const uploadRef = ref()
const showCaptureVisible = ref(false)
const cropper = ref()
// 上传图片loading
const { loading: cropperLoading } = useLoading()
// 裁剪图片
const tailoring = async () => {
    //文件大小
    cropperLoading.value = true
    const blob = await cropper.value.tailoring()
    if (blob.size > 2 * 1024 * 1024) {
        cropperLoading.value = false
        warningMessage('图片大小超出2M限制')
        return
    }

    const formData = new FormData()
    formData.append('file', blob, 'cropped.jpg')
    formData.append('accountId', regionSelect.brandId as string)
    uploadImage(formData) // 这里调用后台api
        .then(
            async res => {
                form.value.backgroundImage = res.data
                doSuccess('上传成功')
            },
            () => {
                ElNotification({
                    type: 'warning',
                    message: '图片上传失败'
                })
            }
        )
        .finally(() => {
            formRef.value?.validate().catch(() => {})
            // 关闭裁剪
            showCaptureVisible.value = false
            cropperLoading.value = false
        })
}

// 图片旋转
const handleRotateLeft = () => {
    cropper.value?.rotateLeft()
}

const handleRotateRight = () => {
    cropper.value?.rotateRight()
}
// 上传图片
const handleCaptureUpload = (e: any) => {
    const input = e.target as HTMLInputElement
    if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
        warningMessage('图片类型要求:jpeg、jpg、png')
        return false
    }
    showCaptureVisible.value = true
    nextTick(() => {
        cropper.value?.selectImg(e)
        input.value = ''
    })
}
// 关闭裁剪
const closeCapture = () => {
    showCaptureVisible.value = false
}
</script>


效果图:

可进行图片旋转,裁剪 自定义裁剪的图片大小

三.vue-cropper的全部参数

 

 

神弓

小吴3

这个人很懒...

用户评论 (0)

发表评论

captcha