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

Vue.js实现父子级复选框联动选中逻辑的方法

Vue 父子复选框联动实现方案

实现逻辑

你需要实现的联动规则可以通过两个监听方法完成,核心逻辑围绕选中ID集合selectedMenu的增删操作:

  1. 父级选中时,批量添加所有子级ID到选中集合;父级取消时,批量移除所有子级和自身ID
  2. 子级操作时,统计当前父级下所有子级的选中状态:有任意子级选中就保留父级ID,全不选就移除父级ID

完整代码示例

首先是template部分,你原有的代码基本不用改,补充了可选的半选状态展示,符合常规交互习惯:

<div
  class="menu-padding padding-top"
  v-for="(data, index) in getAllMenu"
  :key="index"
>
  <input
    type="checkbox"
    v-model="selectedMenu"
    :value="data.id"
    @change="select(data)"
    :indeterminate="isIndeterminate(data)"
  />
  <label>{{ data.menu_name }}</label>
  <div
    class="padding-left"
    v-if="data.child.length > 0"
  >
    <div
      v-for="(data_child, childIndex) in data.child"
      :key="childIndex"
    >
      <input
        type="checkbox"
        v-model="selectedMenu"
        :value="data_child.id"
        @change="selectChild(data)"
      />
      <label>{{ data_child.menu_name }} {{ data_child.id }}</label>
    </div>
  </div>
</div>

然后是script部分的逻辑(Vue2/Vue3选项式API通用):

export default {
  data() {
    return {
      // 你的菜单原始数据
      getAllMenu: [
        {
          "id": 266,
          "parent_id": 0,
          "menu_name": "Server && DB Info",
          "menu_url": "#",
          "menu_icon": "fa fa-database",
          "order_by": 6,
          "has_child": 1,
          "child": [
            {
              "id": 269,
              "parent_id": 266,
              "menu_name": "Client",
              "menu_url": "/server_and_db_info/client",
              "menu_icon": null,
              "order_by": 7,
              "has_child": 0,
              "child": []
            },
            {
              "id": 268,
              "parent_id": 266,
              "menu_name": "VPN",
              "menu_url": "/server_and_db_info/vpn",
              "menu_icon": null,
              "order_by": 8,
              "has_child": 0,
              "child": []
            },
            {
              "id": 262,
              "parent_id": 266,
              "menu_name": "Server",
              "menu_url": "/server_and_db_info/server",
              "menu_icon": "",
              "order_by": 9,
              "has_child": 0,
              "child": []
            },
            {
              "id": 267,
              "parent_id": 266,
              "menu_name": "Database",
              "menu_url": "/server_and_db_info/database",
              "menu_icon": null,
              "order_by": 10,
              "has_child": 0,
              "child": []
            },
            {
              "id": 271,
              "parent_id": 266,
              "menu_name": "Domain",
              "menu_url": "/server_and_db_info/domain",
              "menu_icon": null,
              "order_by": 15,
              "has_child": 0,
              "child": []
            }
          ]
        }
      ],
      // 存储选中的菜单ID集合
      selectedMenu: []
    }
  },
  methods: {
    // 父级复选框change事件
    select(parentData) {
      const parentId = parentData.id
      const childIds = parentData.child.map(item => item.id)
      // 判断父级是否被选中
      const isParentChecked = this.selectedMenu.includes(parentId)
      if (isParentChecked) {
        // 父级选中:添加所有子级ID,自动去重
        this.selectedMenu = [...new Set([...this.selectedMenu, ...childIds])]
      } else {
        // 父级取消:移除父级和所有子级ID
        this.selectedMenu = this.selectedMenu.filter(id => id !== parentId && !childIds.includes(id))
      }
    },
    // 子级复选框change事件
    selectChild(parentData) {
      const parentId = parentData.id
      const childIds = parentData.child.map(item => item.id)
      // 统计当前父级下已选中的子级数量
      const checkedChildCount = childIds.filter(id => this.selectedMenu.includes(id)).length
      if (checkedChildCount > 0) {
        // 有子级选中:如果父级未选中则添加
        if (!this.selectedMenu.includes(parentId)) {
          this.selectedMenu.push(parentId)
        }
      } else {
        // 无子级选中:移除父级ID
        this.selectedMenu = this.selectedMenu.filter(id => id !== parentId)
      }
    },
    // 可选:判断父级是否处于半选状态
    isIndeterminate(parentData) {
      const childIds = parentData.child.map(item => item.id)
      const checkedChildCount = childIds.filter(id => this.selectedMenu.includes(id)).length
      return checkedChildCount > 0 && checkedChildCount < childIds.length
    }
  }
}

注意事项

  • 所有操作都基于数组selectedMenu的增删,v-model会自动同步复选框的选中状态
  • 半选状态不需要可以直接删除indeterminate相关的属性和方法,不影响核心联动逻辑
  • 代码支持多组父子菜单同时生效,只要getAllMenu里存在多个父级节点,逻辑会自动适配

内容的提问来源于stack exchange,提问作者alprazolam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:48:02