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>
相关推荐
Huazzi.17 分钟前
免费好用的静态网页托管平台全面对比介绍
前端·网络·github·web
吃土少女古拉拉25 分钟前
前端和后端
前端·学习笔记
夫琅禾费米线30 分钟前
leetcode2650. 设计可取消函数 generator和Promise
开发语言·javascript·leetcode·ecmascript
寒雒1 小时前
【Python】实战:实现GUI登录界面
开发语言·前端·python
独上归州1 小时前
Vue与React的Suspense组件对比
前端·vue.js·react.js·suspense
战族狼魂2 小时前
html+js实现图片的放大缩小等比缩放翻转,自动播放切换,顺逆时针旋转
javascript·css·html
Komorebi⁼2 小时前
Vue核心特性解析(内含实践项目:设置购物车)
前端·javascript·vue.js·html·html5
明月清风徐徐2 小时前
Vue实训---0-完成Vue开发环境的搭建
前端·javascript·vue.js
SameX2 小时前
HarmonyOS Next 企业数据备份与恢复策略
前端·harmonyos
SameX2 小时前
HarmonyOS Next 企业数据传输安全策略
前端·harmonyos