Select 选择器

如果项目中使用的是 0.x 版本的基础组件(@icedesign/base, @ali/ice, @alife/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @alifd/next@latest -S

Guide

何时使用

Select

如果你不期望用户输入的值生效而仅仅是选择,那么使用 Select. 同时可以使用 Select 的 showSearch 属性进行过滤。

AutoComplete

AutoComplete 会保留用户输入的值,本质上是 Input 组件,扩展了 autocomplete 的能力,所以 Input 组件的属性可以直接透传。

常见问题

出现类似的

Select 默认使用 value 作为菜单项的 key,如果没有设置 key 值,则使用默认的序列 index 作为 key 值,确保这些值不会发生重复。

dataSource的使用

Select 同时支持 children 和在 props 中传入 dataSource 作为数据源, 如果同时设置, 则以 children 为准.

注意:1. Select 默认使用 value 作为渲染的菜单项的 key 值,所以 value 不能重复, 否则无法渲染下拉菜单。2. value 不允许出现 null/undefined/object/array 类型数值

  • children的方式
  1. <Select>
  2. <Select.Option value="option1">option1</Select.Option>
  3. <Select.Option value="option2">option2</Select.Option>
  4. <Select.Option disabled>disabled</Select.Option>
  5. </Select>;
  • props的方式
  1. const dataSource = [
  2. {label:'option1', value:'option1'},
  3. {label:'option2', value:'option2'},
  4. {label:'disabled', disabled:true}
  5. ];
  6. <Select dataSource={dataSource}/>

定制弹出层

参见示例中的 弹层定制。唯一需要注意的是 overlay 的元素记得透传 props.这是因为 Overlay 的弹层的动画是依靠 className 实现的,如果不透传 props 则会造成无法监听到动画播放结束的事件。

API

Select

参数说明类型默认值
size选择器尺寸可选值:'small', 'medium', 'large'Enum'medium'
value当前值,用于受控模式any-
defaultValue初始的默认值any-
placeholder没有值的时候的占位符String-
autoWidth下拉菜单是否与选择器对齐Booleantrue
label自定义内联 labelReactNode-
hasClear是否有清除按钮(单选模式有效)Boolean-
state校验状态可选值:'error', 'loading'Enum-
readOnly是否只读,只读模式下可以展开弹层但不能选Boolean-
disabled是否禁用选择器Boolean-
visible当前弹层是否显示Boolean-
defaultVisible弹层初始化是否显示Boolean-
onVisibleChange弹层显示或隐藏时触发的回调签名:Function(visible: Boolean, type: String) => void参数:visible: {Boolean} 弹层是否显示type: {String} 触发弹层显示或隐藏的来源 fromContent 表示由Dropdown内容触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发Functionfunc.noop
popupContainer弹层挂载的容器节点String/Function-
popupClassName弹层的 classNameany-
popupStyle弹层的内联样式Object-
popupProps添加到弹层上的属性Object{}
followTrigger是否跟随滚动Boolean-
popupContent自定义弹层的内容ReactNode-
filterLocal是否使用本地过滤,在数据源为远程的时候需要关闭此项Booleantrue
filter本地过滤方法,返回一个 Boolean 值确定是否保留签名:Function() => voidFunctionfilter
onToggleHighlightItem键盘上下键切换菜单高亮选项的回调签名:Function() => voidFunctionfunc.noop
useVirtual是否开启虚拟滚动模式Boolean-
dataSource传入的数据源,可以动态渲染子项,详见 dataSource的使用Array<Object/Boolean/Number/String>-
itemRender渲染 MenuItem 内容的方法签名:Function(item: Object, searchValue: String) => ReactNode参数:item: {Object} 渲染节点的itemsearchValue: {String} 搜索关键字(如果开启搜索)返回值:{ReactNode} item nodeFunction-
mode选择器模式可选值:'single', 'multiple', 'tag'Enum'single'
notFoundContent弹层内容为空的文案ReactNode-
onChangeSelect发生改变时触发的回调签名:Function(value: mixed, actionType: String, item: mixed) => void参数:value: {mixed} 选中的值actionType: {String} 触发的方式, 'itemClick', 'enter', 'tag'item: {mixed} 选中的值的对象数据 (useDetailValue=false有效)Function-
hasBorder是否有边框Boolean-
hasArrow是否有下拉箭头Booleantrue
showSearch展开后是否能搜索(tag 模式下固定为true)Booleanfalse
onSearch当搜索框值变化时回调签名:Function(value: String) => void参数:value: {String} 数据Functionfunc.noop
onSearchClear当搜索框值被清空时候的回调签名:Function(actionType: String) => void参数:actionType: {String} 触发的方式, 'select'(选择清空), 'popupClose'(弹窗关闭清空)Functionfunc.noop
hasSelectAll多选模式下是否有全选功能Boolean/String-
fillProps填充到选择框里的值的 keyString-
useDetailValueonChange 返回的 value 使用 dataSource 的对象Boolean-
cacheValuedataSource 变化的时是否保留已选的内容Booleantrue
valueRender渲染 Select 展现内容的方法签名:Function(item: Object) => ReactNode参数:item: {Object} 渲染节点的item返回值:{ReactNode} 展现内容Functionitem => item.label || item.value
searchValue受控搜索值,一般不需要设置String-
tagInline是否一行显示,仅在 mode 为 multiple 的时候生效Booleanfalse
maxTagCount最多显示多少个 tagNumber-
maxTagPlaceholder隐藏多余 tag 时显示的内容,在 maxTagCount 生效时起作用签名:Function(selectedValues: number, totalValues: number) => void参数:selectedValues: {number} 当前已选中的元素totalValues: {number} 总待选元素Function-
hiddenSelected选择后是否立即隐藏菜单 (mode=multiple/tag 模式生效)Boolean-
onRemovetag 删除回调签名:Function(item: object) => void参数:item: {object} 渲染节点的itemFunctionfunc.noop
onFocus焦点事件签名:Function() => voidFunctionfunc.noop
onBlur失去焦点事件签名:Function() => voidFunctionfunc.noop

Select.AutoComplete

参数说明类型默认值
size选择器尺寸可选值:'small', 'medium', 'large'Enum'medium'
value当前值,用于受控模式String/Number-
defaultValue初始化的默认值String/Number-
placeholder没有值的时候的占位符String-
autoWidth下拉菜单是否与选择器对齐Booleantrue
label自定义内联 labelReactNode-
hasClear是否有清除按钮(单选模式有效)Boolean-
state校验状态可选值:'error', 'loading'Enum-
readOnly是否只读,只读模式下可以展开弹层但不能选Boolean-
disabled是否禁用选择器Boolean-
visible当前弹层是否显示Boolean-
defaultVisible弹层初始化是否显示Boolean-
onVisibleChange弹层显示或隐藏时触发的回调签名:Function(visible: Boolean, type: String) => void参数:visible: {Boolean} 弹层是否显示type: {String} 触发弹层显示或隐藏的来源 fromContent 表示由Dropdown内容触发; fromTrigger 表示由trigger的点击触发; docClick 表示由document的点击触发Functionfunc.noop
popupContainer弹层挂载的容器节点String/Function-
popupClassName弹层的 classNameany-
popupStyle弹层的内联样式Object-
popupProps添加到弹层上的属性Object{}
followTrigger是否跟随滚动Boolean-
popupContent自定义弹层的内容ReactNode-
filterLocal是否使用本地过滤,在数据源为远程的时候需要关闭此项Booleantrue
filter本地过滤方法,返回一个 Boolean 值确定是否保留签名:Function() => voidFunctionfilter
onToggleHighlightItem键盘上下键切换菜单高亮选项的回调签名:Function() => voidFunctionfunc.noop
useVirtual是否开启虚拟滚动模式Boolean-
dataSource传入的数据源,可以动态渲染子项Array<Object/String>-
itemRender渲染 MenuItem 内容的方法签名:Function(item: Object) => ReactNode参数:item: {Object} 渲染节点的 item返回值:{ReactNode} item nodeFunction-
onChangeSelect发生改变时触发的回调签名:Function(value: mixed, actionType: String, item: mixed) => void参数:value: {mixed} 选中的值actionType: {String} 触发的方式, 'itemClick', 'enter', 'change'item: {mixed} 选中的值的对象数据Function-
fillProps填充到选择框里的值的 key,默认是 valueString'value'

Select.OptionGroup

参数说明类型默认值
label设置分组的文案ReactNode-

Select.Option

参数说明类型默认值
value选项值any-
disabled是否禁用Boolean-

ARIA and KeyBoard

按键说明
Up Arrow获取当前项前一项焦点
Down Arrow获取当前项后一项焦点
Enter打开列表或选择当前项
Esc关闭列表

代码示例

基本使用

简单

Select 选择器 - 图1

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const Option = Select.Option;
  3. const onChange = function (value) {
  4. console.log(value);
  5. };
  6. const onBlur = function (e) {
  7. console.log(/onblur/,e);
  8. };
  9. const onToggleHighlightItem = function (item, type) {
  10. console.log(item, type);
  11. };
  12. ReactDOM.render(<Select id="basic-demo" onChange={onChange} onBlur={onBlur} onToggleHighlightItem={onToggleHighlightItem} defaultValue="jack" aria-label="name is" showSearch hasClear>
  13. <Option value="jack">Jack</Option>
  14. <Option value="frank">Frank</Option>
  15. <Option value="hugo">Hugo</Option>
  16. </Select>, mountNode);

标签

标签模式,输入的内容可以作为选项

Select 选择器 - 图2

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {value: '10001', label: 'Lucy King'},
  4. {value: 10002, label: 'Lily King'},
  5. {value: 10003, label: 'Tom Cat', disabled: true},
  6. {label: 'Special Group', children: [
  7. {value: -1, label: 'FALSE'},
  8. {value: 0, label: 'ZERO'}
  9. ]}
  10. ];
  11. function handleChange(value) {
  12. console.log(value);
  13. }
  14. ReactDOM.render(<Select aria-label="tag mode" mode="tag" defaultValue={['10001']} onChange={handleChange} dataSource={dataSource} style={{width: 300}} />, mountNode);

