You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:43:45