vue3+ts 使用VueCropper实现剪切图片

效果图: 

 参考文档:

Vue-Cropper 文档Vue-Cropper 文档

安装VueCropper

//npm安装
npm install vue-cropper@next -d --save//yarn安装
yarn add vue-cropper@next

引入组件

 在main.ts中全局注册:

import VueCropper from 'vue-cropper'; 
import 'vue-cropper/dist/index.css';const app = createApp(App);
app.use(VueCropper);
app.mount('#app');

局部:

import 'vue-cropper/dist/index.css';
import { VueCropper } from 'vue-cropper';

代码层:

页面(父组件)
<template><div class="p-4"><imgv-if="photo":src="photo"class="avatar"@click="handleClick"/><el-icon v-else class="avatar-uploader-icon" @click="handleClick"><Plus/></el-icon><ImageCropperv-model="visible"@onSuccess="onSuccess":image="photo"></ImageCropper></div>
</template><script setup lang="ts">
import ImageCropper from "@/components/imageCropper.vue";//裁剪图片组件
import { uploadPicturesApi } from "@/api/common/index";
import { ElMessage } from "element-plus";
import { ref } from "vue";
const visible = ref<boolean>(false); //上传图片弹框
const photo=ref<string>('')
// 打开弹框
const handleClick = (img: string) => {console.log(img);visible.value = true;
};const handleClickImgUrl = () => {console.log(formInfo.value);
};/*** 上传图片成功* @param data File*/
const onSuccess = async (data: File) => {console.log(data);try {
//接口上传为formDataconst res = await uploadPicturesApi(data);if (res.code == 200) {formInfo.value.photo = res.data;//接口返回图片地址ElMessage.success("上传成功");visible.value = false;}console.log(res);} catch (error) {ElMessage.error("上传失败");}
};
</script><style lang="scss" scoped>
.avatar {width: 160px;height: 160px;display: block;/* border: 1px dashed #8c939d; */border-radius: 6px;
}.el-icon.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: 160px;height: 160px;text-align: center;border: 1px dashed #8c939d;border-radius: 6px;
}
</style>
 封装剪切图片组件(子组件):