多选

多选模式, 通过 showSearch 可以开启搜索, 但搜索值不可用作选项

Select 选择器 - 图3

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {value: '10001', label: 'Lucy King'},
  4. {value: 10002, label: 'Lily King'},
  5. {value: 10003, label: 'Tom Cat', disabled: true},
  6. {label: 'Special Group', children: [
  7. {value: -1, label: 'FALSE'},
  8. {value: 0, label: 'ZERO'}
  9. ]}
  10. ];
  11. function handleChange(value) {
  12. console.log(value);
  13. }
  14. ReactDOM.render(
  15. <div>
  16. <Select mode="multiple" showSearch defaultValue={['10001']} onChange={handleChange} dataSource={dataSource} style={{width: 300}} />
  17. </div>
  18. , mountNode);

最大数量

多选模式

Select 选择器 - 图4

查看源码在线预览

  1. import { Select, Balloon } from '@alifd/next';
  2. const { Tooltip } = Balloon;
  3. const dataSource = [
  4. {value: '10001', label: 'Lucy King'},
  5. {value: 10002, label: 'Lily King'},
  6. {value: 10003, label: 'Tom Cat', disabled: true},
  7. {label: 'Special Group', children: [
  8. {value: -1, label: 'FALSE'},
  9. {value: 0, label: 'ZERO'}
  10. ]}
  11. ];
  12. function handleChange(value) {
  13. console.log(value);
  14. }
  15. const maxTagPlaceholder = (selectedValues, totalValues) => {
  16. const trigger = <span>{`${selectedValues.length}/${totalValues.length}`}</span>;
  17. const labels = selectedValues.map(obj => obj.label);
  18. return <Tooltip trigger={trigger}>{ labels.join(', ') }</Tooltip>;
  19. };
  20. ReactDOM.render(
  21. <div>
  22. hasSelectAll:<br/>
  23. <Select hasSelectAll mode="multiple" onChange={handleChange} dataSource={dataSource} style={{width: 200}} />
  24. <br /><br />
  25. maxTagCount=2<br />
  26. <Select maxTagCount={2} defaultValue={['10001', '10002', '-1']} mode="multiple" onChange={handleChange} dataSource={dataSource} style={{width: 200}} /> <br /><br />
  27. maxTagPlaceholder<br />
  28. <Select maxTagCount={2} maxTagPlaceholder={maxTagPlaceholder} defaultValue={['10001', '10002', '-1']} mode="multiple" onChange={handleChange} dataSource={dataSource} style={{width: 200}} /><br /><br />
  29. tagInline <br />
  30. <Select maxTagCount={2} tagInline mode="multiple" defaultValue={['10001', '10002', '-1']} onChange={handleChange} dataSource={dataSource} style={{width: 200}} /><br /><br />
  31. maxTagPlaceholder<br />
  32. <Select maxTagCount={2} tagInline maxTagPlaceholder={maxTagPlaceholder} defaultValue={['10001', '10002', '-1']} mode="multiple" onChange={handleChange} dataSource={dataSource} style={{width: 200}} /><br /><br />
  33. </div>
  34. , mountNode);

