element select默认选中_element-ui checkbox 组件的树形联动

前言

示例版本为 Element-ui 2.13.0 + Vue 2.6.11

最近想弄 Element-ui checkbox 的多级联动,网上相关的例子大多数为二级联动,自己研究了一下,弄了一个树形菜单的多级联动,常用于角色管理等业务。(仅供参考,未考虑性能问题)

数据模型

[
    {
      "menu": { 
        "id":14, 
        "menuName":"测试管理',
         "parentId":0
      } ,
      "menuOptionsList":[
            {
                "id":46,
                "optionsName":"列表",
                "checked":false
            },
            {
                "id":47,
                "optionsName":"新增",
                "checked":false
            }
        ],        
        "children":[],
        "checked":false
    }
]

这里展示的最顶级的数据结构,下级数据只需要在 children 中添加即可。需要注意的是 checked 属性,本身数据库表中没有这个数据,需要后台建立一个 VO 映射实体将 checked 字段添加进去,默认值为 false.

逻辑处理

html 使用 el-table + el-chekbox 展示:

292c2bcb4abb6dcd98992ffa9c771ef9.png
<el-table
      :data="menuList"
      border
      fit
      size="mini"
      highlight-current-row
      row-key="menu.id"
      :default-expand-all="true"
      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
     >
       <el-table-column label="菜单名称" width="180">
         <template slot-scope="scope">
            <el-checkbox 
                v-model="scope.row.checked" 
                :indeterminate="scope.row.indeterminate" 
                @change="handleCheckAllChange(scope.row, $event)">
                {{ scope.row.menu.menuName }}
            </el-checkbox>
          </template>
        </el-table-column>
        <el-table-column label="功能选项">
          <template v-if="scope.row.children.length === 0" slot-scope="scope">
           <el-checkbox
             v-for="options in scope.row.menuOptionsList"
             :key="options.id"
             v-model="options.checked"
             :label="options.optionsName"
             @change="handleCheckChange(scope.row)"
           />
          </template>
       </el-table-column>
     </el-table>

核心方法 handleCheckAllChangehandleCheckChange 这两个方法,handleCheckAllChange菜单选项 列按钮被点击的事件,handleCheckChange选项列表 列被点击的事件。

handleCheckAllChange(菜单列改变事件)

handleCheckAllChange(val, checked) {
      // 有下级去处理下级
      if (val.children.length > 0) {
        // 递归设置子级选中状态
        this.findChildren(val.children, checked)
      } else {
        // 无下级处理本级
        val.menuOptionsList.forEach(options => { options.checked = checked })
      }
      // 处理上级
      if (val.menu.parentId !== 0) {
        递归设置上级选中状态
        this.findParent(this.menuList, val.menu.parentId)
      }
      // 设置全选的未全部选中的状态
      val.indeterminate = false
}

根据数据中 children 的长度来判断是否存在下级,如果存在就执行递归方法 findChildren 将子类的 checked 属性设置为 true,不存在处理本级的 checked 属性即可。需要注意的是 parentId 等于 0 证明当前菜单父级为顶级菜单,不需要再向上寻找。以此为判断依据来进行父级菜单的判断条件。 如果 parentId 不等于 0 说明当前全选的菜单存在父级,需要将父级的选项框进行状态设置。

handleCheckChange(选项列改变事件)

handleCheckChange(val) {
      const length = val.menuOptionsList.length
      let checkedLength = 0
      val.menuOptionsList.forEach(options => {
        if (options.checked) {
          checkedLength++
        }
      })
      val.checked = checkedLength === length
      val.indeterminate = checkedLength > 0 && checkedLength < length
      // 处理上级
      if (val.menu.parentId !== 0) {
        this.findParent(this.menuList, val.menu.parentId)
      }
}

这个方法对应着 选项列表 列选中的状态,需要对 菜单名称 列的全选状态进行控制。首先通过变量 length 获取到当前数据行选项列表的数量,遍历选项数组根据 checked 的状态获取到已选中的选项数量。val.checked 代表当前列是否全选,val.indeterminate 代表当前列是否有选项被选中。但是这只是处理了当前行的状态,当前行可能是某一菜单的子集,所以需要由下向上的去寻找菜单的父级并设置选中状态。这里同样用到了上面方法中的 findParent 函数。

findChildren(递归查询子集)

findChildren(list, checked) {
  list.forEach(children => {
    children.checked = checked
    children.indeterminate = false
    children.menuOptionsList.forEach(options => {
      options.checked = checked
      if (children.children.length > 0) {
        this.findChildren(children.children, checked)
      }
    })
  })
}

findParent(递归查询父集)

findParent(list, parentId) {
  list.forEach(result => {
    let parentCheckedLength = 0
    let parentIndeterminateLength = 0
    if (result.menu.id === parentId) {
      result.children.forEach(children => {
        if (children.indeterminate) {
          parentIndeterminateLength++
        } else if (children.checked) {
          parentCheckedLength++
        }
      })
      result.checked = parentCheckedLength === result.children.length
      result.indeterminate = (parentIndeterminateLength > 0 || parentCheckedLength > 0) && parentCheckedLength < result.children.length
      if (result.menu.parentId !== 0) {
        this.findParent(this.menuList, result.menu.parentId)
      }
    } else if (result.children.length > 0) {
      this.findParent(result.children, parentId)
    }
  })
}

完整示例

由于源码篇幅过长,暂时将源码放到 GitHub 了,希望可以帮助到你。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在基于 Element-UI树形选择器添加横向滚动条,可以通过以下步骤实现: 1. 给树形选择器的样式加上 `overflow-x: auto` 属性,以实现横向滚动条的显示。 2. 为树形选择器的节点(即 `<el-tree>` 组件)设置一个固定宽度,以便能够在超出容器宽度时触发横向滚动条的显示。 3. 给树形选择器的每个节点(即 `<el-tree-node>` 组件)设置一个合适的宽度,以保证节点在不同层级之间的对齐。 下面是一个示例代码: ```html <template> <el-tree :data="treeData" show-checkbox :node-key="id" :props="defaultProps" class="horizontal-scroll"> <!-- 自定义节点内容 --> <span class="custom-node" slot-scope="{ node }">{{ node.label }}</span> </el-tree> </template> <script> export default { data() { return { treeData: [ { id: 1, label: 'Node 1', children: [ { id: 11, label: 'Node 1-1' }, { id: 12, label: 'Node 1-2' }, { id: 13, label: 'Node 1-3' } ] }, { id: 2, label: 'Node 2', children: [ { id: 21, label: 'Node 2-1' }, { id: 22, label: 'Node 2-2' }, { id: 23, label: 'Node 2-3' }, { id: 24, label: 'Node 2-4' } ] } ], defaultProps: { children: 'children', label: 'label' } } } } </script> <style> .horizontal-scroll { overflow-x: auto; } .el-tree { width: 800px; /* 根据实际需求设置宽度 */ } .el-tree-node { width: 200px; /* 根据实际需求设置宽度 */ } .custom-node { display: inline-block; /* 让节点内容横向排列 */ } </style> ``` 在上面的例子,我们给树形选择器添加了一个 `horizontal-scroll` 类名,并为其设置了 `overflow-x: auto` 属性。然后,我们为树形选择器和树形选择器节点设置固定宽度,并为节点设置了合适的宽度,以保证节点在不同层级之间的对齐。最后,我们使用 `display: inline-block` 让节点内容横向排列。这样就能够在树形选择器超出容器宽度时触发横向滚动条的显示了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值