antd树形列表

Ant Design 权限管理
本文介绍了一个基于 Ant Design 的 React 应用程序,用于管理菜单层级的查看和编辑权限。通过递归处理树状数据结构,实现了权限的逐级控制,并支持全选与反选功能。

 

 

import React, { Component } from 'react';
import { Table, Divider, Tag, Icon, Checkbox, Tree, Button } from 'antd';
class index extends Component {
  state = {
    data: [
      {
        key: "product",
        order: "1",
        title: "产品",
        data: {
          code: "product",
          enable_edt: "N",
          enable_view: "Y",
          has_edit: null,
          has_view: "N",
          name: "产品"
        },
        children: [
          {
            key: "fund_info",
            order: "2",
            title: "产品信息",
            data: {
              code: "fund_info",
              enable_edt: "N",
              enable_view: "Y",
              has_edit: null,
              has_view: "N",
              name: "产品信息"
            },
            children: [
              {
                key: "fund_base_info",
                order: "3",
                title: "基本信息",
                data: {
                  code: "fund_base_info",
                  enable_edt: "N",
                  enable_view: "Y",
                  has_edit: null,
                  has_view: "N",
                  name: "基本信息"
                },
                children: [
                  {
                    key: "field_cplx",
                    order: "4",
                    title: "产品类型",
                    data: {
                      code: "field_cplx",
                      enable_edt: "N",
                      enable_view: "Y",
                      has_edit: null,
                      has_view: "N",
                      name: "产品类型"
                    },
                    children: []
                  },
                  {
                    key: "field_cpqc",
                    order: "5",
                    title: "产品全称",
                    data: {
                      code: "field_cpqc",
                      enable_edt: "N",
                      enable_view: "Y",
                      has_edit: null,
                      has_view: "N",
                      name: "产品全称"
                    },
                    children: []
                  }
                ]
              },
              {
                key: "fund_sale_info",
                order: "26",
                title: "销售信息",
                data: {
                  code: "fund_sale_info",
                  enable_edt: "N",
                  enable_view: "Y",
                  has_edit: null,
                  has_view: "N",
                  name: "销售信息"
                },
                children: []
              }
            ]
          },
          {
            key: "fund_role_info",
            order: "97",
            title: "岗位信息",
            data: {
              code: "fund_role_info",
              enable_edt: "N",
              enable_view: "Y",
              has_edit: null,
              has_view: "N",
              name: "岗位信息"
            },
            children: []
          }
        ]
      }
    ],//数据
    columns: [], //表格columns
    permissionTableData: [],//权限树,表格数据
    editFlag: false,//是否为编辑状态
    changeData: [],//checkbox改变后得数据
    loading: true,//loading状态
    yTreeData: [],//原始树形数据
  }