级联选择

使用 Select 构建级联选择框

Select 选择器 - 图5

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const provinceData = ['Zhejiang', 'Hubei', 'Jiangsu'];
  3. const cityData = {
  4. Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
  5. Hubei: ['Wuhan', 'Yichang', 'Jingzhou'],
  6. Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang']
  7. };
  8. class Demo extends React.Component {
  9. constructor(props) {
  10. super(props);
  11. this.state = {
  12. data: [],
  13. disabled: true
  14. };
  15. this.handleProvinceChange = this.handleProvinceChange.bind(this);
  16. this.handleCityChange = this.handleCityChange.bind(this);
  17. }
  18. handleProvinceChange(value) {
  19. const data = cityData[value];
  20. this.setState({data, province: value, city: '', disabled: !data});
  21. }
  22. handleCityChange(value) {
  23. this.setState({city: value});
  24. console.log(this.state.province, value);
  25. }
  26. render() {
  27. const {data, disabled, province, city} = this.state;
  28. return (
  29. <div className="demo-container">
  30. <Select placeholder="Select Province" dataSource={provinceData} value={province} onChange={this.handleProvinceChange} />
  31. <Select placeholder="Select City" dataSource={data} value={city} onChange={this.handleCityChange} disabled={disabled}/>
  32. </div>
  33. );
  34. }
  35. }
  36. ReactDOM.render(<Demo/>, mountNode);
  1. .next-select {
  2. margin-right:10px;
  3. }
  4. .demo-container {
  5. background-color: #F8F8F8;
  6. padding: 16px;
  7. }

