Vue鼠标框选生成坐标组件
最近工作中遇到一个需求,需要在一个图片上,手动框选一些区域,然后生成相对于图片区域的坐标。于是想到之前用到过的一个裁剪图片的插件
vue-cropper
,一样是框选图片区域,于是学习了一下它的源码,并在此基础上自己实现了一个框选图片区域生成坐标的组件。实现功能:
- 鼠标按下拖拽生成框选,不限制个数
- 可调整框选大小
- 可移动框选位置
- 可缩放
- 可单独控制每个框选是否可以编辑
在实现功能之前我们要知道一些属性的区别:
文章图片
clientX
、clientY
表示鼠标相对于当前窗口的坐标,所以我们每次创建框选/改变框选大小/移动框选之前,都要先记录一下当时的clientX,clientY,然后在移动鼠标时用现在的clientX,clientY和之前记录的去对比,计算出鼠标移动的距离,以此来改变框选的宽度和位置,下面代码中的fw
,fh
就是用来记录这个的。【Vue鼠标框选生成坐标组件】
offsetX
、offsetY
是鼠标相对于绑定事件的那个元素,在这个组件中,绑定事件的是最外层的div元素,所以用这两个值,在创建框的时候来确定框选左上角的位置。创建框选的步骤:
- 按下鼠标,触发mousedown事件,通过offsetX、offsetY来确定框选左上角在组件内的位置并记录,绑定mousemove,mouseup事件。
- 移动鼠标调整框选大小,触发mousemove事件,计算出新框选的左上角坐标和宽高。
- 鼠标抬起,触发mouseup事件,移除刚刚绑定的mousemove,mouseup事件。
cropX
、cropY
、cropW
、cropH
来记录框选的左上角坐标以及宽高,并有四个对应的old属性
来记录旧坐标,记录旧坐标的目的是为了计算新坐标,栗子:文章图片
我们将框选拖大,如上图,那么新框选的左上角没变
cropW(新框选长度) = oldCropW + fw
cropH(新框选高度) = oldCrop + fh
。再举个栗子,我们拖动框选右下角,把他拖到上方
文章图片
由上图所知:
cropW = fw - oldCropW
cropH = fh - oldCropH
cropX = oldCropX - cropW
cropY = oldCropY - cropH
代码如下:
文章图片
.cropper-container {
position: relative;
width: 100%;
height: 100%;
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
cursor: crosshair;
}.crop-box,
.cropper-face {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
user-select: none;
box-sizing: border-box;
}.crop-box {
border: 1px solid #39f;
}.cropper-face {
top: 0;
left: 0;
cursor: move;
}.crop-line {
position: absolute;
display: block;
width: 100%;
height: 100%;
}.line-top {
top: -3px;
left: 0;
height: 5px;
cursor: row-resize;
}.line-left {
top: 0;
left: -3px;
width: 5px;
cursor: col-resize;
}.line-bottom {
bottom: -3px;
left: 0;
height: 5px;
cursor: row-resize;
}.line-right {
top: 0;
right: -3px;
width: 5px;
cursor: col-resize;
}.crop-point {
position: absolute;
width: 7px;
height: 7px;
opacity: .75;
background-color: #39f;
border-radius: 100%;
}.point1 {
top: -4px;
left: -4px;
cursor: nwse-resize;
}.point2 {
top: -4px;
left: 50%;
transform: translateX(-50%);
cursor: row-resize;
}.point3 {
top: -4px;
right: -4px;
cursor: nesw-resize;
}.point4 {
top: 50%;
right: -4px;
transform: translateY(-50%);
cursor: col-resize;
}.point5 {
bottom: -4px;
right: -4px;
cursor: nwse-resize;
}.point6 {
bottom: -4px;
left: 50%;
transform: translateX(-50%);
cursor: row-resize;
}.point7 {
bottom: -4px;
left: -4px;
cursor: nesw-resize;
}.point8 {
top: 50%;
left: -4px;
transform: translateY(-50%);
cursor: col-resize;
}
结尾
我是周小羊,一个前端萌新,写文章是为了记录自己日常工作遇到的问题和学习的内容,提升自己,如果您觉得本文对你有用的话,麻烦点个赞鼓励一下哟~
推荐阅读
- vue input 验证输入内容为小数点后两位
- Vue3.0新版API之composition-api入坑指南
- Vue3|Vue3 任务调度器 scheduler 源码分析
- vue3实现抽奖模板设置
- Vue自定义表格组件(测试版)
- 【官方推荐】Laravel7|【官方推荐】Laravel7 + Vue2.0前后端分离框架通用后台源码
- Vue|Vue 源码解读(12)—— patch
- VuePress|VuePress 博客之 SEO 优化(二)之重定向
- vue-slot理解
- petite-vue源码剖析-属性绑定`v-bind`的工作原理