ant-design实现树的穿梭框,穿梭后右侧是已选树(二)

12 篇文章 1 订阅
2 篇文章 0 订阅
该文详细介绍了如何基于antd库的Tree组件实现一个具有搜索功能的穿梭框。主要目标是使左边树形结构展示完整的树,而右边显示已选择的树,支持左右穿梭操作。文中给出了搜索优化、onCheck函数更新以及generateTree函数的修改,以达到目标效果,同时处理了已勾选的显示值bug。
摘要由CSDN通过智能技术生成

 根据上一篇目标一,进一步实现树的穿梭框

头部搜索功能有点问题,处理bug 在文末,咨询可私

主要内容:

基于ant-design树的穿梭框,实现穿梭后右侧是已选树,(当前antd右侧只有一个层级)

理想的树的穿梭框:

左边是完整的树,右边是已选的树,左边已选穿梭到右边,左边已选的消失,右边增加已选,右边也可以勾选然后穿梭回去左边,左边出现右边消失。

目标1:右边是已选的树,左边已选穿梭到右边,左边树不变可以继续操作,右边只可以看结果 

目标2:右边是已选的树,左边已选穿梭到右边,左边已选的消失掉,右边可以选择穿梭回去 

主要核心办法:左边不展示已被穿梭的数据(不改变左边的原数组,采用隐藏的方式,已经被穿梭的或者子集全部被穿梭的不展示)

目标2:目前效果 

步骤一:把目标一的搜索进行优化

改动代码:

  onSearch={(dir, val) => {
            if (dir === 'left') { // 左边搜索
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(dataSource, val);
                this.setState({ newDataSource: newDeptList });
              } else {
                this.setState({ newDataSource: dataSource });// 左边没搜索时候的原始数据
              }
            } else { //右边搜索
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(rightDataSource, val);
                this.setState({ newRightDataSource: newDeptList });
              } else {
                this.setState({ newRightDataSource: rightDataSource }); // 右边没搜索时候的原始数据
              }
            }
          }}
// 树搜索函数 
onsearchDataSource(dataSource, val) {
    // 递归查找存在的父级
    const deepFilter = (i, val) => {
      return (
        i.children.filter((o) => {
          if (o.label.indexOf(val) > -1) {
            return true;
          }
          if (o.children && o.children.length > 0) {
            return deepFilter(o, val);
          }
        }).length > 0
      );
    };
    const filterMenu = (list, val) => {
      return list
        .filter((item) => {
          if (item.label.indexOf(val) > -1) {
            return true;
          }
          if (item.children && item.children.length > 0) {
            return deepFilter(item, val);
          }
          return false;
        })
        .map((item) => {
          item = Object.assign({}, item);
          if (item.children) {
            item.children = item.children.filter((res) => res.label.indexOf(val) > -1);
            filterMenu(item.children, val);
          }
          return item;
        });
    };
    return filterMenu(dataSource, val);
  }

步骤二:把目标onCheck函数进行更新

onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
           
                    if (_.length > 0) {
                      this.setState({ currTargetKeys: lodash.union(targetKeys, checkedChildKeys) });
                      onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                      // 增加随机数 为了可以触发向右穿梭的按钮 触发后删除随机数
                      onItemSelect('DEL' + Math.random(), true);
                    } else {
                  // 加上如果勾来勾去又没勾的情况
                      this.setState({ currTargetKeys: targetKeys });
                    }
                  }}
 

左边的tree : 

if (direction === 'left') {
              const checkedKeys = [...selectedKeys, ...currTargetKeys];
              return newDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  defaultExpandParent={true}
                  disabled={disabled}
                  checkable
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    if (_.length > 0) {
                      this.setState({ currTargetKeys: lodash.union(targetKeys, checkedChildKeys) });
                      onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                      // 增加随机数 为了可以触发向右穿梭的按钮 触发后删除随机数
                      onItemSelect('DEL' + Math.random(), true);
                    } else {
                      this.setState({ currTargetKeys: targetKeys });
                    }
                  }}>
                  {generateTree(newDataSource, targetKeys, searchValue, disabled, 'left')}
                </Tree>
              ) : (
                <div></div>
              );
            }

右边的tree :

