穿梭框 Transfer
issue

两框之间的元素迁移,非常直观且有效。一个或多个元素选择后点击方向按钮转到另一列框中。左栏是“源”,右边是“目标”

何时使用

需要两框之间的元素迁移时

如何使用

import { Transfer } from 'tinper-bee';

or

import Transfer from 'bee-transfer';
import 'bee-transfer/build/Transfer.css';

能力特性

常用可选transfer

targetKeys需要通过ES6的扩展运算符进行赋值,实现对象的深拷贝

查看源码
14 Source
移除已选
Not Found
6 Target
移除已选
Not Found

带搜索框的tranfer

查看源码
13
7

底部自定义的transfer

查看源码

隐藏复选框

通过`showCheckbox`参数控制复选框显示和隐藏

查看源码
14 Source
移除已选
Not Found
6 Target
移除已选
Not Found

拖拽穿梭

通过`draggable`参数设置是否可以通过拖拽进行穿梭和排序

查看源码
14 Source
移除已选
Not Found
6 Target
移除已选
Not Found

自定义渲染行数据

自定义渲染每一个 Transfer Item,可用于渲染复杂数据。

查看源码
14 Source
移除已选
Not Found
6 Target
移除已选
Not Found

自定义右侧已选列表的排列顺序

`appendToBottom` 参数控制是否将已选项追加到右侧列表末尾,其默认值为false(即将已选项添加到右侧列表最上方)。可在项目中动态改变参数数组targetKeys,穿梭框会根据targetKeys中的顺序进行排序。应用场景:通过上移/下移改变右侧数据顺序。

查看源码
17 Source
移除已选
Not Found
3 Target
移除已选
Not Found

树穿梭

结合 Tree 和 Transfer 的使用示例,解决多级数据穿梭问题。

