Transfer 穿梭框
如果项目中使用的是 0.x 版本的基础组件(@icedesign/base, @ali/ice, @alife/next),请在左侧导航顶部切换组件版本。
安装方法
- 在命令行中执行以下命令
npm install @alifd/next@latest -S
开发指南
何时使用
用直观的方式在两栏中移动元素,完成选择行为。
API
Transfer
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
mode | 移动选项模式可选值:'normal', 'simple' | Enum | 'normal' |
dataSource | 数据源 | Array<Object> | [] |
value | (用于受控)当前值 | Array<String> | - |
defaultValue | (用于非受控)初始值 | Array<String> | [] |
onChange | 值发生改变的时候触发的回调函数签名:Function(value: Array, data: Array, extra: Object) => void参数:value: {Array} 右面板值data: {Array} 右面板数据extra: {Object} 额外参数extra.leftValue: {Array} 左面板值extra.leftData: {Array} 左面板数据extra.movedValue: {Array} 发生移动的值extra.movedData: {Object} 发生移动的数据extra.direction: {String} 移动的方向,值为'left'或'right' | Function | - |
disabled | 是否禁用 | Boolean | false |
leftDisabled | 是否禁用左侧面板 | Boolean | false |
rightDisabled | 是否禁用右侧面板 | Boolean | false |
itemRender | 列表项渲染函数签名:Function(data: Object) => ReactNode参数:data: {Object} 数据返回值:{ReactNode} 列表项内容 | Function | data => data.label |
showSearch | 是否显示搜索框 | Boolean | false |
filter | 自定义搜索函数签名:Function(searchedValue: String, data: Object) => Boolean参数:searchedValue: {String} 搜索的内容data: {Object} 数据返回值:{Boolean} 是否匹配到 | Function | 根据 label 属性匹配 |
onSearch | 搜索框输入时触发的回调函数签名:Function(searchedValue: String, position: String) => void参数:searchedValue: {String} 搜索的内容position: {String} 搜索面板的位置 | Function | () => {} |
searchPlaceholder | 搜索框占位符 | String | - |
notFoundContent | 列表为空显示内容 | ReactNode | 'Not Found' |
titles | 左右面板标题 | Array<ReactNode> | [] |
operations | 向右向左移动按钮显示内容 | Array<ReactNode> | < |
defaultLeftChecked | 左面板默认选中值 | Array<String> | [] |
defaultRightChecked | 右面板默认选中值 | Array<String> | [] |
listClassName | 左右面板列表自定义样式类名 | String | - |
listStyle | 左右面板列表自定义样式对象 | Object | - |
sortable | 是否允许拖拽排序 | Boolean | false |
onSort | 拖拽排序时触发的回调函数签名:Function(value: Array, position: String) => void参数:value: {Array} 排序后的值position: {String} 拖拽的面板位置,值为:left 或 right | Function | () => {} |
id | 请设置 id 以保证transfer的可访问性 | String | - |
ARIA and KeyBoard
按键 | 说明 |
---|---|
Up Arrow | 获取当前项的前一项焦点 |
Down Arrow | 获取当前项的后一项焦点 |
Enter | 当前列表选中的项移动到另一个列表 |
SPACE | 选择/取消当前项或当前列表选中的项移动到另一个列表 |
代码示例
最简单的用法。
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return (
<Transfer defaultValue={['3']} dataSource={dataSource} defaultLeftChecked={['1']} onChange={this.handleChange} titles={['Title', 'Title']} />
);
}
}
ReactDOM.render(<Demo />, mountNode);
展示受控的用法。
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: ['3']
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
this.setState({
value
});
}
render() {
return <Transfer value={this.state.value} dataSource={dataSource} defaultLeftChecked={['1']} onChange={this.handleChange} titles={['Title', 'Title']} />;
}
}
ReactDOM.render(<Demo />, mountNode);
通过设置 mode 为 'simple',可以开启简单模式,点击选项即移动。
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return <Transfer mode="simple" defaultValue={['3']} dataSource={dataSource} defaultLeftChecked={['1']} onChange={this.handleChange} titles={['Simple Mode', 'Simple Mode']} />;
}
}
ReactDOM.render(<Demo />, mountNode);
展示搜索的用法。
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return <Transfer showSearch defaultValue={['3']} dataSource={dataSource} defaultLeftChecked={['1']} onChange={this.handleChange} titles={['Searchable', 'Searchable']} />;
}
}
ReactDOM.render(<Demo />, mountNode);
设置 sortable 属性为 true 后,可拖拽排序左右面板。
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleSort = this.handleSort.bind(this);
}
handleSort(value, position) {
console.log(value, position);
}
render() {
return <Transfer sortable defaultValue={['3']} dataSource={dataSource} onSort={this.handleSort} titles={['Sortable', 'Sortable']} />;
}
}
ReactDOM.render(<Demo />, mountNode);
展示自定义样式的用法。
查看源码在线预览
import { Transfer, Button } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: i % 3 === 0 ? `content${i}contentcontentcontentcontentcontent` : `content${i}`,
value: `${i}`,
disabled: i % 4 === 0
});
}
return dataSource;
})();
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return (
<Transfer
defaultValue={['3']}
dataSource={dataSource}
listStyle={{ width: '200px', height: '192px' }}
defaultLeftChecked={['1']}
onChange={this.handleChange}
titles={[<Button key='left' type='primary'>Source</Button>, 'Target']}
operations={['>>', '<<']} />
);
}
}
ReactDOM.render(<Demo />, mountNode);
通过设置locale
去修改对无障碍支持,默认已经设置,请参考ARIA and KeyBoard
。为保证可访问性,需要设置全局唯一的id
查看源码在线预览
import { Transfer } from '@alifd/next';
const dataSource = (() => {
const dataSource = [];
for (let i = 0; i < 10; i++) {
dataSource.push({
label: `content${i}`,
value: `${i}`,
});
}
return dataSource;
})();
const obj = {
items: '项',
item: '项',
moveAll: '移动全部',
searchPlaceholder: '请输入',
moveToLeft: '撤销选中元素',
moveToRight: '提交选中元素'
};
class Demo extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(value, data, extra) {
console.log(value, data, extra);
}
render() {
return (
<Transfer id="a11y-transfer" defaultValue={['2']} dataSource={dataSource} defaultLeftChecked={['1']} locale={obj} onChange={this.handleChange} titles={['Title', 'Title']} />
);
}
}
ReactDOM.render(<Demo />, mountNode);