Vuetify如何创建支持父项全选的嵌套多选框
实现Vuetify多选框父项选中自动勾选所有子项
我明白你想要实现的功能啦——点击父分组(比如Europe)的复选框时,自动选中它下面的所有子国家,对吧?刚好Vuetify可以通过两种方式实现这个需求,我给你详细说说:
方案一:基于v-select自定义模板实现(保留下拉选择样式)
如果你想继续使用v-select的下拉样式,我们可以自定义模板把分组标题改成可点击的复选框,再通过逻辑处理子项的选中状态。
1. 调整数据结构
首先把你的countries数组改成包含分组和子项的结构:
data() { return { selectedCountries: [], // 存储选中的项 countries: [ { header: 'Europe', value: 'europe', items: [ { text: 'Germany', value: 'germany' }, { text: 'France', value: 'france' }, { text: 'Italy', value: 'italy' } ] }, { header: 'Asia', value: 'asia', items: [ { text: 'China', value: 'china' }, { text: 'Japan', value: 'japan' } ] } ] } }
2. 编写v-select组件代码
通过自定义item插槽把分组标题替换成复选框,同时处理选中逻辑:
<v-select label="Choose your Countries" v-model="selectedCountries" multiple chips return-object > <!-- 自定义下拉列表项 --> <template v-slot:item="{ item, on, attrs }"> <!-- 分组头部的复选框 --> <div v-if="item.header" class="d-flex align-center pa-2"> <v-checkbox :value="item.value" :input-value="isGroupSelected(item)" @change="toggleGroup(item)" class="mr-2" ></v-checkbox> <span class="font-weight-medium">{{ item.header }}</span> </div> <!-- 子项的普通列表项 --> <v-list-item v-else v-bind="attrs" v-on="on" > <v-list-item-title>{{ item.text }}</v-list-item-title> </v-list-item> </template> <!-- 自定义选中后的芯片显示(可选) --> <template v-slot:selection="{ item, index }"> <v-chip small :key="index"> {{ item.text || item.header }} <v-icon small @click="removeItem(item)">mdi-close</v-icon> </v-chip> </template> </v-select>
3. 添加处理方法
在methods里实现分组选中/取消的逻辑:
methods: { // 判断当前分组是否已全选 isGroupSelected(group) { return group.items.every(country => this.selectedCountries.includes(country.value)) }, // 切换分组的选中状态:全选/取消全选子项 toggleGroup(group) { const allSelected = this.isGroupSelected(group) const groupValues = group.items.map(item => item.value) if (allSelected) { // 取消分组下所有子项 this.selectedCountries = this.selectedCountries.filter(val => !groupValues.includes(val)) } else { // 添加分组下所有子项(去重避免重复添加) this.selectedCountries = [...new Set([...this.selectedCountries, ...groupValues])] } }, // 移除单个选中项时的处理 removeItem(item) { this.selectedCountries = this.selectedCountries.filter(val => val !== (item.value || item)) } }
方案二:使用v-treeview组件(更简洁的树形多选)
如果你不需要下拉样式,Vuetify的v-treeview原生支持树形多选,并且自带父项选中子项全选、子项部分选中父项半选的功能,实现起来更省心:
1. 调整树形数据结构
data() { return { selectedCountries: [], // 存储选中的节点对象 treeCountries: [ { id: 'europe', name: 'Europe', children: [ { id: 'germany', name: 'Germany' }, { id: 'france', name: 'France' }, { id: 'italy', name: 'Italy' } ] }, { id: 'asia', name: 'Asia', children: [ { id: 'china', name: 'China' }, { id: 'japan', name: 'Japan' } ] } ] } }
2. 编写v-treeview组件代码
只需要几行代码就能实现你要的功能:
<v-card> <v-card-title>Choose your Countries</v-card-title> <v-card-text> <v-treeview v-model="selectedCountries" :items="treeCountries" selectable return-object activatable open-on-click class="pa-2" > <template v-slot:label="{ item }"> {{ item.name }} </template> </v-treeview> </v-card-text> </v-card>
这个组件会自动处理:
- 选中父节点时,所有子节点自动选中
- 取消父节点时,所有子节点自动取消
- 子节点部分选中时,父节点显示半选状态
内容的提问来源于stack exchange,提问作者ToddT
相关产品推荐
相关产品推荐