选择器

演示了 Select 的多种形态.

Select 选择器 - 图6

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {value: '10001', label: 'Lucy King'},
  4. {value: 10002, label: 'Lily King'},
  5. {value: 10003, label: 'Tom Cat', disabled: true},
  6. {label: 'Special Group', children: [
  7. {value: -1, label: 'FALSE'},
  8. {value: 0, label: 'ZERO'}
  9. ]}
  10. ];
  11. const ctrlDataSources = {
  12. mode: ['single', 'multiple', 'tag'],
  13. size: ['small', 'medium', 'large'],
  14. showSearch: [true, false],
  15. hasArrow: [true, false],
  16. hasBorder: [true, false],
  17. hasClear: [true, false]
  18. };
  19. class Demo extends React.Component {
  20. constructor(props) {
  21. super(props);
  22. this.state = {
  23. value: null,
  24. size: undefined,
  25. mode: undefined,
  26. hasArrow: undefined,
  27. hasBorder: undefined,
  28. showSearch: undefined,
  29. hasClear: undefined
  30. };
  31. this.handleChange = this.handleChange.bind(this);
  32. this.handleCtrlChange = this.handleCtrlChange.bind(this);
  33. }
  34. handleCtrlChange(key, value) {
  35. this.setState({[key]: value});
  36. if (key === 'mode') {
  37. this.setState({value: null});
  38. }
  39. }
  40. handleChange(value, item) {
  41. console.log('handleChange: value: ', value, item);
  42. this.setState({value});
  43. }
  44. renderCtrlNodes(state) {
  45. const ctrlNodes = [];
  46. let k;
  47. for (k in ctrlDataSources) {
  48. if (ctrlDataSources.hasOwnProperty(k)) {
  49. ctrlNodes.push(
  50. <Select key={k}
  51. label={`${k}: `}
  52. value={state[k]}
  53. id={k}
  54. dataSource={ctrlDataSources[k]}
  55. onChange={this.handleCtrlChange.bind(this, k)} />
  56. );
  57. }
  58. }
  59. return ctrlNodes;
  60. }
  61. render() {
  62. return (
  63. <div className="demo-container">
  64. <div className="demo-controller">{this.renderCtrlNodes(this.state)}</div>
  65. <Select
  66. {...this.state}
  67. onChange={this.handleChange}
  68. dataSource={dataSource} />
  69. </div>
  70. );
  71. }
  72. }
  73. ReactDOM.render(<Demo />, mountNode);
  1. .demo-container {
  2. padding: 16px;
  3. background-color: #F8F8F8;
  4. }
  5. .demo-controller {
  6. padding: 12px 12px 4px;
  7. margin-bottom: 16px;
  8. border: 2px dashed #ddd;
  9. }
  10. .next-select {
  11. margin-right: 8px;
  12. margin-bottom: 8px;
  13. }

分组

使用 OptionGroup 针对选项进行分组,也可以使用原生的 html 标签 optgroup