查看源码
18
移除已选
Not Found
0
    移除已选
    Not Found

    API

    参数 说明 类型 默认值
    dataSource 设置数据源。当有targetKey props存在时,dataSource的数据刨去targetKey数据,剩下的都放在左边列表 [] []
    render 每行数据渲染函数,该函数的入参为 dataSource 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 label 字段为 ReactElement,value 字段为 title Function(record) -
    targetKeys 展示在右边列表的数据集 [] []
    selectedKeys 所有选中的item的keys [] []
    onChange 当item在穿梭成功后的回调 参数(targetKeys, direction, moveKeys) func -
    onSelectChange 当选中的item发生改变时的回调 参数(sourceSelectedKeys, targetSelectedKeys) fun -
    onScroll 当滑动可选的item列表的回调 参数(direction, event) func -
    listStyle 自定义的columns的样式表 object -
    className class string ''
    titles 两columns的title [] -
    operations 自定义按钮操作 [] '>', '<'
    showSearch 是否显示搜索框 boolean false
    filterOption 搜索过滤方法 参数(inputValue, option) func或者boolean -
    searchPlaceholder 搜索框的默认显示文字 string 'Search'
    notFoundContent 当没有相关内容的显示内容 string或ReactNode 'Not Found'
    footer 渲染底部的dom ReactNode -
    lazy 懒加载dom object 当tranfer放在bee-modal里 添加参数 lazy={container:"modal"}
    onSearchChange 当搜索域变化的回调函数 参数(direction: 'left' 'right', event: Event) func
    showCheckbox 是否显示Checkbox复选框 bool true
    draggable 是否可以通过拖拽进行穿梭和排序 bool false
    appendToBottom 是否将已选项追加到右侧列表末尾 bool false
    renderOperation 自定义扩展操作栏 () => React.Node ()=>''

    注意事项

    按照 React 的规范,所有的组件数组必须绑定 key。在 Transfer 中,dataSource里的数据值需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。

    如果你的数据没有这个属性,务必使用 rowKey 来指定数据列的主键。

    // 比如你的数据主键是 uid
    return <Transfer rowKey={record => record.uid} />;

    更新日志

    • v2.0.12 2019-05-08 ( release地址 )

      • bee-transfer @2.0.12
        • [Fixbug]解决dataSource为空时报错的问题
    • v2.0.11 2019-05-08 ( release地址 )

      • bee-transfer @2.0.11
        • [Feature]支持自定义右侧已选列表的排列顺序
        • [Feature]增加appendToBottom参数,支持将已选项添加到右侧列表末尾
    • v2.0.10 2019-04-28 ( release地址 )

      • bee-transfer @2.0.10
        • [Fixbug]解决复选框和节点间的间距过宽的问题
        • [Fixbug]解决动态改变targetKeys时,列表数据未更新的问题
        • [Fixbug]解决控制台警告问题
    • v2.0.9 2019-04-24 ( release地址 )

      • bee-transfer @2.0.9
        • [Feature]增加draggable参数,设置是否可以通过拖拽进行穿梭和排序
        • [Feature]增加showCheckbox参数,设置是否显示复选框Checkbox
    • v2.0.8 2019-04-09 ( release地址 )

      • [Feature]bee-transfer @2.0.8,升级依赖
    • v2.0.3 2019-03-04 ( release地址 )

      • 解决穿梭框影响了bee-button样式的问题,主要是按钮disable状态的样式
    常用可选transfer
    JS代码
    /**
    *
    * @title 常用可选transfer
    * @description targetKeys需要通过ES6的扩展运算符进行赋值,实现对象的深拷贝
    *
    */
    
    
    import React, { Component } from 'react';
    import { Button, Transfer } from 'tinper-bee';
    
    
    
    const AllTargetKeys = [];
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      mockData.push({
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        disabled: i % 3 < 1,
    
      });
      AllTargetKeys.push(i.toString());
    }
    
    const targetKeys = mockData
            .filter(item => +item.key % 3 > 1)
            .map(item => item.key);
    
    class Demo1 extends React.Component {
      state = {
        targetKeys,
        selectedKeys: [],
        showModal: false,
        modalSize: ''
      }
    
      handleChange = (nextTargetKeys, direction, moveKeys) => {
        this.setState({ targetKeys: nextTargetKeys });
    
        console.log('targetKeys: ', nextTargetKeys);
        console.log('direction: ', direction);
        console.log('moveKeys: ', moveKeys);
      }
    
      handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
        this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
    
        console.log('sourceSelectedKeys: ', sourceSelectedKeys);
        console.log('targetSelectedKeys: ', targetSelectedKeys);
      }
    
      handleScroll = (direction, e) => {
        console.log('direction:', direction);
        console.log('target:', e.target);
      }
    
      moveAllToRight = () => {
        this.setState({
          targetKeys: AllTargetKeys
        })
      }
      moveAllToLeft = () => {
        this.setState({
          targetKeys: []
        })
      }
    
      render() {
        const state = this.state;
        const targetKeys = [...this.state.targetKeys];
        return (
          <div>
            <Button onClick={this.moveAllToRight} style={{margin:'8px'}}>全部移到右边</Button>
            <Button onClick={this.moveAllToLeft} style={{margin:'8px'}}>全部移到左边</Button>
            <Transfer
              dataSource={mockData}
              titles={['Source', 'Target']}
              targetKeys={targetKeys}
              selectedKeys={state.selectedKeys}
              onChange={this.handleChange}
              onSelectChange={this.handleSelectChange}
              onScroll={this.handleScroll}
              render={item => item.title}
            />
          </div>
        );
      }
    }
    
    
    export default Demo1
    
    带搜索框的tranfer
    JS代码
    /**
    *
    * @title 带搜索框的tranfer
    * @description
    *
    */
    
    import React, { Component } from 'react';
    import { Transfer } from 'tinper-bee';
    
    
    
    class Demo2 extends React.Component {
      state = {
        mockData: [],
        targetKeys: [],
      }
      componentDidMount() {
        this.getMock();
      }
      getMock = () => {
        const targetKeys = [];
        const mockData = [];
        for (let i = 0; i < 20; i++) {
          const data = {
            key: i.toString(),
            title: `content${i + 1}`,
            description: `description of content${i + 1}`,
            chosen: Math.random() * 2 > 1,
          };
          if (data.chosen) {
            targetKeys.push(data.key);
          }
          mockData.push(data);
        }
        this.setState({ mockData, targetKeys });
      }
      filterOption = (inputValue, option) => {
        return option.title.indexOf(inputValue) > -1;
      }
      handleChange = (targetKeys) => {
        this.setState({ targetKeys });
      }
      render() {
        return (
          <Transfer
            dataSource={this.state.mockData}
            showSearch
            filterOption={this.filterOption}
            targetKeys={this.state.targetKeys}
            onChange={this.handleChange}
            render={item => item.title}
          />
        );
      }
    }
    
    
    export default Demo2
    
    底部自定义的transfer
    JS代码
    /**
    *
    * @title 底部自定义的transfer
    * @description 
    *
    */
    
    import React, { Component } from 'react';
    import { Button, Transfer } from 'tinper-bee';
    
    
    
    class Demo3 extends React.Component {
      state = {
        mockData: [],
        targetKeys: [],
      }
      componentDidMount() {
        this.getMock();
      }
      getMock = () => {
        const targetKeys = [];
        const mockData = [];
        for (let i = 0; i < 20; i++) {
          const data = {
            key: i.toString(),
            title: `content${i + 1}`,
            description: `description of content${i + 1}`,
            chosen: Math.random() * 2 > 1,
          };
          if (data.chosen) {
            targetKeys.push(data.key);
          }
          mockData.push(data);
        }
        this.setState({ mockData, targetKeys });
      }
      handleChange = (targetKeys) => {
        this.setState({ targetKeys });
      }
      renderFooter = () => {
        return (
          <Button
            size="sm"
            style={{ float: 'right', margin: 5 }}
            onClick={this.getMock}
          >
            reload
          </Button>
        );
      }
      render() {
        return (
          <Transfer
            dataSource={this.state.mockData}
            showSearch
            listStyle={{
              width: 250,
              height: 300,
            }}
            targetKeys={this.state.targetKeys}
            onChange={this.handleChange}
            render={item => `${item.title}-${item.description}`}
            footer={this.renderFooter}
          />
        );
      }
    }
    
    export default Demo3
    
    隐藏复选框
    JS代码
    /**
    *
    * @title 隐藏复选框
    * @description 通过`showCheckbox`参数控制复选框显示和隐藏
    *
    */
    
    
    import React, { Component } from 'react';
    import { Transfer } from 'tinper-bee';
    
    
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      mockData.push({
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        disabled: i % 3 < 1,
    
      });
    }
    
    const targetKeys = mockData
            .filter(item => +item.key % 3 > 1)
            .map(item => item.key);
    
    class Demo4 extends React.Component {
      state = {
        targetKeys,
        selectedKeys: [],
        showModal: false,
        modalSize: ''
      }
    
      handleChange = (nextTargetKeys, direction, moveKeys) => {
        this.setState({ targetKeys: nextTargetKeys });
    
        console.log('targetKeys: ', targetKeys);
        console.log('direction: ', direction);
        console.log('moveKeys: ', moveKeys);
      }
    
      handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
        this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
    
        console.log('sourceSelectedKeys: ', sourceSelectedKeys);
        console.log('targetSelectedKeys: ', targetSelectedKeys);
      }
    
      handleScroll = (direction, e) => {
        console.log('direction:', direction);
        console.log('target:', e.target);
      }
    
    
      render() {
        const state = this.state;
    
        return (
           <Transfer
              dataSource={mockData}
              showCheckbox={false}
              titles={['Source', 'Target']}
              targetKeys={state.targetKeys}
              selectedKeys={state.selectedKeys}
              onChange={this.handleChange}
              onSelectChange={this.handleSelectChange}
              onScroll={this.handleScroll}
              render={item => item.title}
            />
        );
      }
    }
    
    
    export default Demo4;
    
    拖拽穿梭
    JS代码
    /**
    *
    * @title 拖拽穿梭
    * @description 通过`draggable`参数设置是否可以通过拖拽进行穿梭和排序
    *
    */
    
    
    import React, { Component } from 'react';
    import { Transfer } from 'tinper-bee';
    
    
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      mockData.push({
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        disabled: i % 3 < 1,
    
      });
    }
    
    const targetKeys = mockData
            .filter(item => +item.key % 3 > 1)
            .map(item => item.key);
    
    class Demo5 extends React.Component {
      state = {
        targetKeys,
        selectedKeys: [],
        showModal: false,
        modalSize: ''
      }
    
      handleChange = (nextTargetKeys, direction, moveKeys) => {
        this.setState({ targetKeys: nextTargetKeys });
    
        console.log('targetKeys: ', nextTargetKeys);
        console.log('direction: ', direction);
        console.log('moveKeys: ', moveKeys);
      }
    
      handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
        this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
    
        console.log('sourceSelectedKeys: ', sourceSelectedKeys);
        console.log('targetSelectedKeys: ', targetSelectedKeys);
      }
    
      handleScroll = (direction, e) => {
        console.log('direction:', direction);
        console.log('target:', e.target);
      }
    
    
      render() {
        const state = this.state;
        // targetKeys需要通过数组的扩展运算符进行赋值
        const targetKeys = [...this.state.targetKeys];
        return (
           <Transfer
              draggable={true}
              dataSource={mockData}
              titles={['Source', 'Target']}
              targetKeys={targetKeys}
              selectedKeys={state.selectedKeys}
              onChange={this.handleChange}
              onSelectChange={this.handleSelectChange}
              onScroll={this.handleScroll}
              render={item => item.title}
            />
        );
      }
    }
    
    
    export default Demo5
    
    自定义渲染行数据
    JS代码
    /**
    *
    * @title 自定义渲染行数据
    * @description 自定义渲染每一个 Transfer Item,可用于渲染复杂数据。
    *
    */
    
    
    import React, { Component } from 'react';
    import { Button, Transfer } from 'tinper-bee';
    
    
    
    const AllTargetKeys = [];
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      mockData.push({
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        disabled: i % 3 < 1,
    
      });
      AllTargetKeys.push(i.toString());
    }
    
    const targetKeys = mockData
            .filter(item => +item.key % 3 > 1)
            .map(item => item.key);
    
    class Demo6 extends React.Component {
      state = {
        targetKeys,
        selectedKeys: [],
        showModal: false,
        modalSize: ''
      }
    
      handleChange = (nextTargetKeys, direction, moveKeys) => {
        this.setState({ targetKeys: nextTargetKeys });
    
        console.log('targetKeys: ', nextTargetKeys);
        console.log('direction: ', direction);
        console.log('moveKeys: ', moveKeys);
      }
      
      handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
        this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
    
        console.log('sourceSelectedKeys: ', sourceSelectedKeys);
        console.log('targetSelectedKeys: ', targetSelectedKeys);
      }
    
      /**
       * 自定义渲染行数据
       */
      renderItem = (item) => {
        const customLabel = (
          <span className="custom-item">
            {item.title}
          </span>
        );
    
        return {
          label: customLabel, // 显示的ReactElement节点
          value: item.title, // 作为title显示
        };
      }
    
      render() {
        const state = this.state;
        const targetKeys = [...this.state.targetKeys];
        return (
          <div>
            <Transfer
              dataSource={mockData}
              titles={['Source', 'Target']}
              targetKeys={targetKeys}
              selectedKeys={state.selectedKeys}
              onChange={this.handleChange}
              onSelectChange={this.handleSelectChange}
              render={this.renderItem}
            />
          </div>
        );
      }
    }
    
    
    export default Demo6
    
    自定义右侧已选列表的排列顺序
    JS代码
    /**
    *
    * @title 自定义右侧已选列表的排列顺序
    * @description `appendToBottom` 参数控制是否将已选项追加到右侧列表末尾,其默认值为false(即将已选项添加到右侧列表最上方)。可在项目中动态改变参数数组targetKeys,穿梭框会根据targetKeys中的顺序进行排序。应用场景:通过上移/下移改变右侧数据顺序。
    *
    */
    
    
    import React, { Component } from 'react';
    import { Icon, Button, Transfer } from 'tinper-bee';
    
    
    
    
    const AllTargetKeys = [];
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      mockData.push({
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
      });
      AllTargetKeys.push(i.toString());
    }
    
    const targetKeys = mockData
            .filter(item => +item.key % 7 === 0)
            .map(item => item.key);
    
    class Demo7 extends React.Component {
        state = {
            targetKeys,
            selectedKeys: [],
            showModal: false,
            modalSize: ''
        }
    
        handleChange = (nextTargetKeys, direction, moveKeys) => {
            this.setState({ targetKeys: nextTargetKeys });
    
            console.log('targetKeys: ', nextTargetKeys);
            console.log('direction: ', direction);
            console.log('moveKeys: ', moveKeys);
        }
    
        handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
            this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
    
            console.log('sourceSelectedKeys: ', sourceSelectedKeys);
            console.log('targetSelectedKeys: ', targetSelectedKeys);
        }
    
        moveAllToRight = () => {
            this.setState({
            targetKeys: AllTargetKeys
            })
        }
        moveAllToLeft = () => {
            this.setState({
            targetKeys: []
            })
        }
    
        swapItems(arr, index1, index2) {
    		arr[index1] = arr.splice(index2, 1, arr[index1])[0];
    		return arr;
    	};
    
        scopeupRecord(arr, $index) {
    		if ($index == 0) {
    			return;
    		}
    		this.swapItems(arr, $index, $index - 1);
    	};
        
        scopedownRecord(arr, $index) {
    		if ($index == arr.length - 1) {
    			return;
    		}
    		this.swapItems(arr, $index, $index + 1);
    	};
    
        moveUp = () => {
            let { targetKeys, selectedKeys } = this.state
    		let selectedTargetKeys = []
    		targetKeys.forEach((v, i) => {
    			selectedKeys.forEach((v2, i2) => {
    				if (v2 == v) {
    					selectedTargetKeys.push({ key: v, index: i })
    				}
    			})
    		})
    		if (selectedTargetKeys.length == 1) {
    			this.scopeupRecord(targetKeys, selectedTargetKeys[0].index)
    			this.setState({
    				targetKeys
    			});
    		}
        }
    
        moveDown = () => {
            let { targetKeys, selectedKeys } = this.state
    		let selectedTargetKeys = []
    		targetKeys.forEach((v, i) => {
    			selectedKeys.forEach((v2, i2) => {
    				if (v2 == v) {
    					selectedTargetKeys.push({ key: v, index: i })
    				}
    			})
    		})
    		console.log(targetKeys, selectedKeys, selectedTargetKeys)
    		if (selectedTargetKeys.length == 1) {
    			this.scopedownRecord(targetKeys, selectedTargetKeys[0].index)
    			this.setState({
    				targetKeys
    			});
    		}
        }
    
        render() {
            const state = this.state;
            const targetKeys = [...this.state.targetKeys];
            return (
            <div className="demo7">
                <Button onClick={this.moveUp} size="sm" className="moveUpBtn moveBtn"><Icon type="uf-arrow-up" /></Button>
                <Button onClick={this.moveDown} size="sm" className="moveDownBtn moveBtn"><Icon type="uf-arrow-down" /></Button>
                <Transfer
                appendToBottom={true}
                dataSource={mockData}
                titles={['Source', 'Target']}
                targetKeys={targetKeys}
                selectedKeys={state.selectedKeys}
                onChange={this.handleChange}
                onSelectChange={this.handleSelectChange}
                render={item => item.title}
                />
            </div>
            );
        }
    }
    
    
    export default Demo7
    
    SCSS代码
    .demo7{
        width: 476px;
        position: relative;
        .moveBtn{
            position: absolute;
            right: 0;
            margin: 8px;
            min-width: 40px;
            z-index: 10;
            color: #86939E;
            cursor: pointer;
            &.moveUpBtn{
                margin-top: 69px;
            }
            &.moveDownBtn{
                margin-top: 100px;
            }
        }
    }
    树穿梭
    JS代码
    /**
    *
    * @title 树穿梭
    * @description 结合 Tree 和 Transfer 的使用示例,解决多级数据穿梭问题。
    *
    */
    
    
    import React, { Component } from 'react';
    import { Tree, Transfer } from 'tinper-bee';
    
    
    
    const TreeNode = Tree.TreeNode;
    const valueField = "refcode";
    const AllTargetKeys = [];
    
    const treeData = [{"children":[{"children":[],"pid":"lkp","refpk":"857c41b7-e1a3-11e5-aa70-0242ac11001d","refcode":"wujd","id":"wujd","isLeaf":"true","refname":"开发部"},{"children":[],"pid":"lkp","refpk":"780aca16-e1a3-11e5-aa70-0242ac11001d","refcode":"fzl","id":"fzl","isLeaf":"true","refname":"人事部"}],"pid":"","refpk":"708918f5-e1a3-11e5-aa70-0242ac11001d","refcode":"lkp","id":"lkp","refname":"总公司"}];
    
    class Demo8 extends React.Component {
        constructor(props){
            super(props);
            this.state = {
                targetKeys: [],
                selectedKeys: [],
                expandedKeys: [],//记录展开节点
                searchValue: '',//记录搜索内容
                autoExpandParent: true,
                dataList: [],
                transferData : [{"rownum_":1,"login_name":"43","name":"花43","refcode":"43","refpk":"718dda50629e4f8a8833b5d17de85280","id":"718dda50629e4f8a8833b5d17de85280","refname":"花43","key":"43","title":"花43-43"},{"rownum_":2,"login_name":"46","name":"花46","refcode":"46","refpk":"b595b95cf45348d7aadb7ae349a89a76","id":"b595b95cf45348d7aadb7ae349a89a76","refname":"花46","key":"46","title":"花46-46"},{"rownum_":3,"login_name":"48","name":"花48","refcode":"48","refpk":"62310dd3677440ef96042b9c3ad135e2","id":"62310dd3677440ef96042b9c3ad135e2","refname":"花48","key":"48","title":"花48-48"},{"rownum_":4,"login_name":"53","name":"花53","refcode":"53","refpk":"d64f7d6e6d014d40841415cd35a43dcf","id":"d64f7d6e6d014d40841415cd35a43dcf","refname":"花53","key":"53","title":"花53-53"},{"rownum_":5,"login_name":"70","name":"花70","refcode":"70","refpk":"2ff33db8d1e94bcbaf9ba45e1ad6ea9c","id":"2ff33db8d1e94bcbaf9ba45e1ad6ea9c","refname":"花70","key":"70","title":"花70-70"},{"rownum_":6,"login_name":"73","name":"花73","refcode":"73","refpk":"6d8328debfc94d5b8446f58d2b0b3cdc","id":"6d8328debfc94d5b8446f58d2b0b3cdc","refname":"花73","key":"73","title":"花73-73"},{"rownum_":7,"login_name":"76","name":"花76","refcode":"76","refpk":"7768b51dc14544669f2cffa840edb049","id":"7768b51dc14544669f2cffa840edb049","refname":"花76","key":"76","title":"花76-76"},{"rownum_":8,"login_name":"80","name":"花80","refcode":"80","refpk":"a89cc45ed1ec49f19bb608c18c958359","id":"a89cc45ed1ec49f19bb608c18c958359","refname":"花80","key":"80","title":"花80-80"},{"rownum_":9,"login_name":"78","name":"花78","refcode":"78","refpk":"438d0cce9ae442e586940a582c7ee054","id":"438d0cce9ae442e586940a582c7ee054","refname":"花78","key":"78","title":"花78-78"},{"rownum_":10,"login_name":"79","name":"花79","refcode":"79","refpk":"60adbcb7d4cb49449bc7879dd4fbf1f5","id":"60adbcb7d4cb49449bc7879dd4fbf1f5","refname":"花79","key":"79","title":"花79-79"},{"login_name":"zhao","refpk":"14e0220f-1a86-4861-8f74-f7134cb3235b","id":"14e0220f-1a86-4861-8f74-f7134cb3235b","refcode":"zhao","name":"赵宇","refname":"赵宇","key":"zhao","title":"赵宇-zhao"},{"login_name":"chen","refpk":"14e0220f-1a86-4861-8f74-f71343333b5b","id":"14e0220f-1a86-4861-8f74-f71343333b5b","refcode":"chen","name":"陈辉","refname":"陈辉","key":"chen","title":"陈辉-chen"},{"login_name":"yue","refpk":"14e0220f-1a86-4861-8f74-545454547489","id":"14e0220f-1a86-4861-8f74-545454547489","refcode":"yue","name":"岳明","refname":"岳明","key":"yue","title":"岳明-yue"},{"login_name":"xiao","refpk":"14e0220f-1a86-4861-8f74-543434537379","id":"14e0220f-1a86-4861-8f74-543434537379","refcode":"xiao","name":"小羽","refname":"小羽","key":"xiao","title":"小羽-xiao"},{"login_name":"123","refpk":"14e0220f-1a86-4861-8f74-334455643336","id":"14e0220f-1a86-4861-8f74-334455643336","refcode":"123","name":"123","refname":"123","key":"123","title":"123-123"},{"login_name":"huang","refpk":"14e0220f-1a86-4861-8f74-333387127390","id":"14e0220f-1a86-4861-8f74-333387127390","refcode":"huang","name":"黄东东","refname":"黄东东","key":"huang","title":"黄东东-huang"},{"login_name":"liu","refpk":"14e0220f-1a86-4861-8f74-3332332kjffo","id":"14e0220f-1a86-4861-8f74-3332332kjffo","refcode":"liu","name":"刘志鹏","refname":"刘志鹏","key":"liu","title":"刘志鹏-liu"},{"login_name":"liukunlin","refpk":"14e0220f-1a86-4861-8f74-23323e321263","id":"14e0220f-1a86-4861-8f74-23323e321263","refcode":"liukunlin","name":"刘坤琳","refname":"刘坤琳","key":"liukunlin","title":"刘坤琳-liukunlin"}]
            }
            this.transferData = [{"rownum_":1,"login_name":"43","name":"花43","refcode":"43","refpk":"718dda50629e4f8a8833b5d17de85280","id":"718dda50629e4f8a8833b5d17de85280","refname":"花43","key":"43","title":"花43-43"},{"rownum_":2,"login_name":"46","name":"花46","refcode":"46","refpk":"b595b95cf45348d7aadb7ae349a89a76","id":"b595b95cf45348d7aadb7ae349a89a76","refname":"花46","key":"46","title":"花46-46"},{"rownum_":3,"login_name":"48","name":"花48","refcode":"48","refpk":"62310dd3677440ef96042b9c3ad135e2","id":"62310dd3677440ef96042b9c3ad135e2","refname":"花48","key":"48","title":"花48-48"},{"rownum_":4,"login_name":"53","name":"花53","refcode":"53","refpk":"d64f7d6e6d014d40841415cd35a43dcf","id":"d64f7d6e6d014d40841415cd35a43dcf","refname":"花53","key":"53","title":"花53-53"},{"rownum_":5,"login_name":"70","name":"花70","refcode":"70","refpk":"2ff33db8d1e94bcbaf9ba45e1ad6ea9c","id":"2ff33db8d1e94bcbaf9ba45e1ad6ea9c","refname":"花70","key":"70","title":"花70-70"},{"rownum_":6,"login_name":"73","name":"花73","refcode":"73","refpk":"6d8328debfc94d5b8446f58d2b0b3cdc","id":"6d8328debfc94d5b8446f58d2b0b3cdc","refname":"花73","key":"73","title":"花73-73"},{"rownum_":7,"login_name":"76","name":"花76","refcode":"76","refpk":"7768b51dc14544669f2cffa840edb049","id":"7768b51dc14544669f2cffa840edb049","refname":"花76","key":"76","title":"花76-76"},{"rownum_":8,"login_name":"80","name":"花80","refcode":"80","refpk":"a89cc45ed1ec49f19bb608c18c958359","id":"a89cc45ed1ec49f19bb608c18c958359","refname":"花80","key":"80","title":"花80-80"},{"rownum_":9,"login_name":"78","name":"花78","refcode":"78","refpk":"438d0cce9ae442e586940a582c7ee054","id":"438d0cce9ae442e586940a582c7ee054","refname":"花78","key":"78","title":"花78-78"},{"rownum_":10,"login_name":"79","name":"花79","refcode":"79","refpk":"60adbcb7d4cb49449bc7879dd4fbf1f5","id":"60adbcb7d4cb49449bc7879dd4fbf1f5","refname":"花79","key":"79","title":"花79-79"},{"login_name":"zhao","refpk":"14e0220f-1a86-4861-8f74-f7134cb3235b","id":"14e0220f-1a86-4861-8f74-f7134cb3235b","refcode":"zhao","name":"赵宇","refname":"赵宇","key":"zhao","title":"赵宇-zhao"},{"login_name":"chen","refpk":"14e0220f-1a86-4861-8f74-f71343333b5b","id":"14e0220f-1a86-4861-8f74-f71343333b5b","refcode":"chen","name":"陈辉","refname":"陈辉","key":"chen","title":"陈辉-chen"},{"login_name":"yue","refpk":"14e0220f-1a86-4861-8f74-545454547489","id":"14e0220f-1a86-4861-8f74-545454547489","refcode":"yue","name":"岳明","refname":"岳明","key":"yue","title":"岳明-yue"},{"login_name":"xiao","refpk":"14e0220f-1a86-4861-8f74-543434537379","id":"14e0220f-1a86-4861-8f74-543434537379","refcode":"xiao","name":"小羽","refname":"小羽","key":"xiao","title":"小羽-xiao"},{"login_name":"123","refpk":"14e0220f-1a86-4861-8f74-334455643336","id":"14e0220f-1a86-4861-8f74-334455643336","refcode":"123","name":"123","refname":"123","key":"123","title":"123-123"},{"login_name":"huang","refpk":"14e0220f-1a86-4861-8f74-333387127390","id":"14e0220f-1a86-4861-8f74-333387127390","refcode":"huang","name":"黄东东","refname":"黄东东","key":"huang","title":"黄东东-huang"},{"login_name":"liu","refpk":"14e0220f-1a86-4861-8f74-3332332kjffo","id":"14e0220f-1a86-4861-8f74-3332332kjffo","refcode":"liu","name":"刘志鹏","refname":"刘志鹏","key":"liu","title":"刘志鹏-liu"},{"login_name":"liukunlin","refpk":"14e0220f-1a86-4861-8f74-23323e321263","id":"14e0220f-1a86-4861-8f74-23323e321263","refcode":"liukunlin","name":"刘坤琳","refname":"刘坤琳","key":"liukunlin","title":"刘坤琳-liukunlin"}];
        }
        componentWillReceiveProps(nextProps) {
    		const dataList = [];
    		const generateList = (data) => {
    			for (let i = 0; i < data.length; i++) {
    				const node = data[i];
    				const key = node[valueField];
    				const title = node.refname;
    				dataList.push({
    					key,
    					title
    				});
    				if (node.children) {
    					generateList(node.children, node.key);
    				}
    			}
    		};
    		generateList(nextProps.data);
    		this.setState({
    			dataList
    		})
    	}
    
        handleTransferChange = (nextTargetKeys, direction, moveKeys) => {
            this.setState({ targetKeys: nextTargetKeys });
    
            console.log('targetKeys: ', nextTargetKeys);
            console.log('direction: ', direction);
            console.log('moveKeys: ', moveKeys);
        }
    
        handleTransferSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
            this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
        
            console.log('sourceSelectedKeys: ', sourceSelectedKeys);
            console.log('targetSelectedKeys: ', targetSelectedKeys);
        }
    
        handleTreeSelect = (selectNode = {}) => {
            let {targetKeys,transferData}  = this.state;
            let startFlag,endFlag;
            if(selectNode.refcode==="fzl"){
                startFlag = 10;
                endFlag = 18
            }else if(selectNode.refcode === 'wujd'){
                startFlag = 0;
                endFlag = 10;
            }else{
                startFlag=0;
                endFlag=18;
            }
            let selectedData = this.transferData.filter(v => {
    			return targetKeys.some(key => key == v['refcode'])
    		});
    		let temp = this.transferData.slice(startFlag,endFlag)
            let tempTransferData = temp.concat(selectedData);
            console.log('=====',targetKeys,'=====')
    		this.setState({
    			transferData:tempTransferData,
    		});
    	}
    
        onTreeSelect = (selectedKeys, e) => {
    		if (selectedKeys.length === 0) {
    			return
    		}
    		var fullInfo = {};
    		const loopSearch = (arr, key) => {
    			if (!arr) { return }
    			for (let i = 0; i < arr.length; i++) {
    				if (arr[i][valueField] == key) {
    					fullInfo = arr[i];
    				} else {
    					loopSearch(arr[i].children, key)
    				}
    			}
    		}
            loopSearch(treeData, selectedKeys[0])
    		this.handleTreeSelect(fullInfo)
        }
        
        onExpand = (expandedKeys) => {
            this.setState({
                expandedKeys,
                autoExpandParent: false,
            });
        }
    
        render() {
            const {
                selectedKeys,
    			expandedKeys,
                autoExpandParent,
                transferData,
                targetKeys
    		} = this.state;
            const loop = treeData => treeData.map((item) => {
                if (item.children && item.children.length > 0) {
                    return (
                        <TreeNode key={item[valueField]} title={item.refname}>
                            {loop(item.children)}
                        </TreeNode>
                    );
                }
                return <TreeNode key={item[valueField]} title={item.refname} isLeaf={true} />;
            });
            return (
            <div className="demo8">
                <Tree
                    checkStrictly={false}
                    multiple={false}
                    onExpand={this.onExpand}
                    defaultExpandAll={true}
                    expandedKeys={expandedKeys}
                    autoExpandParent={autoExpandParent}
                    onSelect={this.onTreeSelect}
                >
                    {loop(treeData)}
                </Tree>
                <Transfer
                dataSource={transferData}
                targetKeys={targetKeys}
                selectedKeys={selectedKeys}
                onChange={this.handleTransferChange}
                onSelectChange={this.handleTransferSelectChange}
                render={item => item.title}
                />
            </div>
            );
        }
    }
    
    
    export default Demo8
    
    SCSS代码
    .demo8{
        .u-tree{
            max-width: 220px;
            display: inline-block;
            vertical-align: top;
            width: 220px;
            max-height: 525px;
            box-sizing: border-box;
            text-align: left;
        }
        .u-transfer{
            display: inline-block;
            vertical-align: top;
            width: calc(100% - 235px);
            max-height: 525px;
            box-sizing: border-box;
            text-align: left;
            overflow: auto;
        }
    }