vue实现点选多选
Vue 实现点选多选功能
基础实现(基于数组存储选中项)
使用 v-model 绑定到数组实现多选,适用于复选框组场景:
<template>
<div>
<div v-for="item in items" :key="item.id">
<input
type="checkbox"
:id="item.id"
:value="item.value"
v-model="selectedItems"
>
<label :for="item.id">{{ item.label }}</label>
</div>
<p>已选择:{{ selectedItems }}</p>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, value: 'apple', label: '苹果' },
{ id: 2, value: 'banana', label: '香蕉' },
{ id: 3, value: 'orange', label: '橙子' }
],
selectedItems: []
}
}
}
</script>
对象存储方案(带状态管理)
当需要记录更复杂的选中状态时,可以使用对象存储:
<template>
<div>
<div
v-for="item in items"
:key="item.id"
@click="toggleSelect(item.id)"
:class="{ 'active': selectedItems[item.id] }"
>
{{ item.label }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 101, label: '选项A' },
{ id: 102, label: '选项B' },
{ id: 103, label: '选项C' }
],
selectedItems: {}
}
},
methods: {
toggleSelect(id) {
this.$set(this.selectedItems, id, !this.selectedItems[id])
}
}
}
</script>
<style>
.active {
background-color: #42b983;
color: white;
}
</style>
列表项组件化实现
封装可复用的多选列表组件:
<template>
<selectable-list :items="dataList" v-model="selectedIds"/>
</template>
<script>
import SelectableList from './SelectableList.vue'
export default {
components: { SelectableList },
data() {
return {
dataList: [
{ id: 'x1', text: '项目1' },
{ id: 'x2', text: '项目2' }
],
selectedIds: []
}
}
}
</script>
SelectableList.vue 组件实现:
<template>
<ul>
<li
v-for="item in items"
:key="item.id"
@click="handleClick(item.id)"
:class="{ selected: isSelected(item.id) }"
>
{{ item.text }}
</li>
</ul>
</template>
<script>
export default {
props: {
items: Array,
value: Array
},
methods: {
handleClick(id) {
const newSelection = [...this.value]
const index = newSelection.indexOf(id)
index === -1
? newSelection.push(id)
: newSelection.splice(index, 1)
this.$emit('input', newSelection)
},
isSelected(id) {
return this.value.includes(id)
}
}
}
</script>
高级功能扩展
实现全选/反选和批量操作:
<template>
<div>
<button @click="toggleAll">{{ allSelected ? '取消全选' : '全选' }}</button>
<ul>
<li
v-for="item in listData"
:key="item.id"
@click="toggleItem(item.id)"
:class="{ active: selected.has(item.id) }"
>
{{ item.name }}
</li>
</ul>
<button @click="batchDelete" :disabled="selected.size === 0">
删除选中项 ({{ selected.size }})
</button>
</div>
</template>
<script>
export default {
data() {
return {
listData: [
{ id: 1, name: '条目1' },
{ id: 2, name: '条目2' }
],
selected: new Set()
}
},
computed: {
allSelected() {
return this.selected.size === this.listData.length
}
},
methods: {
toggleItem(id) {
this.selected.has(id)
? this.selected.delete(id)
: this.selected.add(id)
},
toggleAll() {
this.allSelected
? this.selected.clear()
: this.listData.forEach(item => this.selected.add(item.id))
},
batchDelete() {
this.listData = this.listData.filter(item => !this.selected.has(item.id))
this.selected.clear()
}
}
}
</script>
性能优化建议
对于大型列表(超过 1000 项),建议采用虚拟滚动方案:
<template>
<virtual-list
:size="50"
:remain="20"
:items="largeData"
v-slot="{ item }"
>
<div
class="item"
:class="{ selected: selectedMap[item.id] }"
@click="selectItem(item.id)"
>
{{ item.content }}
</div>
</virtual-list>
</template>
<script>
import VirtualList from 'vue-virtual-scroll-list'
export default {
components: { VirtualList },
data() {
return {
largeData: generateLargeData(), // 假设有生成大数据的方法
selectedMap: {}
}
},
methods: {
selectItem(id) {
this.$set(this.selectedMap, id, !this.selectedMap[id])
}
}
}
</script>
关键实现要点
- 数组方案适合简单场景,对象/Set 方案适合需要快速查找的场景
- 使用
$set确保响应式更新 - 大型列表应考虑虚拟滚动技术
- 组件化设计时通过
v-model实现双向绑定 - 使用计算属性优化全选状态的判断