Select 选择器 - 图7

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const {Option, OptionGroup} = Select;
  3. const dataSource = [{
  4. label: 'label1',
  5. children: [{
  6. label: 'label1-1',
  7. value: 'text1-1'
  8. }]
  9. }, {
  10. label: 'label2',
  11. children: [{
  12. label: 'label2-1',
  13. value: 'text2-1'
  14. }]
  15. }];
  16. ReactDOM.render(
  17. <div className="demo-container">
  18. <Select placeholder="OptionGroup">
  19. <OptionGroup label="group1">
  20. <Option value="small">Small</Option>
  21. <Option value="medium">Medium</Option>
  22. <Option value="large">Large</Option>
  23. </OptionGroup>
  24. <OptionGroup label="group2">
  25. <Option value="small2">Small2</Option>
  26. <Option value="medium2">Medium2</Option>
  27. <Option value="large2">Large2</Option>
  28. </OptionGroup>
  29. </Select>
  30. <Select placeholder="optgroup">
  31. <option value="apple">Apple</option>
  32. <option value="orange">Orange</option>
  33. <option value="banana">Banana</option>
  34. <optgroup label="Pets Group">
  35. <option value="cat">Cat</option>
  36. <option value="rabbit">Rabbit</option>
  37. <option value="dog" disabled>Dog</option>
  38. </optgroup>
  39. </Select>
  40. <Select placeholder="item.children" dataSource={dataSource}/>
  41. </div>,
  42. mountNode
  43. );
  1. .next-select {
  2. margin-right:10px;
  3. }
  4. .demo-container {
  5. background-color: #F8F8F8;
  6. padding: 16px;
  7. }

自定义 value

Select 的 value 可以是任意非空类型的值,但是要保证 toString() 后是唯一的。

Select 选择器 - 图8

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {value: 'Lilith', age: 22, gender: 'F'},
  4. {value: 'Tom Cat', age: 28, gender: 'M'},
  5. {value: 'Jim Green', age: 18, gender: 'M'},
  6. {value: 'Monkey King', age: 999, gender: 'M'}
  7. ];
  8. const handleChange = value => {
  9. console.log('handleChange: ', value);
  10. };
  11. const valueRender = v => {
  12. return `${v.value} / ${v.gender} / ${v.age}`;
  13. };
  14. ReactDOM.render(<Select mode="multiple" placeholder="custom value" valueRender={valueRender} dataSource={dataSource} onChange={handleChange} />, mountNode);

搜索框

使用 showSearch 显示搜索框,如果需要动态更新 dataSource,需要关闭 filterLocal

Select 选择器 - 图9

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. import jsonp from 'jsonp';
  3. let timestamp = Date.now();
  4. class Demo extends React.Component {
  5. state = {
  6. dataSource: []
  7. }
  8. handleSearch = (value) => {
  9. if (this.searchTimeout) {
  10. clearTimeout(this.searchTimeout);
  11. }
  12. this.searchTimeout = setTimeout(() => {
  13. // eslint-disable-next-line handle-callback-err
  14. value ? jsonp(`https://suggest.taobao.com/sug?code=utf-8&q=${value}`, (err, data) => {
  15. const dataSource = data.result.map(item => ({
  16. label: item[0], value: (timestamp++).toString(36)
  17. }));
  18. this.setState({dataSource});
  19. }) : this.setState({dataSource: []});
  20. }, 100);
  21. }
  22. render() {
  23. return (
  24. <div className="demo-container">
  25. <Select showSearch placeholder="select search" filterLocal={false} dataSource={this.state.dataSource} onSearch={this.handleSearch} style={{width: 200}}/>
  26. </div>
  27. );
  28. }
  29. }
  30. ReactDOM.render(<Demo/>, mountNode);

前后缀

Select 增加前后缀

Select 选择器 - 图10

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {label: '1', value: 1},
  4. {label: '10', value: 10},
  5. {label: '50', value: 50},
  6. {label: '100', value: 100}
  7. ];
  8. const handleChange = value => {
  9. console.log('handleChange: ', value);
  10. };
  11. ReactDOM.render(<Select label="size:" innerAfter={<span style={{color: '#999', marginRight: 4}}>GB</span>} dataSource={dataSource} onChange={handleChange} />, mountNode);

对象数据

useDetailValuevalue 从字符串变成对象

Select 选择器 - 图11

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. {value: '10001', label: 'Lucy King'},
  4. {value: 10002, label: 'Lily King'},
  5. {value: 10003, label: 'Tom Cat', disabled: true},
  6. {label: 'Special Group', children: [
  7. {value: new Date(), label: 'new Date()'},
  8. {value: false, label: 'FALSE'},
  9. {value: 0, label: 'ZERO'}
  10. ]}
  11. ];
  12. function handleChange(value) {
  13. console.log(value);
  14. }
  15. ReactDOM.render(<Select useDetailValue defaultValue={{value: '10001', label: 'Lucy King'}} onChange={handleChange} dataSource={dataSource} style={{width: 150}} />, mountNode);

自动完成

