vue3 Typescript实现鼠标框选div效果
- 创建一个
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>
- 在需要使用鼠标框选效果的组件中引入
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>
- 在鼠标框选过程中,根据选中的元素进行处理
<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>
``
原文地址: https://www.cveoy.top/t/topic/ewUy 著作权归作者所有。请勿转载和采集!