// 右边从纯展示变成了可更改 所以增加已选的操作
if (direction === 'right') {
              const checkedKeys = [...rightCurrTargetKeys];
              return newRightDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  checkable
                  defaultExpandAll={true}
                  disabled={disabled}
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    //  勾选后更改左侧已选定内容
                    this.setState({ currTargetKeys: lodash.xor(checkedChildKeys, targetKeys) });
                    // 设置右侧已勾选框
                    this.setState({ rightCurrTargetKeys: checkedChildKeys });
                    onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                  }}>
                  {generateTree(newRightDataSource, targetKeys, searchValue, false, 'right')}
                </Tree>
              ) : (
                <div></div>
              );
            }

步骤三:generateTree展示的更新

目标一:左边没变

目标二:左边减少上次已穿梭的内容,右边增加新穿梭的内容,

// 不改变左边的原数组,采用隐藏的方式,已经被穿梭的或者子集全部被穿梭的不展示label
const generateTree = (treeNodes = [], checkedKeys = [], searchValue, disabled = false, type = 'left') => {
  return treeNodes.map(({ children, ...props }) => {
    if (type === 'left') {
      // 是否子元素都被选择了 如果是则父不展示了
      const isAll =
        children.length > 0
          ? lodash.every(children, (e) => {
              return checkedKeys.includes(e.key);
            })
          : false;
// 自己是否被穿梭了 穿梭了则不展示了 !checkedKeys.includes(props.key)
      return !isAll && !checkedKeys.includes(props.key) ? (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over'>{props.label}</span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      ) : (
        ''
      );
    } else {
// 右边的展示内容
      return (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over'>
                {props.label}
              </span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      );
    }
  });
};

TreeTransfer 整个组件代码

import React, { Component } from 'react';
import './index.less';
import { Transfer, Tree, Tooltip } from 'antd';
import lodash from 'lodash';
const { TreeNode } = Tree;
const isChecked = (selectedKeys, eventKey) => {
  return selectedKeys.indexOf(eventKey) !== -1;
};

const generateTree = (treeNodes = [], checkedKeys = [], searchValue, disabled = false, type = 'left') => {
  return treeNodes.map(({ children, ...props }) => {
    if (type === 'left') {
      // 是否子元素都被选择了
      const isAll =
        children.length > 0
          ? lodash.every(children, (e) => {
              return checkedKeys.includes(e.key);
            })
          : false;   
   return !isAll && !checkedKeys.includes(props.key) ? (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over'>{props.label}</span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      ) : (
        ''
      );
    } else {
      return (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over' style={{ color: props.label.indexOf(searchValue) >= 0 ? 'red' : '' }}>
                {props.label}
              </span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      );
    }
  });
};

