vue实现鼠标拖动多选
实现鼠标拖动多选的核心思路
监听鼠标的mousedown、mousemove和mouseup事件,通过计算鼠标移动轨迹和位置,动态生成一个选择框。检测目标元素是否在选择框范围内,更新选中状态。
基础代码结构
<template>
<div
class="container"
@mousedown="startDrag"
@mousemove="onDrag"
@mouseup="endDrag"
>
<div
v-for="item in items"
:key="item.id"
class="selectable-item"
:class="{ selected: selectedItems.includes(item.id) }"
>
{{ item.name }}
</div>
<div
v-if="isDragging"
class="selection-box"
:style="selectionBoxStyle"
/>
</div>
</template>
数据与事件处理
<script>
export default {
data() {
return {
items: [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
// 更多项目...
],
selectedItems: [],
isDragging: false,
startPos: { x: 0, y: 0 },
currentPos: { x: 0, y: 0 }
}
},
computed: {
selectionBoxStyle() {
const left = Math.min(this.startPos.x, this.currentPos.x)
const top = Math.min(this.startPos.y, this.currentPos.y)
const width = Math.abs(this.currentPos.x - this.startPos.x)
const height = Math.abs(this.currentPos.y - this.startPos.y)
return {
left: `${left}px`,
top: `${top}px`,
width: `${width}px`,
height: `${height}px`
}
}
},
methods: {
startDrag(e) {
this.isDragging = true
this.startPos = { x: e.clientX, y: e.clientY }
this.currentPos = { x: e.clientX, y: e.clientY }
},
onDrag(e) {
if (!this.isDragging) return
this.currentPos = { x: e.clientX, y: e.clientY }
this.updateSelection()
},
endDrag() {
this.isDragging = false
}
}
}
</script>
碰撞检测实现
methods: {
updateSelection() {
const selectionBox = {
left: Math.min(this.startPos.x, this.currentPos.x),
top: Math.min(this.startPos.y, this.currentPos.y),
right: Math.max(this.startPos.x, this.currentPos.x),
bottom: Math.max(this.startPos.y, this.currentPos.y)
}
this.selectedItems = []
const items = document.querySelectorAll('.selectable-item')
items.forEach(item => {
const rect = item.getBoundingClientRect()
const isIntersecting = !(
selectionBox.right < rect.left ||
selectionBox.left > rect.right ||
selectionBox.bottom < rect.top ||
selectionBox.top > rect.bottom
)
if (isIntersecting) {
const itemId = parseInt(item.dataset.id)
this.selectedItems.push(itemId)
}
})
}
}
样式优化
<style>
.container {
position: relative;
width: 100%;
height: 100vh;
}
.selectable-item {
position: absolute;
width: 100px;
height: 100px;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
.selectable-item.selected {
background-color: rgba(0, 123, 255, 0.3);
border-color: #007bff;
}
.selection-box {
position: absolute;
background-color: rgba(0, 123, 255, 0.1);
border: 1px dashed #007bff;
pointer-events: none;
}
</style>
性能优化建议
使用事件委托减少事件监听器数量,避免在mousemove中频繁操作DOM。可以添加防抖处理减少不必要的计算。
methods: {
onDrag: _.throttle(function(e) {
if (!this.isDragging) return
this.currentPos = { x: e.clientX, y: e.clientY }
this.updateSelection()
}, 50)
}
完整组件示例
将上述代码整合为一个完整组件,确保所有功能协同工作。注意处理边界情况,如滚动容器、元素重叠等场景。







