1. 创建一个 RectSelector 组件
<template>
  <div class="rect-selector" @mousedown="startSelection" @mousemove="updateSelection" @mouseup="endSelection">
    <div class="selection-box" :style="boxStyle" v-show="showBox"></div>
    <slot></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

export default defineComponent({
  setup() {
    const startX = ref(0);
    const startY = ref(0);
    const endX = ref(0);
    const endY = ref(0);
    const showBox = ref(false);

    const startSelection = (e: MouseEvent) => {
      startX.value = e.clientX;
      startY.value = e.clientY;
      endX.value = e.clientX;
      endY.value = e.clientY;
      showBox.value = true;
    };

    const updateSelection = (e: MouseEvent) => {
      if (!showBox.value) return;
      endX.value = e.clientX;
      endY.value = e.clientY;
    };

    const endSelection = () => {
      showBox.value = false;
    };

    const boxStyle = {
      left: Math.min(startX.value, endX.value) + "px",
      top: Math.min(startY.value, endY.value) + "px",
      width: Math.abs(endX.value - startX.value) + "px",
      height: Math.abs(endY.value - startY.value) + "px",
    };

    return { startSelection, updateSelection, endSelection, showBox, boxStyle };
  },
});
</script>

<style scoped>
.rect-selector {
  position: relative;
}

.selection-box {
  position: absolute;
  border: 2px dashed #f00;
  background-color: rgba(255, 0, 0, 0.2);
  pointer-events: none;
}
</style>
  1. 在需要使用鼠标框选效果的组件中引入 RectSelector 组件
<template>
  <div class="container">
    <rect-selector>
      <div class="item" v-for="item in items" :key="item.id">
        {{ item.text }}
      </div>
    </rect-selector>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import RectSelector from "@/components/RectSelector.vue";

export default defineComponent({
  components: {
    RectSelector,
  },
  setup() {
    const items = ref([
      { id: 1, text: "Item 1" },
      { id: 2, text: "Item 2" },
      { id: 3, text: "Item 3" },
      { id: 4, text: "Item 4" },
      { id: 5, text: "Item 5" },
    ]);

    return { items };
  },
});
</script>

<style scoped>
.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.item {
  width: 100px;
  height: 100px;
  border: 1px solid #000;
  margin: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>
  1. 在鼠标框选过程中,根据选中的元素进行处理
<template>
  <div class="container">
    <rect-selector>
      <div
        class="item"
        v-for="item in items"
        :key="item.id"
        :class="{ selected: item.selected }"
        @mousedown="selectItem(item)"
      >
        {{ item.text }}
      </div>
    </rect-selector>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import RectSelector from "@/components/RectSelector.vue";

interface Item {
  id: number;
  text: string;
  selected: boolean;
}

export default defineComponent({
  components: {
    RectSelector,
  },
  setup() {
    const items = ref<Item[]>([
      { id: 1, text: "Item 1", selected: false },
      { id: 2, text: "Item 2", selected: false },
      { id: 3, text: "Item 3", selected: false },
      { id: 4, text: "Item 4", selected: false },
      { id: 5, text: "Item 5", selected: false },
    ]);

    const selectItem = (item: Item) => {
      item.selected = true;
    };

    const deselectAll = () => {
      items.value.forEach((item) => (item.selected = false));
    };

    const updateSelection = (e: MouseEvent) => {
      if (!showBox.value) return;
      endX.value = e.clientX;
      endY.value = e.clientY;
      items.value.forEach((item) => {
        const rect = item.$el.getBoundingClientRect();
        const isIntersect =
          Math.min(startX.value, endX.value) <= rect.right &&
          Math.max(startX.value, endX.value) >= rect.left &&
          Math.min(startY.value, endY.value) <= rect.bottom &&
          Math.max(startY.value, endY.value) >= rect.top;
        item.selected = isIntersect;
      });
    };

    const endSelection = () => {
      showBox.value = false;
      deselectAll();
    };

    return { items, selectItem, updateSelection, endSelection };
  },
});
</script>

<style scoped>
.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.item {
  width: 100px;
  height: 100px;
  border: 1px solid #000;
  margin: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.selected {
  background-color: #f00;
}
</style>
``
vue3 Typescript实现鼠标框选div效果

原文地址: https://www.cveoy.top/t/topic/ewUy 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录