class TreeTransfer extends Component {
  constructor(props, context) {
    super(props, context);
    this.stores = this.props.UserMgtMod;
    this.state = {
      searchValue: null,
      transferDataSource: [],
      currTargetKeys: [],
      rightCurrTargetKeys: [],
      defaultExpandAll: true,
      newDataSource: [],
      newRightDataSource: [],
    };
  }
  componentDidMount() {
    const { dataSource, targetKeys, rightDataSource } = this.props;
    this.flatten(dataSource);
    this.setState({
      currTargetKeys: targetKeys,
      newDataSource: dataSource,
      newRightDataSource: rightDataSource,
    });
  }
  UNSAFE_componentWillReceiveProps(nextprops) {
    const { dataSource, targetKeys, rightDataSource } = nextprops;
 
    this.setState({
      currTargetKeys: targetKeys,
      newDataSource: dataSource,
      newRightDataSource: rightDataSource,
    });
  }
  flatten(list = []) {
    const dataSource = this.state.transferDataSource;
    list.forEach((item) => {
      dataSource.push(item);
      this.setState({ transferDataSource: dataSource });
      this.flatten(item.children);
    });
  }
  onChange(e) {
    this.setState({
      searchValue: e.target.value,
    });
  }
  onsearchDataSource(dataSource, val) {
    // 递归查找存在的父级
    const deepFilter = (i, val) => {
      return (
        i.children.filter((o) => {
          if (o.label.indexOf(val) > -1) {
            return true;
          }
          if (o.children && o.children.length > 0) {
            return deepFilter(o, val);
          }
        }).length > 0
      );
    };
    const filterMenu = (list, val) => {
      return list
        .filter((item) => {
          if (item.label.indexOf(val) > -1) {
            return true;
          }
          if (item.children && item.children.length > 0) {
            return deepFilter(item, val);
          }
          return false;
        })
        .map((item) => {
          item = Object.assign({}, item);
          if (item.children) {
            item.children = item.children.filter((res) => res.label.indexOf(val) > -1);
            filterMenu(item.children, val);
          }
          return item;
        });
    };
    return filterMenu(dataSource, val);
  }
  render() {
    const { dataSource, targetKeys, rightDataSource, disabled, ...restProps } = this.props;
    const { transferDataSource, searchValue, currTargetKeys, rightCurrTargetKeys, newDataSource, newRightDataSource } = this.state;

    return (
      <div>
        <Transfer
          {...restProps}
          disabled={disabled}
          targetKeys={currTargetKeys}
          dataSource={transferDataSource}
          className='tree-transfer'
          render={(item) => item.label}
          showSearch
          showSelectAll={false}
          onSearch={(dir, val) => {
            if (dir === 'left') {
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(dataSource, val);
                this.setState({ newDataSource: newDeptList });
              } else {
                this.setState({ newDataSource: dataSource });
              }
            } else {
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(rightDataSource, val);
                this.setState({ newRightDataSource: newDeptList });
              } else {
                this.setState({ newRightDataSource: rightDataSource });
              }
            }
          }}>
          {({ direction, onItemSelect, selectedKeys }) => {
            if (direction === 'left') {
              const checkedKeys = [...selectedKeys, ...currTargetKeys];
              return newDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  defaultExpandParent={true}
                  disabled={disabled}
                  checkable
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    if (_.length > 0) {
                      this.setState({ currTargetKeys: lodash.union(targetKeys, checkedChildKeys) });
                      onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                      // 增加随机数 为了可以触发向右穿梭的按钮 触发后删除随机数
                      onItemSelect('DEL' + Math.random(), true);
                    } else {
                      this.setState({ currTargetKeys: targetKeys });
                    }
                  }}>
                  {generateTree(newDataSource, targetKeys, searchValue, disabled, 'left')}
                </Tree>
              ) : (
                <div></div>
              );
            }
            if (direction === 'right') {
              const checkedKeys = [...rightCurrTargetKeys];
              return newRightDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  checkable
                  defaultExpandAll={true}
                  disabled={disabled}
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    //  勾选后更改左侧已选定内容
                    this.setState({ currTargetKeys: lodash.xor(checkedChildKeys, targetKeys) });
                    // 设置右侧已勾选框
                    this.setState({ rightCurrTargetKeys: checkedChildKeys });
                    onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                  }}>
                  {generateTree(newRightDataSource, targetKeys, searchValue, false, 'right')}
                </Tree>
              ) : (
                <div></div>
              );
            }
          }}
        </Transfer>
      </div>
    );
  }
}
export default TreeTransfer;

 组件引用案例:


        <Modal
          width={1000}
          title={'所属角色'}
          className='user-modal'
          visible={this.state.roleModal}
          onOk={() => {
            this.setState({ roleModal: false, rightDataSource: [] });
          }}
          onCancel={() => {
            this.setState({ roleModal: false, rightDataSource: [] });
          }}>
          <Spin spinning={roleLoading}> 
            {this.state.roleModal && (
              <TreeTransfer
                disabled={'' + title === 'detail' ? true : false}
                dataSource={roleList} // 原始树结构
                rightDataSource={rightDataSource}
                targetKeys={roleTargetKeys}
                onChange={this.handleChange.bind(this)}
              />
            )}
          </Spin>
        </Modal>

 关键函数

 handleChange = (newTargetKeys) => {
    const targetKeys = newTargetKeys.reduce((arr, e) => {
      // 增加随机数 为了可以触发向右穿梭的按钮 触发后删除随机数
      if (e.indexOf('DEL') < 0) {
        arr.push(e);
      }
      return arr;
    }, []);
    // 递归查找是否存在包含选中key的父级 
    const deepFilter = (i, arr) => {
      return (
        i.children.filter((o) => {
          if (arr.includes(o.key)) {
            return true;
          }
          if (o.children && o.children.length > 0) {
            return deepFilter(o, arr);
          }
        }).length > 0
      );
    };
  // 找到一个存在key的父级 然后遍历获取层级内容
    const filterMenu = (list, arr) => {
      return list
        .filter((item) => {
          if (arr.includes(item.key)) {
            return true;
          }
          if (item.children && item.children.length > 0) {
            return deepFilter(item, arr);
          }
          return false;
        })
        .map((item) => {
          item = Object.assign({}, item);
          if (item.children) {
            item.children = filterMenu(item.children, arr);
          }
          return item;
        });
    };
    if (this.state.roleModal) {
      const { roleList } = toJS(this.stores.state);
      this.setState({ roleTargetKeys: [...new Set(targetKeys)] }); // 去重
      const rightDataSource = filterMenu(roleList, targetKeys); // 查询组装已选树
      this.stores.saveInfoModal({ roleIds: targetKeys });
      this.props.form.setFieldsValue({ roleIds: targetKeys });
      this.setState({ rightDataSource: rightDataSource || [] });
    }
   
  };

 触发方法:

  <div style={{ display: 'flex' }}>
              <YxButton
                type='primary'
                style={{ marginRight: '10px' }}
                onClick={() => {
                  this.setState({ roleModal: true });
                  setTimeout(() => {
                    this.handleChange(this.state.roleTargetKeys);
                  }, 100);
                }}>
                {'' + title === 'detail' ? '查看' : '请选择'}
              </YxButton>
              已选{this.state.roleTargetKeys.length}项
            </div>

 目标二就完成了