AutoComplete 继承了 Input 的能力,并在其基础上增加了 autoComplete 的功能。对于设置为AutoComplete为off不生效对的情况,可以参考 MDN 中进行设置。

Select 选择器 - 图12

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const dataSource = [
  3. 'Lucy King',
  4. 'Lily King',
  5. 'Jim Green',
  6. {
  7. label: 'Chinese',
  8. children: [
  9. {value: 'Hang Meimei', label: 'Hang Meimei'},
  10. 'Li Lei',
  11. {value: 'Gao Hui', label: 'Gao Hui', disabled: true},
  12. 'Zhang San',
  13. 'Li Si',
  14. 'Wang Wu',
  15. {value: 'Zhao Benshan', label: 'Zhao Benshan', disabled: true},
  16. 'Sun Yang',
  17. 'Song Shuying'
  18. ]
  19. },
  20. {
  21. label: 'Pets',
  22. children: [
  23. 'Poly',
  24. 'Kitty'
  25. ]
  26. }
  27. ];
  28. const onChange = (v) => {
  29. console.log(v);
  30. };
  31. ReactDOM.render(<Select.AutoComplete style={{width: 300}} onChange={onChange} dataSource={dataSource} />, mountNode);

自动完成大小

AutoComplete 大小、disabled、清除

Select 选择器 - 图13

查看源码在线预览

  1. import { Select } from '@alifd/next';
  2. const {AutoComplete} = Select;
  3. const dataSource = [
  4. 'Lucy King',
  5. 'Lily King',
  6. 'Jim Green',
  7. {
  8. label: 'Chinese',
  9. children: [
  10. {value: 'Hang Meimei', label: 'Hang Meimei'},
  11. 'Li Lei',
  12. {value: 'Gao Hui', label: 'Gao Hui', disabled: true},
  13. 'Zhang San',
  14. 'Li Si',
  15. 'Wang Wu',
  16. {value: 'Zhao Benshan', label: 'Zhao Benshan', disabled: true},
  17. 'Sun Yang',
  18. 'Song Shuying'
  19. ]
  20. },
  21. {
  22. label: 'Pets',
  23. children: [
  24. 'Poly',
  25. 'Kitty'
  26. ]
  27. }
  28. ];
  29. const ctrlDataSources = {
  30. size: ['small', 'medium', 'large'],
  31. disabled: [true, false],
  32. hasClear: [true, false]
  33. };
  34. class Demo extends React.Component {
  35. constructor(props) {
  36. super(props);
  37. this.state = {
  38. value: null,
  39. size: undefined,
  40. disabled: undefined,
  41. hasClear: undefined
  42. };
  43. this.handleChange = this.handleChange.bind(this);
  44. this.handleCtrlChange = this.handleCtrlChange.bind(this);
  45. }
  46. handleCtrlChange(key, value) {
  47. this.setState({[key]: value});
  48. if (key === 'mode') {
  49. this.setState({value: null});
  50. }
  51. }
  52. handleChange(value) {
  53. console.log('handleChange: value: ', value);
  54. this.setState({value});
  55. }
  56. renderCtrlNodes(state) {
  57. const ctrlNodes = [];
  58. let k;
  59. for (k in ctrlDataSources) {
  60. if (ctrlDataSources.hasOwnProperty(k)) {
  61. ctrlNodes.push(
  62. <Select key={k}
  63. label={`${k}: `}
  64. value={state[k]}
  65. dataSource={ctrlDataSources[k]}
  66. onChange={this.handleCtrlChange.bind(this, k)} />
  67. );
  68. }
  69. }
  70. return ctrlNodes;
  71. }
  72. render() {
  73. return (
  74. <div className="demo-container">
  75. <div className="demo-controller">{this.renderCtrlNodes(this.state)}</div>
  76. <AutoComplete
  77. {...this.state}
  78. style={{maxWidth: 300}}
  79. onChange={this.handleChange}
  80. dataSource={dataSource} />
  81. </div>
  82. );
  83. }
  84. }
  85. ReactDOM.render(<Demo />, mountNode);
.demo-container {
    padding: 16px;
    background-color: #F8F8F8;
}

.demo-controller {
    padding: 12px 12px 4px;
    margin-bottom: 16px;
    border: 2px dashed #ddd;
}

.next-select {
    margin-right: 8px;
    margin-bottom: 8px;
}

动态数据

使用动态数据填充 AutoComplete, 设置 filterLocal 为 false

Select 选择器 - 图14

查看源码在线预览

import { Select } from '@alifd/next';
import jsonp from 'jsonp';

const {AutoComplete} = Select;

