Transfer穿梭框

双栏穿梭选择框。

何时使用#

  • 需要在多个可选项中进行多选时。

  • 比起 Select 和 TreeSelect,穿梭框占据更大的空间,可以展示可选项的更多信息。

穿梭选择框用直观的方式在两栏中移动元素,完成选择行为。

选择一个或以上的选项后,点击对应的方向键,可以把选中的选项移动到另一栏。 其中,左边一栏为 source,右边一栏为 target,API 的设计也反映了这两个概念。

代码演示

14 Source
6 Target

最基本的用法,展示了 dataSourcetargetKeys、每行的渲染函数 render 以及回调函数 onChange onSelectChange onScroll 的用法。

expand codeexpand code
import { Transfer, Switch } from 'antd';

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 oriTargetKeys = mockData
  .filter(item => +item.key % 3 > 1)
  .map(item => item.key);

class App extends React.Component {
  state = {
    targetKeys: oriTargetKeys,
    selectedKeys: [],
    disabled: false,
  }

  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);
  }

  handleDisable = (disabled) => {
    this.setState({ disabled });
  };

  render() {
    const { targetKeys, selectedKeys, disabled } = this.state;
    return (
      <div>
        <Transfer
          dataSource={mockData}
          titles={['Source', 'Target']}
          targetKeys={targetKeys}
          selectedKeys={selectedKeys}
          onChange={this.handleChange}
          onSelectChange={this.handleSelectChange}
          onScroll={this.handleScroll}
          render={item => item.title}
          disabled={disabled}
        />
        <Switch
          unCheckedChildren="disabled"
          checkedChildren="disabled"
          checked={disabled}
          onChange={this.handleDisable}
          style={{ marginTop: 16 }}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

穿梭框高级用法,可配置操作文案,可定制宽高,可对底部进行自定义渲染。

expand codeexpand code
import { Transfer, Button } from 'antd';

class App 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 = () => (
    <Button
      size="small"
      style={{ float: 'right', margin: 5 }}
      onClick={this.getMock}
    >
        reload
    </Button>
  )

  render() {
    return (
      <Transfer
        dataSource={this.state.mockData}
        showSearch
        listStyle={{
          width: 250,
          height: 300,
        }}
        operations={['to right', 'to left']}
        targetKeys={this.state.targetKeys}
        onChange={this.handleChange}
        render={item => `${item.title}-${item.description}`}
        footer={this.renderFooter}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);
0
暂无数据

暂无数据

0
暂无数据

暂无数据

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

expand codeexpand code
import { Transfer } from 'antd';

class App 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, direction, moveKeys) => {
    console.log(targetKeys, direction, moveKeys);
    this.setState({ targetKeys });
  }

  renderItem = (item) => {
    const customLabel = (
      <span className="custom-item">
        {item.title} - {item.description}
      </span>
    );

    return {
      label: customLabel, // for displayed item
      value: item.title, // for title and filter matching
    };
  }

  render() {
    return (
      <Transfer
        dataSource={this.state.mockData}
        listStyle={{
          width: 300,
          height: 300,
        }}
        targetKeys={this.state.targetKeys}
        onChange={this.handleChange}
        render={this.renderItem}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);

API#

参数说明类型默认值
className自定义类string
dataSource数据源,其中的数据将会被渲染到左边一栏中,targetKeys 中指定的除外。TransferItem[][]
disabled是否禁用booleanfalse
filterOption接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false(inputValue, option): boolean
footer底部渲染函数(props): ReactNode
lazyTransfer 使用了 react-lazy-load 优化性能,这里可以设置相关参数。设为 false 可以关闭懒加载。object|boolean{ height: 32, offset: 32 }
listStyle两个穿梭框的自定义样式object
locale各种语言object{ itemUnit: '项', itemsUnit: '项', notFoundContent: '列表为空', searchPlaceholder: '请输入搜索内容' }
operations操作文案集合,顺序从上至下string[]['>', '<']
render每行数据渲染函数,该函数的入参为 dataSource 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 label 字段为 ReactElement,value 字段为 titleFunction(record)
selectedKeys设置哪些项应该被选中string[][]
showSearch是否显示搜索框booleanfalse
targetKeys显示在右侧框数据的key集合string[][]
titles标题集合,顺序从左至右string[]['', '']
onChange选项在两栏之间转移时的回调函数(targetKeys, direction, moveKeys): void
onScroll选项列表滚动时的回调函数(direction, event): void
onSearch搜索框内容时改变时的回调函数(direction: 'left'|'right', value: string): void-
onSelectChange选中项发生改变时的回调函数(sourceSelectedKeys, targetSelectedKeys): void

注意#

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

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

// 比如你的数据主键是 uid
return <Transfer rowKey={record => record.uid} />;
Switch开关TimePicker时间选择框