处理已勾选的显示值bug

 初始化

   this.state = {
      rightCheckLength: 0, // 记录右边已勾
      leftCheckLength: 0, // 记录左边已勾
    };
  }

 重置

  UNSAFE_componentWillReceiveProps(nextprops) {
  // 穿梭到右边更新后重置
    this.setState({
      leftCheckLength: 0,
      rightCheckLength: 0,
    });

  }

 ​ 自行定义title

 <Transfer
// 自行定义title
          titles={[`${leftCheckLength}/${dataSourceLength.length - targetKeys.length}项`, `${rightCheckLength}/${targetKeys.length}项`]}
        >

​设置勾选

// 左边     
  
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    // 设置勾选
                    this.setState({ leftCheckLength: checkedChildKeys.length });
 

// 右边
 
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    this.setState({ currTargetKeys: lodash.xor(checkedChildKeys, targetKeys) });
                    
                 

 完整代码:

import React, { Component } from 'react';
import './index.less';
import { Transfer, Tree, Tooltip } from 'antd';
import lodash from 'lodash';
const { TreeNode } = Tree;
const isChecked = (selectedKeys, eventKey) => {
  return selectedKeys.indexOf(eventKey) !== -1;
};

const generateTree = (treeNodes = [], checkedKeys = [], searchValue, disabled = false, type = 'left') => {
  return treeNodes.map(({ children, ...props }) => {
    if (type === 'left') {
      // 是否子元素都被选择了
      const isAll =
        children && children.length > 0
          ? lodash.every(children, (e) => {
              return checkedKeys.includes(e.key);
            })
          : false;

      return !isAll && !checkedKeys.includes(props.key) ? (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over'>{props.label}</span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      ) : (
        ''
      );
    } else {
      return (
        <TreeNode
          {...props}
          disabled={disabled}
          key={props.key}
          title={
            <Tooltip placement='topLeft' title={props.label}>
              <span className='title-over' style={{ color: props.label.indexOf(searchValue) >= 0 ? 'red' : '' }}>
                {props.label}
              </span>
            </Tooltip>
          }>
          {generateTree(children, checkedKeys, searchValue, disabled, type)}
        </TreeNode>
      );
    }
  });
};