class Demo extends React.Component {
    state = {
        dataSource: []
    };

    handleChange = value => {
        clearTimeout(this.searchTimeout);
        this.searchTimeout = setTimeout(() => {
            // eslint-disable-next-line handle-callback-err
            jsonp(`https://suggest.taobao.com/sug?code=utf-8&q=${value}`, (err, data) => {
                const dataSource = data.result.map(item => item[0]);
                this.setState({dataSource});
            });
        }, 100);
    }

    render() {
        return (
            <div className="demo-container">
                <AutoComplete
                    filterLocal={false}
                    placeholder="search from taobao"
                    onChange={this.handleChange}
                    dataSource={this.state.dataSource}/>
            </div>
        );
    }
}

ReactDOM.render(<Demo/>, mountNode);
.demo-container {
    background-color: #F8F8F8;
    padding: 16px;
}

图文展示

展示较为复杂的内容展示

Select 选择器 - 图15

查看源码在线预览

import { Select, Icon } from '@alifd/next';
import jsonp from 'jsonp';

const {AutoComplete} = Select;

class Demo extends React.Component {
    state = {
        dataSource: []
    }

    handleChange = (value) => {
        if (this.searchTimeout) {
            clearTimeout(this.searchTimeout);
        }
        this.searchTimeout = setTimeout(() => {
            // eslint-disable-next-line handle-callback-err
            jsonp(`https://suggest.taobao.com/sug?code=utf-8&q=${value}`, (err, data) => {
                const dataSource = data.result.map(item => {
                    return {
                        label: <div><Icon type="picture" size="small"/>&nbsp;{item[0]}</div>,
                        value: item[1],
                        originLabel: item[0]
                    };
                });
                this.setState({dataSource});
            });
        }, 100);
    }

    render() {
        return (
            <div className="demo-container">
                <AutoComplete onChange={this.handleChange}
                    filterLocal={false}
                    fillProps="originLabel"
                    placeholder="search from taobao"
                    dataSource={this.state.dataSource}/></div>
        );
    }
}
ReactDOM.render(<Demo/>, mountNode);
.next-select {
    margin-right:10px;
    vertical-align: middle;
}

.demo-container {
  background-color: #F8F8F8;
  padding: 16px;
}

.demo-container p {
    margin-top:0;
}

自定义渲染

通过 itemRendervalueRender (仅 Select) 自定义渲染的节点内容。

Select 选择器 - 图16

查看源码在线预览

import { Select, Icon } from '@alifd/next';

const dataSource = [
    {value: '#FF0000', label: 'red', title: 'red'},
    {value: '#00AA00', label: 'green', title: 'green'},
    {value: '#B482DB', label: 'purple', title: 'purple'},
    {value: '#F17334', label: 'orange', title: 'orange'},
    {value: '#66CCFF', label: 'blue', title: 'blue'}
];

const itemRender = item => {
    return (
        <span>
            <Icon type="account" size="xs" style={{color: item.value}} />
            <Icon type="account" size="xs" style={{color: item.value}} />
            <Icon type="account" size="xs" style={{color: item.value}} />
            <Icon type="account" size="xs" style={{color: item.value}} />
            <Icon type="account" size="xs" style={{color: item.value}} />
        </span>
    );
};

const valueRender = item => {
    return <span><Icon type="account" size="xs" style={{color: item.value}} /> {item.label}</span>;
};

const dataSource2 = [
    'Lorem ipsum dolor sit amet',
    'consectetur adipisicing elit',
    'sed do eiusmod tempor incididunt',
    'ut labore et dolore magna aliqua.',
    'Ut enim ad minim veniam',
    'quis nostrud exercitation',
    'ullamco laboris nisi ut',
    'aliquip ex ea commodo consequat',
    'Duis aute irure dolor in',
    'reprehenderit in voluptate',
    'velit esse cillum dolore eu',
    'Fugiat nulla pariatur excepteur sint',
    'occaecat cupidatat non proident',
    'sunt in culpa qui officia',
    'deserunt mollit anim id est laborum'
];

// highlight keywords
const itemRender2 = (item, searchKey) => {
    let label = item.label;
    if (searchKey && searchKey.length) {
        const key = searchKey.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
        const reg = new RegExp(`(${key})`, 'ig');
        label = label.replace(reg, x => `<span class="next-select-highlight">${x}</span>`);
    }

    return <span dangerouslySetInnerHTML={{__html: label}} />;
};

