vue3+vant+cropper.js实现移动端图片裁剪功能
一、前言
最近做项目中遇到一个需求,需要对海报图片按照一定的比例进行裁剪并上传到oss。一开始这个需求思路有两个,使用canvas原生或者寻找现成的第三方库,对比了一番觉得canvas实现时间耗费较长,且秉承着不重复造轮子的原则(其实是菜)。
在进行技术调研后,决定使用vue-cropper插件来实现,预想会顺利,可结果恰恰相反!安装vue-cropper设置参数封装完组件后,发现裁剪框和裁剪的图片在h5页面上不能拖动,在web页面上可以,看源码里面也有兼容移动端的方法代码,在github上的issue里面也没发现有人遇到相同问题,难道就我遇到了?问度娘发现大家都可以,为什么我的就不行呢?后来又使用了vue-cropper-h5,也存在各种问题。其实,vue-cropper、vue-cropper-h5、vue-cropperjs等插件都是基于cropper.js实现的,最终决定使用cropper.js去实现。官方封装了很多参数、方法、事件,上手容易,文档阅读体验较好、而且便于扩展。下面就来详细介绍一个cropper.js的详细用法吧!
cropper.js可以对指定的图片进行裁剪,可以自己选择裁剪的交互方式,如大小、纵横比等,裁剪后可以生成一个包含裁剪图的canvas对象,借助canvas的toDataURL方法可以生成一张Base64格式的图片,再通过toBlob转换成blob类型文件,再通过new File(),转换成file文件上传,当然也可以直接上传裁剪后生成的base64。还有另外一种不使用canvas的方式,利用该工具丰富的api可以拿到裁剪区域相对于原图的各项数据,使用这些数据进行css绝对定位即可展示裁剪后的图,该方式可以保证图片不失真和完整。
二、项目环境
1.node
v16.0.0
2.vue
"vue": "^3.2.45"
3.vant
"vant": "^4.0.2"
4.cropper.js
"cropperjs": "^1.5.13"
三、使用
1.安装
yarn add cropperjs
2.引入,要导入样式,不然不会生效
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.min.css'
3.模板
<div class="v-simple-cropper"><van-uploader:after-read="afterRead"><template #default><img v-if="imgUrl" class="upload-img" :src="imgUrl" alt=""><div v-else class="upload-area" /></template></van-uploader><div v-show="showlayer" class="v-cropper-layer"><van-row class="layer-header" :gutter="36"><van-col :span="8"><van-button type="danger" plain block size="small" @click="cancelHandle">取消</van-button></van-col><van-col :span="8"><van-button type="success" block size="small" @click="rotateHandle">旋转</van-button></van-col><van-col :span="8"><van-button type="primary" block size="small" @click="confirmHandle">裁剪并上传</van-button></van-col></van-row><img ref="cropperImg"></div></div>
</template>
4.js
<script setup lang="ts">
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.min.css'
import { onMounted, ref, watch } from 'vue'
import { closeToast, showFailToast, showLoadingToast, showToast } from 'vant'
import { useRequest } from 'vue-request'
import { fileUpload } from '@/api/basic/index'const props = defineProps({url: {type: String,default: '',},width: {type: Number,},height: {type: Number,},scale: {type: Number,default: 0.8}
})
const emit = defineEmits(['update:url'])const cropperImg = ref<any>(null)
const cropper = ref<any>(null)
const showlayer = ref(false)
const imgUrl = ref(props.url)watch(() => props.url, (val) => {if (val)imgUrl.value = val
})function init() {cropper.value = new Cropper(cropperImg.value, {viewMode: 1,// 根据所需图片宽高,计算比例aspectRatio: props.width && props.height ? (Number(props.width) / Number(props.height)) : 1 / 0.618,dragMode: 'move',cropBoxResizable: false,autoCropArea: 1,})
}
// 选择图片
function afterRead(file) {// 判断扩展名const tmpCnt = file.file.name.lastIndexOf('.')const exName = file.file.name.substring(tmpCnt + 1)const names = ['jpg', 'jpeg', 'png']if (!names.includes(exName)) {showToast('不支持的格式!')return}const URL = window.URL || window.webkitURLconst binaryData = []binaryData.push(file.file)cropper.value.replace(URL.createObjectURL(new Blob(binaryData)))showlayer.value = true
}// 旋转
function rotateHandle() {cropper.value.rotate(90)
}
function cancelHandle() {cropper.value.reset()showlayer.value = false
}
// 上传方法
const { run: runUplaod } = useRequest(fileUpload, {manual: true,onSuccess: (res) => {closeToast()imgUrl.value = res.imgUrlemit('update:url', res.imgUrl)},onError: (err) => {closeToast()showFailToast(err.message)},
})
// 裁剪并上传
function confirmHandle() {const cropBox = cropper.value.getCropBoxData();const scale = props.scale || 1;cropper.value.getCroppedCanvas({width: cropBox.width * scale,height: cropBox.height * scale,})// 把裁剪的图片转换成blob类型文件,在通过new File(),转换成file文件.toBlob(async (blob) => {// 重置file的name,以时间戳作为文件名const timeString = new Date().getTime()const imgFile = new File([blob], `${timeString}.jpg`, {type: 'image/jepg',})showlayer.value = falseshowLoadingToast({message: '上传中...',duration: 0,forbidClick: true,})runUplaod(imgFile)})
}onMounted(() => {init()
})
</script>
5.style
<style lang="less" scoped>
.v-simple-cropper {text-align: center;padding-top: 10px;.upload-area {width: 190px;height: 120px;background: url('@/assets/bg-upload-box.png');background-size: 100% 100%;}.upload-img {width: 190px;height: 120px;}/deep/.van-uploader__upload {margin: 0 !important;}.v-cropper-layer {position: fixed;top: 0;bottom: 0;left: 0;right: 0;background: #fff;z-index: 200;.layer-header {position: absolute;bottom: 0;left: 0;z-index: 200;width: 100%;padding: 0 16px 12px;box-sizing: border-box;}img {position: inherit !important;border-radius: inherit !important;float: inherit !important;}}
}
</style>
在上面的代码中,我们使用了cropperjs组件来实现图片裁剪功能。在afterRead方法中,我们获取用户上传的图片,并将其转换为URL对象。在confirmHandle方法中,我们使用getCroppedCanvas方法获取裁剪后的canvas对象,并使用toBlob方法将其转换为Blob对象,最后将其转换为File对象并上传oss,返回一个oss url。
四、其他
1.预览功能
上面创建cropper的时候,我们可以在选项中添加了如下代码实现预览功能。
preview:[document.querySelector('.previewBox'), document.querySelector('.previewBoxRound')
]
preview就是用来设置我们需要实时预览的地方,但是设置完成之后要给上述的两个div添加一下样式,才可以正常显示。
.previewBox {box-shadow: 0 0 5px #adadad;width: 100px;height: 100px;margin-top: 30px;/*这个超出设置为隐藏很重要,否则就会整个显示出来了*/overflow: hidden;
}
2. 官方文档
(1)官网示例
https://fengyuanchen.github.io/cropper/
(2)官方github文档
https://github.com/fengyuanchen/cropperjs
(3)npm官方网站
https://www.npmjs.com/package/cropper
相关文章:
vue3+vant+cropper.js实现移动端图片裁剪功能
一、前言 最近做项目中遇到一个需求,需要对海报图片按照一定的比例进行裁剪并上传到oss。一开始这个需求思路有两个,使用canvas原生或者寻找现成的第三方库,对比了一番觉得canvas实现时间耗费较长,且秉承着不重复造轮子的原则&am…...
springCould中的Bus-从小白开始【11】
目录 🧂1.Bus是什么❤️❤️❤️ 🌭2.什么是总线❤️❤️❤️ 🥓3.rabbitmq❤️❤️❤️ 🥞4.新建模块3366❤️❤️❤️ 🍳5.设计思想 ❤️❤️❤️ 🍿6.添加消息总线的支持❤️❤️❤️ ǹ…...
xshell和xftp
1.xshell和xftp的关系 Xftp和Xshell都是Xmanager Power Suite的组件,它们的功能和用途有所不同。 Xshell是一个用于MS Windows平台的强大的SSH、telnet和rlogin终端仿真软件,它使得用户能轻松和安全地从Windows PC上访问Unix/Linux主机。 Xftp是一个用…...
python for...else用法,一个实例就能让你明白
直接上代码,很简单,不用讲解吧,看不懂的话,就需要补充下基础知识了。 def funct2():for i in range(4):try:assert i>2print("success")breakexcept Exception as e:print(error)continueelse:print(循环不合预期)d…...
windows 设置ip命令bat脚本
您可以使用以下命令创建一个批处理文件(.bat)来添加IP地址: echo off set ipaddress set subnetmask set gatewaynetsh interface ip set address name"以太网" sourcestatic address%ipaddress% mask%subnetmask% gateway%gatewa…...
Openharmony 对应Android内存查看
众所周知,内存查看是一个很重要的部分,大多数情况,我们都是使用dumpsys的方法对android的内存进行查看,但是对于openharmony而言好像又不太一样了。 Android内存查看 命令行: adb shell dumpsys meminfo <packag…...
R语言【paleobioDB】——pbdb_interval():通过ID选择,返回一个地层年代段的基本信息
Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新,该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后,执行本地安装。 Usage pbdb_interval (id, ...) Arguments 参数【id】…...
spring boot mybatis plus mapper如何自动注册到spring bean容器
##Import(AutoConfiguredMapperScannerRegistrar.class) ##注册MapperScannerConfigurer ##MapperScannerConfigurer.postProcessBeanDefinitionRegistry方法扫描注册mapper ##找到mapper候选者 ##过滤mapper 类 候选者 ##BeanDefinitionHolder注册到spring 容器...
What is `@PathVariable` does?
PathVariable 是SpringMVC中的注解,用于将HTTP请求的URI路径变量映射到Controller方法参数上。 当URL路径中包含占位符(由大括号 {} 包围的部分)时,可以使用此注解来绑定这些动态部分到方法参数。 使用样例 获取单个路径变量 …...
如何利用小程序介绍公司品牌形象?
企业小程序的建设对于现代企业来说已经成为了一项必不可少的工作。随着移动互联网的快速发展,越来越多的职场人士和创业老板希望通过小程序来提升企业形象,增强与用户的互动,实现更好的商业效果。在这个过程中,使用第三方制作平台…...
[C#]使用sdcb.paddleocr部署v4版本ocr识别模型
【官方框架地址】 https://github.com/sdcb/PaddleSharp 【算法介绍】 PaddleOCR,全称为PaddlePaddle OCR,是PaddlePaddle深度学习平台下的一款强大的光学字符识别工具。它利用深度学习技术,实现了高精度的文字识别,可以帮助用户…...
Echarts图表如何利用formatter自定义tooltip的内容和样式
在展示多数据图表的时候 有的时候需要图例也展示出一些内容来,例如官方这样子:鼠标悬停的时候展示该点数据 但是,官方提供的样式有时不适用所有的开发场景 我的项目需要实现鼠标悬停在某一点的时候,只展示该条线的数据࿰…...
Ceph源码分析-s->req_id = store->svc()->zone_utils->unique_id(req->id)
s->req_id store->svc()->zone_utils->unique_id(req->id); 涉及到指针和对象方法的调用。我会逐步为你解释这行代码的含义。 s->req_id ...; s 是一个指针,它指向一个结构或类。req_id 是该结构或类的一个成员变量。这行代码的意思是ÿ…...
Unity中的异步编程【7】——在一个异步方法里播放了animation动画,取消任务时,如何停止动画播放
用一个异步方法来播放一个动画,正常情况是:动画播放结束时,异步方法宣告结束。那如果我提前取消这个异步任务,那在这个异步方法里面,我要怎么停止播放呢?! 一、播放animation动画的异步实现 1…...
vue3中ref和reactive联系与区别以及如何选择
vue3中ref和reactive区别与联系 区别 1、ref既可定义基本数据类型,也可以定义引用数据类型,reactive只能定义应用数据类型 2、ref在js中取响应值需要使用 .value,而reactive则直接取用既可 3、ref定义的对象通过.value重新分配新对象时依旧…...
面试宝典之spring框架常见面试题
F1、类的反射机制有啥用? (1)增加程序的灵活性,可扩展性,动态创建对象。 (2)框架必备,任何框架的封装都要用反射。(框架的灵魂) F2、获取Class对象的三种方…...
建筑垃圾处理行业分析:正在被越来越广泛的运用
建筑垃圾处理,是将固体废弃物作为再生资源重新利用的一种方式。建筑垃圾是在对建筑物实施新建、改建、扩建或者是拆除过程中产生的固体废弃物。建筑垃圾一般可分为建设废物、拆除垃圾及装修垃圾。因此建筑垃圾处理行业可以分为建设废物处理、拆除垃圾处理、装修垃圾…...
【DIY summaries on Linux】
DIY Linux summaries 1) difference between ways of creation file and edit files1.1) echoecho talk to yourself touch 1) difference between ways of creation file and edit files 1.1) echo ###) > echo talk to yourself touch...
Redis(概述、应用场景、线程模式、数据持久化、数据一致、事务、集群、哨兵、key过期策略、缓存穿透、击穿、雪崩)
目录 Redis概述 应用场景 Redis的线程模式 数据持久化 1.Rdb(Redis DataBase) 2.Aof(Append Only File) mysql与redis保持数据一致 redis事务 主从复制(Redis集群) 哨兵模式 key过期策略 缓存穿透、击穿、…...
ospf-gre隧道小练习
全网可达,R5路由表没有其他路由器的路由条目 注:每个路由器都添加了自己的环回,如R1就是1.1.1.1 R1可以分别ping通与R2,R3,R4之间的隧道 R1路由表上有所有路由器环回的路由条目 R5路由表上没有其他路由器的路由条目 实现代码: 首先将各个接口IP配好 边上3个路由器:[R6][R7][R…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
