Vue3鼠标拖拽生成区域块并选中元素

Vue3鼠标拖拽生成区域块并选中元素,选中的元素则背景高亮(或者其它逻辑)。

javascript 复制代码
<script setup>
import { ref } from 'vue'

// 区域ref
const regionRef = ref(null)

// 内容ref
const itemRefs = ref(null)

// 是否开启绘画区域
const enable = ref(false)

// 鼠标开始位置
const start = ref({
  x: 0,
  y: 0
})

// 区域块元素配置
const regionConfig = ref({
  top: '0px',
  left: '0px',
  width: '0px',
  height: '0px'
})


// 鼠标点击
const onMousedown = (e) => {
  const { pageX, pageY } = e
  start.value.x = pageX
  start.value.y = pageY
  regionConfig.value.top = pageY + 'px'
  regionConfig.value.left = pageX + 'px'
  enable.value = true
}

// 鼠标弹起
const onMouseup = () => {
  enable.value = false
}

// 鼠标移动
const onMousemove = (e) => {
  if (!enable.value) return false
  const { pageX, pageY } = e

  // 当前鼠标移动的位置减开始位置得到区域块宽高
  const x = pageX - start.value.x
  const y = pageY - start.value.y

  regionConfig.value.width = Math.abs(x) + 'px'
  regionConfig.value.height = Math.abs(y) + 'px'

  // 鼠标移动的位置小于开始位置,当前鼠标的位置是区域块的位置
  if (x < 0) {
    regionConfig.value.left = pageX + 'px'
  }

  if (y < 0) {
    regionConfig.value.top = pageY + 'px'
  }

  // 获取区域块和内容的位置
  const boxRect = regionRef.value.getBoundingClientRect()

  itemRefs.value.forEach((item) => {
    const rect = item.getBoundingClientRect()

    // 判断区域块包裹内容元素则改变背景颜色
    if (boxRect.top <= rect.top && boxRect.bottom >= rect.bottom && boxRect.left <= rect.left && boxRect.right >= rect.right) {
      item.style.backgroundColor = 'rgb(10, 228, 10)'
    } else {
      item.style.backgroundColor = '#cbccce'
    }
  })
}
</script>

<template>
  <main
    class="w_h_100 home"
    @mousedown="onMousedown"
    @mouseup="onMouseup"
    @mousemove="onMousemove"
  >
    <div class="box">
      <div
        ref="itemRefs"
        class="item"
        v-for="item in 10"
        :key="item"
      >{{ item }}</div>
    </div>

    <div
      ref="regionRef"
      class="region"
      :style="regionConfig"
    ></div>
  </main>
</template>

<style lang="less">
.home {
  display: flex;
  align-items: center;
  justify-content: center;

  .box {
    width: 200px;
    display: flex;
    flex-wrap: wrap;
  }

  .item {
    margin-right: 10px;
    margin-bottom: 10px;
    width: 30px;
    height: 30px;
    color: #fff;
    text-align: center;
    line-height: 30px;
    background-color: #cbccce;
    user-select: none;
  }

  .region {
    position: fixed;
    z-index: 10;
    border: 1px solid #0094ff;
    background-color: rgba(0, 148, 255, 0.1);
  }
}
</style>
相关推荐
Andrew55113 分钟前
让 AI 写页面不再“一眼假”:我把设计品味做成了一个 Claude Code Skill 流水线
前端
乐享qicheng15 分钟前
14-AI智能管家JSBridge深度问答
前端
10年前端老司机26 分钟前
我用 Vue3 + LangGraph 做了个心理咨询 AI,踩了 9 个坑后总结出来的实战经验
前端·langchain·agent
数据掘金28 分钟前
A/B 实验分组参数回滚后还在生效?一次参数校验体系的重构复盘
前端
bmxy小明同学1 小时前
2026-10-09-token与成本
java·前端·数据库
neoooo1 小时前
🚀Claude Code 小技巧(二):找回会话,撤销修改
前端·人工智能·后端
今年下半年2 小时前
【文件上传】记录一次大附件上传的处理方案
前端·文件上传·内存溢出·分段上传
溪语流沙2 小时前
【每天一个CSS | Day21】落地页Hero动画的分镜表
前端·css
neoooo2 小时前
🚀Claude Code 小技巧(一):一键进入危险模式
前端·人工智能·后端
bmxy小明同学3 小时前
2026-10-11-幻觉治理
服务器·前端·javascript