  componentDidMount() {
    this.getRolePermissonTree();
  }
  //给子级添加父级Key
  addParentKeyWrapper = (tree) => {
    //深度克隆
    const data = JSON.parse(JSON.stringify(tree));
    function addParentKey(data, parentKey) {
      data.forEach(ele => {
        const { children } = ele;
        ele.data.parent_code = parentKey;
        if (children) {//如果唯一标识不是code可以自行改变
          addParentKey(children, ele.data.code)
        }
      })
    }
    addParentKey(data, null); //一开始为null,根节点没有父级
    return data;
  }
  getRolePermissonTree = () => { //项目中这里是请求接口
    this.setState({
      loading: true
    })
    let { data } = this.state; //实际上这个data是从接口来的
    let parentData = this.addParentKeyWrapper(data);//添加父级属性
    this.initData(parentData, "has_view");
    this.initData(parentData, "has_edit");
    let copyData = JSON.stringify(parentData); //备份原始数据
    let col = [
      {
        title: '菜单名称',
        dataIndex: 'data.name'
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_view',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={true}//是否仅用
                indeterminate={record['has_viewindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_edit',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={true}//是否仅用
                indeterminate={record['has_editindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      }
    ]
    this.setState({
      permissionTableData: parentData,
      loading: false,
      yTreeData: copyData,
      columns: col
    })
  }
  //初始化数据
  initData = (data, type) => {
    data.map((item) => {
      // console.log(item)
      item[type + 'indeterminate'] = false;
      if (item.children.length > 0) {
        this.initData(item.children, type)
        // console.log(item.children, "999")
        let allSelect = item.children.every((item1) => {
          return item1.data[type] == "Y" && item1[type + "indeterminate"] == false;
        })
        let someSelect = item.children.some((item1) => {
          return item1.data[type] == "Y";
        })
        if (allSelect) {
          item.data[type] = "Y"
          item[type + 'indeterminate'] = false;
        } else if (someSelect) {
          item.data[type] = "Y"
          item[type + 'indeterminate'] = true;
        } else {
          item.data[type] = "N"
          item[type + 'indeterminate'] = false;
        }
      }
    })
  }
  //根据code(唯一标识)找到其值
  getItem = (code) => {
    let { permissionTableData } = this.state;
    let value;
    let loops = (data, code) => {
      data.map((item, index) => {
        if (item.data.code == code) {
          value = item;
        }
        if (item.children.length > 0) {
          loops(item.children, code);
        }
      })
    }
    loops(permissionTableData, code);
    return value;
  }

  //checkbox循环事件  flag是否选中 code唯一标识  type查看或者编辑
  changeFlag = (flag, code, type) => {
    let { permissionTableData } = this.state;
    //递归循环
    let loops = (data, flag, code, type) => {
      data.map((item, index) => {
        if (item.data.code == code) {
          item.data[type] = flag ? "Y" : "N";
          item[type + 'indeterminate'] = false;
          if (item.data.parent_code) {
            //子级选中父级也选中
            let childAndParent_Select = (code, type) => {
              let parent = this.getItem(code);
              if (parent.children.length > 0) {
                let all = parent.children.every((item1) => {
                  return item1.data[type] == "Y"&&item1[type + "indeterminate"] == false;
                })
                let some = parent.children.some((item1) => {
                  return item1.data[type] == "Y";
                })
                if (all) {
                  parent[type + 'indeterminate'] = false;
                  parent.data[type] = "Y"
                } else if (some) {
                  parent[type + 'indeterminate'] = true;
                  parent.data[type] = "Y"
                } else {
                  parent[type + 'indeterminate'] = false;
                  parent.data[type] = "N"
                }
              }
              if (parent.data.parent_code) {
                childAndParent_Select(parent.data.parent_code, type)
              }
            }
            childAndParent_Select(item.data.parent_code, type);
          }
          if (item.children.length > 0) {
            //父亲选中,子级全选中,实现全选反选
            let parentAndChild_Select = (data, flag, type) => {
              data.map((item1, index) => {
                item1.data[type] = flag ? "Y" : "N";
                item1[type + 'indeterminate'] = false;
                if (item1.children.length > 0) {
                  parentAndChild_Select(item1.children, flag, type);
                }
              })
            }
            parentAndChild_Select(item.children, flag, type);
          }
        }

        if (item.children.length > 0) {
          loops(item.children, flag, code, type);
        }
      })
    }
    loops(permissionTableData, flag, code, type);
    this.setState({
      permissionTableData: permissionTableData
    }, () => {
      console.log(this.state)
    })
  }
  //查看checkbox onchange事件 e--chekcbox值 code当前唯一标识
  ViewonChange = (e, code, type) => {
    let flag = e.target.checked;
    this.changeFlag(flag, code, type);
  }
  //编辑checkbox onchange事件 e--chekcbox值 code当前唯一标识
  EditonChange = (e, code, type) => {
    let flag = e.target.checked;
    this.changeFlag(flag, code, type);
  }
  //Y与N和true/false的转换
  transformation = (text) => {
    if (text == "Y") {
      return false;
    } else if (text == "N") {
      return true;
    } else {
      return false;
    }
  }

  //编辑配置
  editMenu = () => {
    let col = [
      {
        title: '菜单名称',
        dataIndex: 'data.name'
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_view',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={this.transformation(record.data.enable_view)}//是否仅用
                onChange={(e) => this.ViewonChange(e, record.data.code, "has_view")}//change事件
                indeterminate={record['has_viewindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_edit',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={this.transformation(record.data.enable_edit)}//是否仅用
                onChange={(e) => this.EditonChange(e, record.data.code, "has_edit")}//change事件
                indeterminate={record['has_editindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      }
    ]
    this.setState({
      editFlag: true,
      columns: col
    })
  }
  //扁平化数组(tree)变为一维数组
  FlatArray = (data, val) => {
    if (data.length == 0) {
      return [];
    }
    let arr = [];
    data.map((item) => {
      arr.push(item.data);
      if (item.children.length > 0) {
        arr = arr.concat(this.FlatArray(item.children));
      }
    })
    return arr;
  }
  //保存
  saveMenu = () => {
    let { permissionTableData, yTreeData } = this.state;
    let col = [
      {
        title: '菜单名称',
        dataIndex: 'data.name'
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_view',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={true}//是否仅用
                indeterminate={record['has_viewindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      },
      {
        title: '查看权限',
        dataIndex: 'data.has_edit',
        render: (text, record) => {
          return (
            <>
              <Checkbox //参考antd Checkbox API
                checked={text == "Y" ? true : false}//是否选中
                disabled={true}//是否仅用
                indeterminate={record['has_editindeterminate'] ? true : false} //全选与反选状态
              >

              </Checkbox>
            </>
          )
        }
      }
    ]
    this.setState({
      editFlag: false,
      columns: col
    })
  }
  //对比差异 传两个数组找出变化的项
  ContrastDifferences = (data1, data) => {
    if (data1.length == 0 || data.length == 0) {
      return [];
    }
    let changeArr = [];
    data1.map((item, index) => {
      if (item.has_view != data[index].has_view || item.has_edit != data[index].has_edit) {
        changeArr.push(item);
      }
    })
    return changeArr;
  }
  render() {
    const { columns, permissionTableData, loading, editFlag } = this.state;
    return (
      <div>

        {
          editFlag ? <Button onClick={this.saveMenu}>保存</Button> : <Button onClick={this.editMenu}>编辑</Button>
        }
        <Table //参考antd Table API
          columns={columns} //表格表头
          dataSource={permissionTableData}//表格数据
          loading={loading} //loading状态
          scroll={{ y: 400, x: 1000 }} //滚动
          pagination={false} //分页
        ></Table>
      </div>
    )
  }

}
export default index;

 

<think>根据用户问题,用户希望使用Ant Design实现一个四层树形结构组件。Ant Design的Tree组件支持多层级结构,通过配置treeData属性即可实现。 实现步骤: 1. 准备树形结构数据:treeData是一个数组,每个节点可以包含children属性来表示子节点,从而形成多层结构。 2. 使用Tree组件,并将treeData传递给组件的treeData属性。 注意:Ant Design Tree组件默认展开所有节点,但通常我们可能希望默认展开某些层级或节点。可以通过`expandedKeys`属性控制展开的节点,并通过`onExpand`事件处理展开状态的变化。 下面是一个四层树形结构组件的示例代码:</think>### Ant Design 实现四层树形结构组件 在 Ant Design 中实现四层树形结构组件,主要通过 `Tree` 组件配合多层嵌套的 `treeData` 数据结构实现。以下是具体实现方法: #### 1. **准备树形结构数据** 使用嵌套的 `children` 属性构建四层结构: ```javascript const treeData = [ { title: '根节点 1', key: '0-0', children: [ { title: '二级节点 1-1', key: '0-0-0', children: [ { title: '三级节点 1-1-1', key: '0-0-0-0', children: [ // 第四层节点 { title: '四级节点 1-1-1-1', key: '0-0-0-0-0' }, { title: '四级节点 1-1-1-2', key: '0-0-0-0-1' } ] } ] } ] }, { title: '根节点 2', key: '0-1', children: [/* 类似结构 */] } ]; ``` #### 2. **渲染 Tree 组件** ```jsx import { Tree } from 'antd'; function FourLevelTree() { return ( <Tree treeData={treeData} defaultExpandAll={true} // 默认展开所有节点 onSelect={(selectedKeys) => console.log('选中:', selectedKeys)} /> ); } ``` #### 3. **关键功能配置** - **展开控制**:使用 `expandedKeys` 和 `onExpand` 控制展开状态 ```jsx const [expandedKeys, setExpandedKeys] = useState(['0-0', '0-0-0']); <Tree expandedKeys={expandedKeys} onExpand={(keys) => setExpandedKeys(keys)} /> ``` - **异步加载**:通过 `loadData` 属性实现动态加载子节点 ```jsx const loadData = async (treeNode) => { if (treeNode.children) return; const children = await fetchData(treeNode.key); treeNode.children = children; }; ``` #### 4. **完整示例代码** ```jsx import React, { useState } from 'react'; import { Tree } from 'antd'; const treeData = [/* 上述数据结构 */]; export default () => { const [expandedKeys, setExpandedKeys] = useState(['0-0', '0-0-0']); return ( <Tree treeData={treeData} expandedKeys={expandedKeys} onExpand={(keys) => setExpandedKeys(keys)} defaultExpandAll={false} showLine={{ showLeafIcon: false }} height={400} /> ); }; ``` #### 注意事项 1. **key 值规范**:每层节点的 `key` 必须全局唯一(推荐使用 `parentKey-childKey` 模式) 2. **性能优化**:当数据量较大时: - 启用虚拟滚动:`<Tree height={400} virtual />` - 使用 `loadData` 异步加载子节点 3. **默认展开**:通过 `defaultExpandedKeys` 设置初始展开的节点 4. **样式定制**:通过 `titleRender` 属性自定义节点内容: ```jsx titleRender={(node) => ( <span style={{ color: node.level === 4 ? '#1890ff' : '' }}> {node.title} </span> )} ``` Ant Design 的 Tree 组件提供了丰富的 API 支持复杂树形结构的展示和交互,通过合理配置可满足四层结构的需求[^1][^2]。 --- ### 相关问题 1. 如何在 Ant Design Tree 中实现节点的动态加载? 2. Ant Design Tree 组件如何实现节点的拖拽排序功能? 3. 如何为不同层级的树节点设置不同的图标? 4. 树形结构数据量过大时,有哪些性能优化方案? [^1]: Ant Design 是蚂蚁集团设计团队开发的一套企业级 UI 设计语言和 React 组件库,它致力于提升用户界面设计的规范性和一致性,提高开发效率。 [^2]: 在默认展开某些指定节点时适用,通过 `expandedKeys` 和 `onExpand` 控制展开状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值