<template><el-dialogappend-to-body:close-on-click-modal="false"v-model="visible"title="图片裁剪"width="800px"@close="handleClose"><div class="cropper-cut"><div class="picUpload-wraper"><div class="pic-left-wraper"><VueCropperref="cropperRef":img="option.img":outputType="option.outputType":info="true":full="option.full":canMove="option.canMove":canScale="option.canScale":canMoveBox="option.canMoveBox":fixed="option.fixed":fixedBox="option.fixedBox":original="option.original":autoCrop="option.autoCrop":autoCropWidth="cropWith || option.autoCropWidth":autoCropHeight="cropHeight || option.autoCropHeight":centerBox="option.centerBox":high="option.high":infoTrue="option.infoTrue":enlarge="option.enlarge"@realTime="realTime"></VueCropper></div><div class="pic-right-wraper"><div class="title">图片预览</div><div :style="previewStyle" class="previewImg" v-show="option.img"><div :style="previews.div"><img :src="previews.url" :style="previews.img" /></div></div></div></div><div class="pic-operate"><inputstyle="display: none"@change="handleChange"ref="fileRef"type="file"name=""id=""/><el-button @click="fileRef?.click()">选择图片</el-button><el-button @click="changeScale(1)" :icon="Plus"> </el-button><el-button @click="changeScale(-1)" :icon="Minus"> </el-button><el-button @click="rotateRight()" :icon="RefreshRight"> </el-button></div></div><template #footer><div class="dialog-footer"><el-button @click="$emit('update:modelValue', false)">取消</el-button><el-button @click="saveHeadPic">保存</el-button></div></template></el-dialog>
</template><script setup lang="ts">
import { reactive, ref, watch } from "vue";
import { VueCropper } from "vue-cropper";
import "vue-cropper/dist/index.css";
import { Plus, Minus, RefreshRight } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";const props = defineProps({// 窗口modelValue: {type: Boolean,default: false,},//   大小limitSize: {type: Number,default: 100,},//   宽cropWith: {type: String,default: "350px",},//   高cropHeight: {type: String,default: "350px",},accept: {type: Array<String>,default: () => [],},//   校验regExp: {type: RegExp,default: /\.(jpg|jpeg|png)$/i,},
});const emit = defineEmits(["update:modelValue", "onSuccess"]);const visible = ref<boolean>(false);const option = reactive({img: "",outputSize: 1, // 裁剪生成图片的质量 1 0.1 - 1outputType: "png", //  裁剪生成图片的格式 jpg (jpg 需要传入jpeg)  jpeg || png || webpinfo: true, //  裁剪框的大小信息  true  true || falsecanScale: true, // 图片是否允许滚轮缩放  true  true || falseautoCrop: true, //是否默认生成截图框 false true || falseautoCropWidth: 240, //默认生成截图框宽度 容器的80%  0~maxautoCropHeight: 300, //默认生成截图框高度  容器的80%  0~maxfixed: false, //是否开启截图框宽高固定比例  true  true | false// fixedNumber: [1, 1], //截图框的宽高比例 [1, 1]  [宽度, 高度]full: false, //是否输出原图比例的截图  false true | falsefixedBox: true, //固定截图框大小 不允许改变  false true | falsecanMove: false, //上传图片是否可以移动  true  true | falsecanMoveBox: true, //截图框能否拖动 true  true | falseoriginal: false, //上传图片按照原始比例渲染 false true | falsecenterBox: false, //截图框是否被限制在图片里面  false true | falsehigh: false, //是否按照设备的dpr 输出等比例图片  true  true | falseinfoTrue: false, //true 为展示真实输出图片宽高 false 展示看到的截图框宽高 false true | falsemaxImgSize: 2000, //限制图片最大宽度和高度 2000  0-maxenlarge: 1, //图片根据截图框输出比例倍数 1 0-max(建议不要太大不然会卡死的呢)mode: "contain", //图片默认渲染方式  contain contain , cover, 100px, 100% auto
});const previewStyle = ref<any>({});
const previews = ref<any>({});const fileRef = ref<HTMLInputElement>();
const cropperRef = ref<typeof VueCropper>();
let _file: File | null = null;watch(() => props.modelValue,(val) => {visible.value = val;}
);/*** 选择图片* @param e*/
const handleChange = (e: Event) => {const _target = e.target as HTMLInputElement;// console.log(_target)if (_target.files && _target.files.length > 0) {_file = _target.files[0];if (_file.size / 1024 / 1024 > props.limitSize) {ElMessage.warning(`图片大小不能超过${props.limitSize}MB`);return;}// const type = _file.name.split('.')[1]if (!props.regExp.test(_file.name)) {ElMessage.warning(`请上传jpg、jpeg、png格式图片`);return;}const reader = new FileReader();reader.readAsDataURL(_file);reader.onload = (e) => {option.img = e.target?.result as string;};}
};
/***  实时预览事件* @param data*/
const realTime = (data: any) => {previews.value = data;previewStyle.value = {width: data.w + "px",height: data.h + "px",overflow: "hidden",margin: "0",zoom: 160 / data.w,};
};
/*** 放大缩小* @param num*/
const changeScale = (num: number) => {num = num || 1;cropperRef.value?.changeScale(num);
};
/*** 旋转图片*/
const rotateRight = () => {cropperRef.value?.rotateRight();
};/*** 取消清空*/
const handleClose = () => {// console.log('close')option.img = "";fileRef.value && (fileRef.value.value = "");previews.value = {};previewStyle.value = {};cropperRef.value?.clearCrop();_file = null;emit("update:modelValue", false);
};/***上传保存图片*/
const saveHeadPic = () => {if (!option.img) return ElMessage.warning("请先上传图片");cropperRef.value?.getCropBlob((blob: Blob) => {// blob 转 fileif (_file) {const file = new File([blob], _file.name, { type: _file.type });emit("onSuccess", file);} else {ElMessage.error("获取图片失败");}});
};
</script><style lang="scss" scoped>
.picUpload-wraper {height: fit-content;display: flex;justify-content: space-between;.pic-left-wraper {width: 540px;height: 360px;border: 1px solid #ddd;}.pic-right-wraper {padding: 20px;width: 200px;max-height: 360px;border: 1px solid #ddd;background: #fafafa;.title {margin-bottom: 10px;font-size: 14px;font-weight: 600;}.previewImg {max-height: 360px !important;overflow: hidden;}}
}
.pic-operate {margin-top: 10px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84992.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-table特殊表头样式

el-table特殊表头样式 实现表头是按钮 <el-table-column align"center"><template slot"header"><el-buttonsize"mini"type"primary"icon"el-icon-plus"circleclick"addData"></el-button&g…

el-tree的属性render-content自定义样式不生效

需求是想要自定义展示el-tree的项&#xff0c;官网有一个:render-content属性&#xff0c;用的时候发现不管是使用class还是style&#xff0c;样式都没有生效&#xff0c;还会报一个错&#xff0c;怎么个事呢&#xff0c;后来发现控制台还会报一个错“vue.js:5129 [Vue warn]: …

银杏书签里的春天

春末的细雨沾湿了旧书扉页&#xff0c;我在泛黄的《飞鸟集》里发现那枚银杏书签时&#xff0c;窗外的梧桐树正抖落最后一片枯叶。深褐色的叶脉间夹着张字条&#xff0c;娟秀的字迹被岁月晕染&#xff1a;"给永远在奔跑的人。" 十年前的我在旧书店打工&#xff0c;每天…

spring-ai 1.0.0 学习(十四)——向量数据库

向量数据库是AI系统中常用的工具&#xff0c;主要用来存储文档片段及进行语义相似度查找 与传统数据库不同&#xff0c;它执行的是相似度查找而不是精确匹配 最小化样例 首先在application.properties中&#xff0c;根据所用Embedding模型&#xff0c;添加一个嵌入式模型型号…

Spring Boot 的Banner的介绍和设置

Spring Banner 是指在 Spring Boot 应用启动时,控制台上显示的那一段 ASCII 艺术字(通常是 Spring 的 logo),以及一些应用信息。 Banner 是 Spring Boot 提供的一个小但有趣的功能,可以让应用程序启动时更具个性也显得更高级。 默认 Banner Spring Boot 内置了一个默认…

魅族“换血”出牌:手机基本盘站不稳,想靠AI和汽车“改命”

撰稿|何威 来源|贝多财经 被吉利收购后&#xff0c;魅族逐渐转向在AI领域躬身耕作。 自2024年2月以“All in AI”正式宣告转型、喊出不再推出传统智能手机的豪言开始&#xff0c;这家曾以设计见长的手机厂商&#xff0c;将下半场押注在AI终端、AR眼镜与智能座舱系统上&#…

力扣热题100之将有序数组转换为二叉搜索树

题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 代码 使用递归的方法 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # s…

mac隐藏文件现身快捷键

在 macOS 系统中&#xff0c;‌显示/隐藏隐藏文件‌ 有两种常用方法&#xff0c;以下是详细说明&#xff1a; ✅ 方法一&#xff1a;使用快捷键&#xff08;最简单&#xff09; 打开 ‌访达&#xff08;Finder&#xff09;‌。 进入任意文件夹&#xff08;如桌面或文档&#x…

IAR Workspace 中 Debug 与 Release 配置的深度解析

IAR Workspace 中 Debug 与 Release 配置的深度解析 一、配置的本质区别 1. 核心目标对比 特性Debug 配置Release 配置优化目标调试友好性性能/尺寸优化代码优化无或低优化 (-O0/-O1)高级优化 (-O2/-O3/-Oz)调试信息包含完整符号信息无或最小化符号断言检查启用通常禁用输出…

Ubuntu下安装python3

一、下载python3源码 以要安装的是python3.13.5为例&#xff0c;在 Index of /ftp/python/3.13.5/ 下载Python-3.13.5.tgz&#xff1a; 将压缩包上传到Ubuntu系统中&#xff0c;解压&#xff1a; tar -zxvf Python-3.13.5.tgz 二、安装 进入解压后的源码目录&#xff1a; c…

计算机基础和Java编程的练习题

1. 计算机的核心硬件是什么&#xff1f;各自有什么用&#xff1f; 中央处理器&#xff08;CPU&#xff09;&#xff1a;负责执行程序中的指令&#xff0c;进行算术和逻辑运算&#xff0c;是计算机的“大脑”。 内存&#xff08;RAM&#xff09;&#xff1a;临时存储CPU正在处…

桥头守望者

赵阿姨在324国道边的便利店守了八年柜台&#xff0c;她的记账本里藏着特殊的日历——那些标着KLN字母的运输单据总在固定日期出现&#xff0c;精确得像是节气。"比气象台还准"&#xff0c;她指着玻璃窗上凝结的水珠说。去年寒潮来袭时&#xff0c;她亲眼看见送货员小…

C语言函数的参数传递和C++函数的参数传递

文章目录 C语言值传递地址传递 C引用传递 C语言 值传递 这种方式使用变量、数组元素作为函数参数&#xff0c;实际是将实参的值复制到形参相应的存储单元中&#xff0c;即形参和实参分别占用不同的存储单元&#xff0c;这种传递方式称为“参数的值传递”。在调用结束后&#…

设计模式-三大工厂

工厂模式有三种&#xff0c;分别是简单工厂模式、工厂方法模式、抽象工厂模式。三种模式从前到后越来越抽象&#xff0c;也更具有一般性。 设计模式 优点 缺点 简单工厂 1.实现了对责任的分割&#xff0c;它提供了专门的工厂类用于创建对象。 1.违背了开闭原则。 2.使用了…

在 AI 工具海洋中掌舵:Cherry Studio 如何成为你的统一指挥中心

01 被 AI 工具包围的知识工作者现状 在这个 AI 爆发的时代&#xff0c;知识工作者的工具库正经历前所未有的扩容。以我为例&#xff0c;按平台类型梳理日常使用的 AI 工具&#xff0c;已然形成三层矩阵&#xff1a; 「云端智能助手」&#xff1a;Kimi、豆包、ChatGPT、Gemini…

Java 线程池技术深度解析与代码实战

为什么线程池总在深夜崩溃&#xff1f; 昨天我这项目又经历了一次爆破——路由推送服务突然崩溃&#xff0c;排查发现线程池队列堆积了几万任务直接把内存撑爆。早上起来看见人都麻了&#xff0c;线程池用不好&#xff0c;分分钟变系统炸弹。今天我们就来系统梳理线程池的实战…

Gradio可视化构建聊天机器人

Gradio是一个Python库&#xff0c;专门用于快速构建和部署机器学习模型的Web界面。它的名字来源于"Gradient"&#xff08;梯度&#xff09;&#xff0c;最初是为了让机器学习开发者能够快速展示他们的模型而设计的。 1. Gradio是什么&#xff1f; 核心概念 快速原…

selenium如何识别条形验证码,自动输入验证码

在自动化测试或网页爬取中&#xff0c;识别验证码是常见的难点。Selenium 本身不具备直接识别验证码的能力&#xff0c;但可以通过结合第三方工具、OCR 技术或人工介入等方式解决。以下是多种可行方案的详细实现思路及代码示例&#xff1a; 一、方案一&#xff1a;使用第三方验…

SAP将指定EXCEL工作SHEET的数据上传到内表

SAP将指定EXCEL工作SHEET的数据上传到内表 本文描述了一个SAP ABAP类方法upload_excel_2internaltab&#xff0c;用于将Excel文件数据上传到内部表。主要功能包括&#xff1a; 验证Excel行列范围有效性&#xff0c;若起始值大于结束值则抛出异常检查文件是否存在&#xff0c;支…

Spring Boot(九十三):Springboot 整合cfx实现webservice接口

1 服务端 最近项目改造,有一些老项目接口协议是webservice soap1.1,这就需要我们提供webservice服务接口。在Spring Boot中整合CFX(CXF框架)以实现Web服务客户端与服务端的功能,可以分为几个步骤。下面我将详细介绍如何在Spring Boot中设置一个Web服务端点,使用Apache CX…