在一些项目中,可能会需要对一些内容模块通过框选随时进行一个标记,以下实现了在页面中通过鼠标拖动进行椭圆的绘制(当然 如果有其他标记样式需求换个样式即可)
首先,要熟悉一下具体实现流程,当鼠标按下需要创建一个元素标签用来作为存放椭圆的容器,因为可能绘制多个椭圆,这里通过circlelist数组存放每个椭圆的信息(以便后期与后端交互永久存储,下次直接获取数据展示)
const circlelist = reactive([
{
id: 1,
width: 100,//椭圆的宽
height: 50,//椭圆的高
left: 50,//椭圆距离父元素左侧距离
top: 10,//椭圆距离父元素顶部距离
},
]);
当鼠标按下设置isdragging状态值,用来在鼠标移动时判断是否需要去绘制;获取当前鼠标的位置(offsetX:距离容器左侧的距离;offsetY:距离容器顶部的距离),用来设置椭圆在容器中的位置;设置椭圆起始宽高为0,将新建的一个椭圆信息插入到circlelist中,并且创建元素标签
const currentid = ref(1);//当前绘制的椭圆id
const onmousedowns = (e) => {
isdragging.value = true;
let { offsetX, offsetY } = e;
startX.value = offsetX;
startY.value = offsetY;
currentid.value++;
const ele = {
id: currentid.value,
width: 0,
height: 0,
left: offsetX,
top: offsetY,
status:false,
};
circlelist.push(ele);
let span = document.createElement("span");
span.id=ele.id.toString()
span.style.cssText = `position:absolute;left:${ele.left}px;top:${ele.top}px;display:inline-block;width:${ele.width}px;height:${ele.height}px;border:2px solid red;border-radius: 50%;`;
showcontainer.value?.appendChild(span);
};
当鼠标移动并且鼠标处于按下状态中,也就是isdragging值为true时,根据当前的id获取绘制的椭圆标签,计算出移动后新的椭圆宽高,位置信息对标签样式属性进行改变,以便实时获取椭圆信息
const onmousemoves = (e) => {
if (isdragging.value) {
let span = document.getElementById(currentid.value.toString());
const rect = e.currentTarget.getBoundingClientRect();
let offsetX = e.clientX - rect.left;
let offsetY = e.clientY - rect.top;
let width = Math.abs(offsetX - startX.value);
let height = Math.abs(offsetY - startY.value);
// 判断当前鼠标和起始鼠标位置,用于反向绘制
let left = startX.value > offsetX ? offsetX : startX.value;
let top = startY.value > offsetY ? offsetY : startY.value;
span.style.width = width + "px";
span.style.height = height + "px";
span.style.left = left + "px";
span.style.top = top + "px";
}
};
鼠标抬起,设置isdragging值为false,停止椭圆的绘制
完整代码:
<template>
<h1 style="text-align: center">绘制椭圆</h1>
<div
ref="showcontainer"
class="container"
@mousedown="onmousedowns($event)"
@mousemove="onmousemoves($event)"
@mouseup="onmouseups($event)"
></div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
const showcontainer = ref();
// 是否处于绘制状态
const isdragging = ref(false);
//开始绘制的起始位置
let startX = ref();
let startY = ref();
const circlelist = reactive([
{
id: 1,
width: 100, //椭圆的宽
height: 50, //椭圆的高
left: 50, //椭圆距离父元素左侧距离
top: 10, //椭圆距离父元素顶部距离
},
]);
const currentid = ref(1); //当前绘制的椭圆id
const onmousedowns = (e) => {
isdragging.value = true;
let { offsetX, offsetY } = e;
startX.value = offsetX;
startY.value = offsetY;
currentid.value++;
const ele = {
id: currentid.value,
width: 0,
height: 0,
left: offsetX,
top: offsetY,
};
circlelist.push(ele);
// 创建标签元素
let span = document.createElement("span");
span.id = ele.id.toString();
span.style.cssText = `position:absolute;left:${ele.left}px;top:${ele.top}px;display:inline-block;width:${ele.width}px;height:${ele.height}px;border:2px solid red;border-radius: 50%;`;
showcontainer.value?.appendChild(span);
};
const onmousemoves = (e) => {
if (isdragging.value) {
let span = document.getElementById(currentid.value.toString());
const rect = e.currentTarget.getBoundingClientRect();
let offsetX = e.clientX - rect.left;
let offsetY = e.clientY - rect.top;
let width = Math.abs(offsetX - startX.value);
let height = Math.abs(offsetY - startY.value);
// 判断当前鼠标和起始鼠标位置,用于反向绘制
let left = startX.value > offsetX ? offsetX : startX.value;
let top = startY.value > offsetY ? offsetY : startY.value;
span.style.width = width + "px";
span.style.height = height + "px";
span.style.left = left + "px";
span.style.top = top + "px";
}
};
const onmouseups = (e) => {
isdragging.value = false;
};
const initcircle = () => {
if (circlelist.length != 0) {
circlelist.forEach((item) => {
let span = document.createElement("span");
span.id = item.id.toString();
span.style.cssText = `position:absolute;left:${item.left}px;top:${item.top}px;display:inline-block;width:${item.width}px;height:${item.height}px;border:2px solid red;border-radius: 50%;`;
showcontainer.value?.appendChild(span);
});
}
};
onMounted(() => {
initcircle();
});
</script>
<style scoped lang="scss">
.container {
position: relative;
width: 100%;
height: 400px;
background-color: antiquewhite;
}
</style>