zoukankan      html  css  js  c++  java
  • antd可搜索可选择Tree树形组件,expandedKeys,checkedKeys属性详解

    最近写react用的都是antd组件,不得不说,antd组件在使用上会比element-UI复杂点,不知道是因为react的原因不.很多组件的方法是需要自己配置的,在element-ui中可能只需要增加一个属性,最近也使用也踩了一些坑.今天总结一下Tree树形组件的使用和一些闭坑指南把.
    项目源码: https://github.com/shengbid/my-react-admin这是一个react hook + antd + ts写的后台管理系统,
    我的需求是: 一个可选择的tree树形列表,页面初始化展示,从后台获取数据,根据数据设置部分节点选中.顶部有搜索框,可以搜索树形列表,根据搜索高亮匹配的节点,并且展开节点.
    找了下官网的例子,也有可搜索tree,拿过来用了下,套上自己的数据,结果怎么都不生效.折腾了半天,发现是我的数据的原因,后台返给我的key是Number数据,而tree设置展开和选中都需要string数据的key
    所以还是要仔细看文档
     
    然后还要注意的是expandedKeys和defaultExpandedKeys 也就是属性前有default和没有default的区别,没有default是完全控制,做任何操作都要重新设置值,否则就不会改变,有default的属性是只在初始化渲染有效,后期的操作不会影响

    以defaultExpandedKeys为例,初始值设置的展开节点会生效,但是在后期搜索节点后重新设置展开节点时就不会生效了,所以如果你之后还需要对节点进行操作,就需要用没有default的完全可控的expandedKeys属性
     
    实现可搜索的tree的步骤:

    1.设置expandedKeys属性来控制搜索时的节点展开
    2.对treeData数据进行处理,设置样式,对匹配的搜索项高亮
    3.增加输入框,输入时,调用方法把需要展开的节点返回,重新设置expandedKeys
    4.点击节点的展开收缩是也需要重新设置expandedKeys

    贴代码
    import React, { useEffect, useState } from 'react';
    import { Tree, Input } from 'antd'
    import { getDeptList } from '@/services/dept'
    import { 
      // getFathersById,
      getParentKey,
     } from '@/commons/utils'
    import { DeleteOutlined } from '@ant-design/icons'
    import './style.less'
    
    const Detail = () => {
      const [expandedKeys, setExpandedKeys] = useState(['0-0', '0-0-0'])
      const [treeData, setTreeData] = useState<any[]>([])
      const [selectdKeys, setSelectdKeys] = useState<any[]>([])
      const [checkedKeys, setCheckedKeys] = useState<any[]>([])
      const [autoExpandParent, setAutoExpandParent] = useState(true)
      const [searchValue, setSearchValue] = useState('')
    
      // 将树形节点改为一维数组
      const generateList = (data: any, dataList: any[]) => {
        for (let i = 0; i < data.length; i++) {
          const node = data[i];
          const { key, title } = node;
          dataList.push({ key, title, });
          if (node.children) {
            generateList(node.children, dataList);
          }
        }
        return dataList
      }
    
      // 获取树形节点数据
      const getList = async() => {
        const res = await getDeptList()
        console.log(11, res)
        setTreeData(res.data)
        // handleTree(res.data)
      }
      // 搜索节点
      const onChange = (e: any) => {
        
        let { value } = e.target
        value = String(value).trim()
        const dataList: any[] = generateList(treeData, [])
        let expandedKeys: any = dataList
          .map((item: any) => {
            if (item.title.indexOf(value) > -1) {
              // return getFathersById(treeData, item.key, 'key')
              return getParentKey(item.key, treeData)
            }
            return null;
          })
          .filter((item: any, i: number, self: any) => item && self.indexOf(item) === i)
    
        // expandedKeys = expandedKeys.length ? expandedKeys[0] : []
        console.log(26, expandedKeys)
        setExpandedKeys(expandedKeys)
        setAutoExpandParent(true)
        setSearchValue(value)
      }
    
      // 树节点展开/收缩
      const onExpand = (expandedKeys: any) => {
        console.log(22, expandedKeys)
        setExpandedKeys(expandedKeys)
        setAutoExpandParent(false)
      }
    
      // 选择节点
      const checkDep = (val: any, data: any) => {
        if (data && data.checkedNodes && data.checkedNodes.length) {
          let checkedNodes = [...data.checkedNodes]
          // console.log(1, val, data)
    
          setSelectdKeys(checkedNodes)
          setCheckedKeys(
            checkedNodes.map((subItem: any) => {
              return subItem.key
            }),
          )
        } else {
          setSelectdKeys([])
          setCheckedKeys([])
        }
      }
    
      // 删除节点
      const removeDep = (i: number) => {
        const checkedNodes = [...selectdKeys]
        checkedNodes.splice(i, 1)
        setSelectdKeys(checkedNodes)
        setCheckedKeys(
          checkedNodes.map((subItem: any) => {
            return subItem.key
          }),
        )
      }
    
      // 处理搜索时树形数据高亮
      const loop = (data: any) =>
        data.map((item: any) => {
          const index = item.title.indexOf(searchValue);
          const beforeStr = item.title.substr(0, index);
          const afterStr = item.title.substr(index + searchValue.length);
          const title =
            index > -1 ? (
              <span>
                {beforeStr}
                <span className="site-tree-search-value">{searchValue}</span>
                {afterStr}
              </span>
            ) : (
              <span>{item.title}</span>
            );
          if (item.children) {
            return { title, key: item.key, children: loop(item.children) };
          }
    
          return {
            title,
            key: item.key,
          };
        })
    
      useEffect(() => {
        getList()
      }, [])
    
      return (
          <div>
            <div className="tree-contanier">
              <div className="left-content">
                <span>可搜索可控制选择的树形组件</span>
                <Input style={{ marginBottom: 8 }} allowClear placeholder="Search" onChange={onChange} />
                <Tree
                  onExpand={onExpand}
                  expandedKeys={expandedKeys}
                  autoExpandParent={autoExpandParent}
                  checkable
                  defaultExpandAll
                  onCheck={checkDep}
                  checkedKeys={checkedKeys}
                  checkStrictly
                  treeData={loop(treeData)}
                />
              </div>
              <div className="right-content">
                <span>已选择列表</span>
                <ul>
                  {selectdKeys.map((item: any, i: number) => {
                    return <li key={item.key} className="select-item">
                      {item.title}
                      <span className="remove" title="删除" onClick={() => removeDep(i)}><DeleteOutlined /></span>
                    </li>
                  })}
                </ul>
              </div>
            </div>
          </div>
      )
    }
    
    export default Detail
    代码中的getParentKey方法单独拿出来了
    // antd tree树形匹配方法
    export function getParentKey( key: number | string, tree: any): any {
      let parentKey
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i];
        if (node.children) {
          if (node.children.some((item: any) => item.key === key)) {
            parentKey = node.key;
          } else if (getParentKey(key, node.children)) {
            parentKey = getParentKey(key, node.children);
          }
        }
      }
      return parentKey;
    }

    实现效果

  • 相关阅读:
    django 笔记4 数据库操作
    html关于不换行代码
    之前搭建的jenkins的一些笔记
    pip报错
    ssh 免密及加密远程脚本实现
    今天了解了些redis和memcached的知识
    django 笔记3
    来选择一款适合你网站的CMS建站程序吧
    如何预防和检测网页挂马?
    网页挂马方式
  • 原文地址:https://www.cnblogs.com/steamed-twisted-roll/p/13552422.html
Copyright © 2011-2022 走看看