vue实现按住鼠标多选
实现思路
在Vue中实现按住鼠标多选功能,核心逻辑是监听鼠标按下、移动和抬起事件,通过状态管理记录选中项。需要结合事件修饰符和动态样式控制。
基础实现步骤
模板部分
<template>
<div
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
>
<div
v-for="(item, index) in items"
:key="index"
:class="{ 'selected': selectedItems.includes(index) }"
class="selectable-item"
>
{{ item }}
</div>
</div>
</template>
脚本部分
<script>
export default {
data() {
return {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4'],
selectedItems: [],
isSelecting: false
}
},
methods: {
handleMouseDown() {
this.isSelecting = true
},
handleMouseMove(e) {
if (!this.isSelecting) return
const target = e.target.closest('.selectable-item')
if (!target) return
const index = [...target.parentNode.children].indexOf(target)
if (!this.selectedItems.includes(index)) {
this.selectedItems.push(index)
}
},
handleMouseUp() {
this.isSelecting = false
}
}
}
</script>
样式部分
<style>
.selectable-item {
padding: 8px;
margin: 4px;
border: 1px solid #ddd;
cursor: pointer;
}
.selectable-item.selected {
background-color: #42b983;
color: white;
}
</style>
高级优化方案
添加Shift键多选支持
handleMouseDown(e) {
this.isSelecting = true
if (e.shiftKey && this.selectedItems.length > 0) {
const target = e.target.closest('.selectable-item')
const lastSelected = this.selectedItems[this.selectedItems.length - 1]
const currentIndex = [...target.parentNode.children].indexOf(target)
const start = Math.min(lastSelected, currentIndex)
const end = Math.max(lastSelected, currentIndex)
for (let i = start; i <= end; i++) {
if (!this.selectedItems.includes(i)) {
this.selectedItems.push(i)
}
}
}
}
性能优化 使用Set代替数组存储选中项,优化查找性能:
data() {
return {
selectedItems: new Set()
}
},
methods: {
handleMouseMove(e) {
// ...
if (!this.selectedItems.has(index)) {
this.selectedItems.add(index)
}
}
}
完整组件示例
<template>
<div class="multi-select-container">
<div
v-for="(item, index) in items"
:key="index"
:class="{ 'selected': selectedItems.has(index) }"
class="selectable-item"
@mousedown="handleMouseDown($event, index)"
@mouseenter="handleMouseEnter(index)"
>
{{ item }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`),
selectedItems: new Set(),
isSelecting: false,
lastSelected: null
}
},
methods: {
handleMouseDown(e, index) {
this.isSelecting = true
if (e.shiftKey && this.lastSelected !== null) {
const start = Math.min(this.lastSelected, index)
const end = Math.max(this.lastSelected, index)
for (let i = start; i <= end; i++) {
this.selectedItems.add(i)
}
} else {
if (e.ctrlKey || e.metaKey) {
if (this.selectedItems.has(index)) {
this.selectedItems.delete(index)
} else {
this.selectedItems.add(index)
}
} else {
this.selectedItems.clear()
this.selectedItems.add(index)
}
}
this.lastSelected = index
},
handleMouseEnter(index) {
if (this.isSelecting) {
this.selectedItems.add(index)
this.lastSelected = index
}
},
handleMouseUp() {
this.isSelecting = false
}
},
mounted() {
window.addEventListener('mouseup', this.handleMouseUp)
},
beforeDestroy() {
window.removeEventListener('mouseup', this.handleMouseUp)
}
}
</script>
注意事项
- 事件委托性能优于单独监听每个元素
- 移动端需要额外处理touch事件
- 大量数据时需要虚拟滚动优化
- 选中状态建议使用CSS变量实现主题定制
- 可结合Vuex管理全局选中状态
以上实现方案可根据实际需求调整选择策略和交互细节,核心逻辑是通过鼠标事件和状态管理实现多选功能。







