vue实现鼠标拖动多选
Vue 实现鼠标拖动多选框
基本思路
通过监听鼠标事件(mousedown、mousemove、mouseup)实现拖动选区,结合动态计算选中元素的范围完成多选功能。核心是记录起始位置和当前鼠标位置,生成选区矩形。
核心代码实现
模板部分
<template>
<div
class="container"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
>
<!-- 可选元素列表 -->
<div
v-for="(item, index) in items"
:key="index"
class="selectable-item"
:class="{ 'selected': selectedItems.includes(index) }"
:style="getItemStyle(index)"
>
{{ item }}
</div>
<!-- 拖拽选区框 -->
<div
v-if="isSelecting"
class="selection-box"
:style="selectionBoxStyle"
/>
</div>
</template>
脚本部分
<script>
export default {
data() {
return {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'],
selectedItems: [],
isSelecting: 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: {
handleMouseDown(e) {
this.isSelecting = true
this.startPos = { x: e.clientX, y: e.clientY }
this.currentPos = { x: e.clientX, y: e.clientY }
this.selectedItems = [] // 开始新选择时清空已选
},
handleMouseMove(e) {
if (!this.isSelecting) return
this.currentPos = { x: e.clientX, y: e.clientY }
this.updateSelectedItems()
},
handleMouseUp() {
this.isSelecting = false
},
getItemStyle(index) {
// 返回元素位置信息(需根据实际布局实现)
return {
position: 'absolute',
left: `${(index % 3) * 100 + 10}px`,
top: `${Math.floor(index / 3) * 100 + 10}px`
}
},
updateSelectedItems() {
const items = document.querySelectorAll('.selectable-item')
this.selectedItems = []
items.forEach((item, index) => {
const rect = item.getBoundingClientRect()
if (this.isInSelection(rect)) {
this.selectedItems.push(index)
}
})
},
isInSelection(rect) {
const selectionLeft = Math.min(this.startPos.x, this.currentPos.x)
const selectionRight = Math.max(this.startPos.x, this.currentPos.x)
const selectionTop = Math.min(this.startPos.y, this.currentPos.y)
const selectionBottom = Math.max(this.startPos.y, this.currentPos.y)
return (
rect.left < selectionRight &&
rect.right > selectionLeft &&
rect.top < selectionBottom &&
rect.bottom > selectionTop
)
}
}
}
</script>
样式部分
<style scoped>
.container {
position: relative;
width: 100%;
height: 500px;
border: 1px solid #ddd;
overflow: hidden;
}
.selectable-item {
width: 80px;
height: 80px;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.selected {
background-color: #b3d4ff;
border-color: #4a90e2;
}
.selection-box {
position: absolute;
background-color: rgba(74, 144, 226, 0.2);
border: 1px dashed #4a90e2;
pointer-events: none;
}
</style>
功能扩展建议
添加Shift键多选
handleMouseDown(e) {
if (!e.shiftKey) {
this.selectedItems = []
}
// 其余逻辑不变
}
性能优化
对于大量元素,使用虚拟滚动技术(如vue-virtual-scroller)避免全量DOM检测。
边界处理 添加对容器边界的检测,防止选区超出可视区域。