class TreeTransfer extends Component {
  constructor(props, context) {
    super(props, context);
    this.stores = this.props.UserMgtMod;
    this.state = {
      searchValue: null,
      transferDataSource: [],
      currTargetKeys: [],
      rightCurrTargetKeys: [],
      defaultExpandAll: true,
      newDataSource: [],
      newRightDataSource: [],
      rightCheckLength: 0,
      leftCheckLength: 0,
      dataSourceLength: 0,
    };
  }
  componentDidMount() {
    const { dataSource, targetKeys, rightDataSource } = this.props;
    this.flatten(dataSource);
    this.setState({
      currTargetKeys: targetKeys,
      newDataSource: dataSource,
      newRightDataSource: rightDataSource,
    });
    this.getChildrenLength(dataSource);
  }
  UNSAFE_componentWillReceiveProps(nextprops) {
    const { dataSource, targetKeys, rightDataSource } = nextprops;
    this.setState({
      leftCheckLength: 0,
      rightCheckLength: 0,
    });
    // this.flatten(nextprops.dataSource);
    this.setState({
      currTargetKeys: targetKeys,
      newDataSource: dataSource,
      newRightDataSource: rightDataSource,
    });
  }
  //  获取子数量 用在勾选是左上角的显示
  getChildrenLength(dataSource) {
    const getTail = (item) => (item.children && item.children.length > 0 ? item.children.map((m) => getTail(m)) : [item]);
    const result = lodash.flattenDeep(dataSource.map((m) => getTail(m)));
    this.setState({ dataSourceLength: result.length });
  }
  flatten(list = []) {
    const dataSource = this.state.transferDataSource;
    list.forEach((item) => {
      dataSource.push(item);
      this.setState({ transferDataSource: dataSource });
      this.flatten(item.children);
    });
  }
  onChange(e) {
    this.setState({
      searchValue: e.target.value,
    });
  }
  onsearchDataSource(dataSource, val) {
    // 递归查找存在的父级
    const deepFilter = (i, val) => {
      return (
        i.children.filter((o) => {
          if (o.label.indexOf(val) > -1) {
            return true;
          }
          if (o.children && o.children.length > 0) {
            return deepFilter(o, val);
          }
        }).length > 0
      );
    };
    const filterMenu = (list, val) => {
      return list
        .filter((item) => {
          if (item.label.indexOf(val) > -1) {
            return true;
          }
          if (item.children && item.children.length > 0) {
            return deepFilter(item, val);
          }
          return false;
        })
        .map((item) => {
          item = Object.assign({}, item);
          if (item.children) {
            item.children = item.children.filter((res) => res.label.indexOf(val) > -1);
            filterMenu(item.children, val);
          }
          return item;
        });
    };
    return filterMenu(dataSource, val);
  }
  render() {
    const { dataSource, targetKeys, rightDataSource, disabled, ...restProps } = this.props;
    const { leftCheckLength, rightCheckLength, transferDataSource, searchValue, currTargetKeys, rightCurrTargetKeys, newDataSource, newRightDataSource, dataSourceLength } = this.state;

    return (
      <div>
        <Transfer
          {...restProps}
          disabled={disabled}
          targetKeys={currTargetKeys}
          dataSource={transferDataSource}
          className='tree-transfer'
          render={(item) => item.label}
          showSearch
          titles={[`${leftCheckLength}/${dataSourceLength - targetKeys.length}项`, `${rightCheckLength}/${targetKeys.length}项`]}
          showSelectAll={false}
          onSearch={(dir, val) => {
            if (dir === 'left') {
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(dataSource, val);
                this.setState({ newDataSource: newDeptList });
              } else {
                this.setState({ newDataSource: dataSource });
              }
            } else {
              if (val !== '') {
                const newDeptList = this.onsearchDataSource(rightDataSource, val);
                this.setState({ newRightDataSource: newDeptList });
              } else {
                this.setState({ newRightDataSource: rightDataSource });
              }
            }
          }}>
          {({ direction, onItemSelect, selectedKeys }) => {
            if (direction === 'left') {
              const checkedKeys = [...selectedKeys, ...currTargetKeys];
              return newDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  defaultExpandParent={true}
                  disabled={disabled}
                  checkable
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    this.setState({ leftCheckLength: checkedChildKeys.length });
                    if (_.length > 0) {
                      this.setState({ currTargetKeys: lodash.union(targetKeys, checkedChildKeys) });
                      onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                      // 增加随机数 为了可以触发向右穿梭的按钮 触发后删除随机数
                      onItemSelect('DEL' + Math.random(), true);
                    } else {
                      this.setState({ currTargetKeys: targetKeys });
                    }
                  }}>
                  {generateTree(newDataSource, targetKeys, searchValue, disabled, 'left')}
                </Tree>
              ) : (
                <div></div>
              );
            }
            if (direction === 'right') {
              const checkedKeys = [...rightCurrTargetKeys];
              return newRightDataSource.length > 0 ? (
                <Tree
                  blockNode
                  showLine
                  checkable
                  defaultExpandAll={true}
                  disabled={disabled}
                  checkedKeys={checkedKeys}
                  onCheck={(_, even) => {
                    const {
                      checkedNodes,
                      node: {
                        props: { eventKey },
                      },
                    } = even;
                    // 筛选出最底层的子集 集合
                    const checkedChildKeys = checkedNodes.reduce((arr, e) => {
                      if (e.props.children.length <= 0) {
                        arr.push(e.key);
                      }
                      return arr;
                    }, []);
                    this.setState({ currTargetKeys: lodash.xor(checkedChildKeys, targetKeys) });
                    this.setState({ rightCheckLength: checkedChildKeys.length, rightCurrTargetKeys: checkedChildKeys });
                    onItemSelect(eventKey, !isChecked(checkedKeys, eventKey));
                  }}>
                  {generateTree(newRightDataSource, targetKeys, searchValue, false, 'right')}
                </Tree>
              ) : (
                <div></div>
              );
            }
          }}
        </Transfer>
      </div>
    );
  }
}
export default TreeTransfer;

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Embrace924

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值