ReactDOM.render(
    <div className="demo-container">
        <Select dataSource={dataSource} itemRender={itemRender} valueRender={valueRender} placeholder="pick your color" />
        <Select showSearch dataSource={dataSource2} itemRender={itemRender2} placeholder="highlight keywords" style={{minWidth: 200}} />
    </div>,
    mountNode
);
.demo-container {
    padding: 16px;
    background-color: #F8F8F8;
}

.demo-container .next-select {
    margin-right: 10px;
}

弹层定制

通过 popupContent 定制 Select 弹层, Select 使用 popupContent 中渲染出的 item 的 value 作为菜单项的key,如果没有提供或者自定义渲染 key 请使用 valueRender

Select 选择器 - 图17

查看源码在线预览

import { Select } from '@alifd/next';
import classNames from 'classnames';
/* eslint-disable react/prop-types, react/no-multi-comp */

// prevent onBlur
function preventDefault(e) {
    e.preventDefault();
}

class Menu extends React.Component {
    data = [{
        label: 'value1',
        value: 1
    }, {
        label: 'value2',
        value: 2
    }];

    onClick(item) {
        this.props.onChange(item);
    }

    renderItems() {
        return this.data.map(item => <li onClick={this.onClick.bind(this, item)} key={item.value}>{item.label}</li>);
    }

    render() {
        const {className, ...others} = this.props;
        const cls = classNames('overlay-content', className);

        return (
            <ul className={cls} {...others}>
                {this.renderItems()}
            </ul>
        );
    }
}

class Demo extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            value: null
        };
    }

    handleSelect = (value) => {
        this.setState({
            value,
            visible: false
        });
    }

    onVisibleChange = (visible) => {
        this.setState({
            visible
        });
    }

    render() {
        const popupContent = <Menu onChange={this.handleSelect} onMouseDown={preventDefault}/>;
        const popupProps = {
            triggerClickKeycode: [13, 32, 40] // space, enter, down-arrow
        };

        return (
            <div className="demo-container">
                <Select
                    placeholder="custom popupContent"
                    visible={this.state.visible}
                    onVisibleChange={this.onVisibleChange}
                    value={this.state.value}
                    popupProps={popupProps}
                    popupContent={popupContent} />
            </div>
        );
    }
}
ReactDOM.render(<Demo/>, mountNode);
.demo-container {
  background-color: #F8F8F8;
  padding: 16px;
}

.demo-container p {
    margin-top:0;
}

.overlay-content {
    border:1px solid #DDDDDD;
    padding:10px;
    background: #FFFFFF;
    margin:0;
    font-size: 12px;
    font-family: Arial;
    box-shadow: 2px 2px 20px rgba(0,0,0,0.15);
}

.overlay-content li {
    list-style: none;
    line-height:30px;
    padding: 0 5px;
    cursor: pointer;
}

.overlay-content li:hover {
    background: #F8F8F8;
}

.overlay-content li:last-child {
    border-width:0;
}

无限滚动

select 配合无限滚动

Select 选择器 - 图18

查看源码在线预览

import { Select } from '@alifd/next';

const Option = Select.Option;

const onChange = function (value) {
    console.log(value);
};

function generateItem(index) {
    return {label: `option${index}`, value: `option${index}`};
}

function generateOption(index) {
    return <Option key={`option${index}`} value={`option${index}`}>{`option${index}`}</Option>;
}

function generateData(len, isOption) {
    const data = [];

    for (let i = 0; i < len; i++) {
        isOption ? data.push(generateOption(i)) : data.push(generateItem(i));
    }

    return data;
}

ReactDOM.render(
    <div>
        <Select dataSource={generateData(100)} useVirtual onChange={onChange} defaultValue="option0" />
        &nbsp;&nbsp;&nbsp;&nbsp;
        <Select useVirtual onChange={onChange} defaultValue="option50">
            {generateData(100, true)}
        </Select>
    </div>
    , mountNode);

无障碍

当聚焦在组件上时,通过aria-labelledby对组件进行描述。关于键盘操作请参考ARIA and KeyBoard

Select 选择器 - 图19

查看源码在线预览

import { Select } from '@alifd/next';

const Option = Select.Option;

class App extends React.Component {
    constructor(props) {
        super(props);
        this.onChange = this.onChange.bind(this);
    }
    onChange(value) {
        console.log(value);
    };

    render() {
        return (<div>
            <span id="select-a11y">Select: </span>
            <Select onChange={this.onChange} defaultValue="jack" aria-labelledby="select-a11y">
                <Option value="jack">Jack</Option>
                <Option value="frank">Frank</Option>
                <Option value="hugo">Hugo</Option>
            </Select>
        </div>);
    }
}

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

相关区块

Select 选择器 - 图20

暂无相关区块