feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑 (#7695)

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* feat: transfer 树形搜索的时候支持高亮& feat: transfer 提供清空搜索的事件动作 & fix: transfer 穿梭器左上角的全选勾选时,没有处理 onlyChildren:true 的逻辑

* style: transfer文档动作完善
This commit is contained in:
sqzhou 2023-08-22 14:02:57 +08:00 committed by GitHub
parent 71bfc3f730
commit 866d3412b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 181 deletions

View File

@ -929,5 +929,6 @@ icon:
| --------- | -------------------------------------- | --------------------------------------------------------------------------------------- |
| clear | - | 清空 |
| reset | - | 将值重置为`resetValue`,若没有配置`resetValue`,则清空 |
| clearSearch | `left: boolean` 左侧搜索、`right:boolean`右侧搜索 | 默认清除所有搜索态,可以单独配置`left`、`right`为`true`来清空对应左侧或者右侧面板(`3.4.0`及以上版本支持) |
| selectAll | - | 全选 |
| setValue | `value: string` \| `string[]` 更新的值 | 更新数据,开启`multiple`支持设置多项,开启`joinValues`时,多值用`,`分隔,否则多值用数组 |

View File

@ -52,6 +52,29 @@ export default {
}
}
},
{
name: 'transferEvent2',
id: 'transferEvent2',
type: 'action',
label: '清空搜索',
level: 'primary',
className: 'mr-3 mb-3',
debugger: true,
onEvent: {
click: {
actions: [
{
actionType: 'clearSearch',
componentId: 'transfer-receiver',
args: {
left: true,
right: true
}
}
]
}
}
},
{
name: 'transferEvent2',
id: 'transferEvent2',
@ -84,6 +107,8 @@ export default {
id: 'transfer-receiver',
type: 'transfer',
name: 'transfer',
searchable: true,
resultSearchable: true,
debugger: true,
resetValue: 'c',
source: '/api/mock2/form/getTreeOptions',

View File

@ -339,7 +339,8 @@ export interface ActionObject extends ButtonObject {
| 'collapse'
| 'step-submit'
| 'selectAll'
| 'changeTabKey';
| 'changeTabKey'
| 'clearSearch';
api?: BaseApiObject | string;
asyncApi?: BaseApiObject | string;
payload?: any;

View File

@ -81,6 +81,7 @@ export class ResultList extends React.Component<
id = guid();
sortable?: Sortable;
unmounted = false;
searchRef?: any;
componentDidMount() {
this.props.sortable && this.initSortable();
@ -99,6 +100,14 @@ export class ResultList extends React.Component<
this.unmounted = true;
}
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
initSortable() {
const ns = this.props.classPrefix;
const dom = findDOMNode(this) as HTMLElement;
@ -181,6 +190,14 @@ export class ResultList extends React.Component<
this.setState({searchResult: null});
}
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
// 删除项
@autobind
handleCloseItem(e: React.MouseEvent<HTMLElement>, option: Option) {
@ -359,6 +376,7 @@ export class ResultList extends React.Component<
{title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? (
<TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder}
onSearch={this.search}
onCancelSearch={this.clearSearch}

View File

@ -68,6 +68,8 @@ export class BaseResultTableSelection extends BaseSelection<
searchTableOptions: []
};
searchRef?: any;
static getDerivedStateFromProps(props: ResultTableSelectionProps) {
const {options, value, option2value, valueField} = props;
const valueArray = BaseSelection.value2array(
@ -81,6 +83,14 @@ export class BaseResultTableSelection extends BaseSelection<
};
}
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
@autobind
handleCloseItem(option: Option) {
const {value, onChange, option2value, options, disabled, valueField} =
@ -147,6 +157,14 @@ export class BaseResultTableSelection extends BaseSelection<
});
}
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
renderTable() {
const {
classnames: cx,
@ -233,6 +251,7 @@ export class BaseResultTableSelection extends BaseSelection<
{title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? (
<TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder}
onSearch={this.search}
onCancelSearch={this.clearSearch}

View File

@ -163,6 +163,8 @@ export class BaseResultTreeList extends React.Component<
searchTreeOptions: []
};
searchRef?: any;
static getDerivedStateFromProps(props: ResultTreeListProps) {
const newOptions = getResultOptions(
props.value,
@ -174,6 +176,14 @@ export class BaseResultTreeList extends React.Component<
};
}
@autobind
domSearchRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.searchRef = ref;
}
// 删除非选中节点
@autobind
deleteTreeChecked(option: Option) {
@ -259,6 +269,14 @@ export class BaseResultTreeList extends React.Component<
});
}
@autobind
clearInput() {
if (this.props.searchable) {
this.searchRef?.clearInput?.();
}
this.clearSearch();
}
renderTree() {
const {
className,
@ -314,6 +332,7 @@ export class BaseResultTreeList extends React.Component<
{title ? <div className={cx('Selections-title')}>{title}</div> : null}
{searchable ? (
<TransferSearch
ref={this.domSearchRef}
placeholder={searchPlaceholder}
onSearch={this.search}
onCancelSearch={this.clearSearch}

View File

@ -155,6 +155,7 @@ export class Transfer<
unmounted = false;
cancelSearch?: () => void;
treeRef: any;
resultRef: any;
componentDidMount() {
this.props?.onRef?.(this);
@ -196,9 +197,20 @@ export class Transfer<
@autobind
domRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.treeRef = ref;
}
@autobind
domResultRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.resultRef = ref;
}
@autobind
toggleAll() {
const {
@ -207,7 +219,8 @@ export class Transfer<
onChange,
value,
onSelectAll,
valueField = 'value'
valueField = 'value',
selectMode
} = this.props;
let valueArray = BaseSelection.value2array(
value,
@ -217,6 +230,11 @@ export class Transfer<
);
const availableOptions = this.availableOptions;
if (selectMode === 'tree') {
this.treeRef?.handleToggle();
return;
}
// availableOptions 中选项是否都被选中了
// to do intersectionWith 需要优化,大数据会卡死
const isAvailableOptionsAllSelected =
@ -247,7 +265,17 @@ export class Transfer<
// 全选,给予动作全选使用
selectAll() {
const {options, option2value, onChange, valueField = 'value'} = this.props;
const {
options,
option2value,
onChange,
valueField = 'value',
selectMode
} = this.props;
if (selectMode === 'tree') {
this.treeRef?.handleToggle(true);
return;
}
const availableOptions = flattenTree(options).filter(
(option, index, list) =>
!option.disabled &&
@ -260,6 +288,20 @@ export class Transfer<
onChange?.(newValue);
}
// 清空搜索
clearSearch(target?: {left?: boolean; right?: boolean}) {
if (!target) {
this.handleSeachCancel();
this.resultRef?.clearInput();
}
if (target?.left) {
this.handleSeachCancel();
}
if (target?.right) {
this.resultRef?.clearInput();
}
}
@autobind
clearAll() {
const {onChange} = this.props;
@ -369,6 +411,22 @@ export class Transfer<
onChange && onChange(newArr);
}
@autobind
optionItemRender(option: Option, states: ItemRenderStates) {
const {optionItemRender, labelField = 'label'} = this.props;
return optionItemRender
? optionItemRender(option, states)
: BaseSelection.itemRender(option, {labelField, ...states});
}
@autobind
resultItemRender(option: Option, states: ItemRenderStates) {
const {resultItemRender} = this.props;
return resultItemRender
? resultItemRender(option, states)
: ResultList.itemRender(option, states);
}
renderSelect(
props: TransferProps & {
onToggleAll?: () => void;
@ -509,11 +567,15 @@ export class Transfer<
checkAllLabel,
onlyChildren
} = props;
const {isTreeDeferLoad, searchResult} = this.state;
const {isTreeDeferLoad, searchResult, inputValue} = this.state;
const options = searchResult ?? [];
const mode = searchResultMode || selectMode;
const resultColumns = searchResultColumns || columns;
const treeItemRender =
!searchResult || optionItemRender ? this.optionItemRender : undefined;
const highlightTxt = searchResult ? inputValue : undefined;
return mode === 'table' ? (
<TableSelection
placeholder={noResultsText}
@ -525,7 +587,7 @@ export class Transfer<
onChange={onChange}
option2value={option2value}
cellRender={cellRender}
itemRender={optionItemRender}
itemRender={this.optionItemRender}
valueField={valueField}
multiple={multiple}
virtualThreshold={virtualThreshold}
@ -534,7 +596,7 @@ export class Transfer<
/>
) : mode === 'tree' ? (
<Tree
onRef={this.domRef}
ref={this.domRef}
placeholder={noResultsText}
className={cx('Transfer-selection')}
options={options}
@ -548,7 +610,8 @@ export class Transfer<
multiple={multiple}
cascade={true}
onlyChildren={onlyChildren ?? !isTreeDeferLoad}
itemRender={optionItemRender}
highlightTxt={highlightTxt}
itemRender={treeItemRender}
labelField={labelField}
valueField={valueField}
virtualThreshold={virtualThreshold}
@ -565,7 +628,7 @@ export class Transfer<
disabled={disabled}
onChange={onChange}
option2value={option2value}
itemRender={optionItemRender}
itemRender={this.optionItemRender}
multiple={multiple}
labelField={labelField}
valueField={valueField}
@ -584,7 +647,7 @@ export class Transfer<
disabled={disabled}
onChange={onChange}
option2value={option2value}
itemRender={optionItemRender}
itemRender={this.optionItemRender}
multiple={multiple}
labelField={labelField}
valueField={valueField}
@ -647,7 +710,7 @@ export class Transfer<
/>
) : selectMode === 'tree' ? (
<Tree
onRef={this.domRef}
ref={this.domRef}
placeholder={noResultsText}
className={cx('Transfer-selection')}
options={options}
@ -745,7 +808,6 @@ export class Transfer<
cellRender,
onChange,
value,
resultItemRender,
resultSearchable,
resultSearchPlaceholder,
onResultSearch,
@ -766,6 +828,7 @@ export class Transfer<
case 'table':
return (
<ResultTableList
ref={this.domResultRef}
classnames={cx}
columns={columns!}
options={options || []}
@ -786,6 +849,7 @@ export class Transfer<
case 'tree':
return (
<ResultTreeList
ref={this.domResultRef}
loadingConfig={loadingConfig}
classnames={cx}
className={cx('Transfer-value')}
@ -793,7 +857,7 @@ export class Transfer<
valueField={'value'}
value={value || []}
onChange={onChange!}
itemRender={resultItemRender}
itemRender={this.resultItemRender}
searchable={searchable}
placeholder={placeholder}
searchPlaceholder={resultSearchPlaceholder}
@ -806,6 +870,7 @@ export class Transfer<
default:
return (
<ResultList
ref={this.domResultRef}
className={cx('Transfer-value')}
sortable={sortable}
disabled={disabled}
@ -813,7 +878,7 @@ export class Transfer<
onChange={onChange}
placeholder={placeholder}
searchPlaceholder={resultSearchPlaceholder}
itemRender={resultItemRender}
itemRender={this.resultItemRender}
searchable={searchable}
onSearch={onResultSearch}
labelField={labelField}

View File

@ -84,6 +84,13 @@ export class TransferSearch extends React.Component<
});
}
@autobind
clearInput() {
this.setState({
inputValue: ''
});
}
render() {
const {classnames: cx, translate: __, placeholder, mobileUI} = this.props;

View File

@ -1355,6 +1355,19 @@ export class TreeSelector extends React.Component<
);
}
@autobind
handleToggle(bool?: boolean) {
const availableOptions = this.getAvailableOptions();
if (bool === undefined) {
const checkedAll = availableOptions.every(option =>
this.isItemChecked(option)
);
this.handleCheckAll(availableOptions, checkedAll);
return;
}
this.handleCheckAll(availableOptions, bool);
}
renderCheckAll() {
const {
multiple,

View File

@ -1774,13 +1774,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="法师"
>
<span
class=""
>
法师
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -1814,13 +1810,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="诸葛亮"
>
<span
class=""
>
诸葛亮
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -1859,13 +1851,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="战士"
>
<span
class=""
>
战士
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -1899,13 +1887,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="曹操"
>
<span
class=""
>
曹操
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -1939,13 +1923,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="钟无艳"
>
<span
class=""
>
钟无艳
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -1984,13 +1964,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="打野"
>
<span
class=""
>
打野
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2024,13 +2000,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="李白"
>
<span
class=""
>
李白
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2064,13 +2036,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="韩信"
>
<span
class=""
>
韩信
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2104,13 +2072,9 @@ exports[`Renderer:transfer follow left mode 1`] = `
<span
class="cxd-Tree-itemText"
title="云中君"
>
<span
class=""
>
云中君
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2442,13 +2406,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="法师"
>
<span
class=""
>
法师
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2482,13 +2442,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="诸葛亮"
>
<span
class=""
>
诸葛亮
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2527,13 +2483,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="战士"
>
<span
class=""
>
战士
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2567,13 +2519,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="曹操"
>
<span
class=""
>
曹操
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2607,13 +2555,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="钟无艳"
>
<span
class=""
>
钟无艳
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2652,13 +2596,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="打野"
>
<span
class=""
>
打野
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2692,13 +2632,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="李白"
>
<span
class=""
>
李白
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2732,13 +2668,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="韩信"
>
<span
class=""
>
韩信
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -2772,13 +2704,9 @@ exports[`Renderer:transfer follow left mode 2`] = `
<span
class="cxd-Tree-itemText"
title="云中君"
>
<span
class=""
>
云中君
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -5896,13 +5824,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="法师"
>
<span
class=""
>
法师
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -5936,13 +5860,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="诸葛亮"
>
<span
class=""
>
诸葛亮
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -5981,13 +5901,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="战士"
>
<span
class=""
>
战士
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6021,13 +5937,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="曹操"
>
<span
class=""
>
曹操
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6061,13 +5973,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="钟无艳"
>
<span
class=""
>
钟无艳
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6106,13 +6014,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="打野"
>
<span
class=""
>
打野
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6146,13 +6050,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="李白"
>
<span
class=""
>
李白
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6186,13 +6086,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="韩信"
>
<span
class=""
>
韩信
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6226,13 +6122,9 @@ exports[`Renderer:transfer tree 1`] = `
<span
class="cxd-Tree-itemText"
title="云中君"
>
<span
class=""
>
云中君
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6430,13 +6322,9 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
<span
class="cxd-Tree-itemText"
title="诸葛亮"
>
<span
class=""
>
诸葛亮
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6470,13 +6358,9 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
<span
class="cxd-Tree-itemText"
title="曹操"
>
<span
class=""
>
曹操
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>
@ -6510,13 +6394,9 @@ exports[`Renderer:transfer with showInvalidMatch & unmatched do not add 1`] = `
<span
class="cxd-Tree-itemText"
title="钟无艳"
>
<span
class=""
>
钟无艳
</span>
</span>
<div
class="cxd-Tree-item-icons"
/>

View File

@ -1230,3 +1230,84 @@ test('Renderer:transfer with searchApi', async () => {
const caocao = container.querySelector('span[title=曹操]');
expect(caocao).toBeNull();
});
test('Renderer:transfer tree onlyChildren true', async () => {
const onSubmit = jest.fn();
const schema = {
"type": "form",
"api": "/api/mock2/form/saveForm",
"debug": true,
"body": [
{
"label": "默认",
"type": "transfer",
"name": "transfer",
"value": "libai",
"selectMode": "tree",
"searchable": true,
"onlyChildren": true,
"options": [
{
"label": "法师",
"children": [
{
"label": "诸葛亮",
"value": "zhugeliang"
}
]
},
{
"label": "战士",
"value": "战士",
"children": [
{
"label": "曹操",
"disabled": true,
"value": "caocao"
},
{
"label": "钟无艳",
"value": "zhongwuyan"
}
]
},
{
"label": "打野",
"children": [
{
"label": "李白",
"value": "libai"
},
{
"label": "韩信",
"value": "hanxin"
},
{
"label": "云中君",
"value": "yunzhongjun"
}
]
}
]
}
]
};
const {getByText, container} = render(
amisRender(schema, {onSubmit}, makeEnv({}))
);
const checkbox = container.querySelector('.cxd-Checkbox');
expect(checkbox).not.toBeNull();
checkbox && fireEvent.click(checkbox);
fireEvent.click(getByText('提交'));
await wait(100);
expect(onSubmit).toBeCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toEqual({
transfer: "zhugeliang,zhongwuyan,libai,hanxin,yunzhongjun"
});
});

View File

@ -428,31 +428,23 @@ export class BaseTransferRenderer<
@autobind
optionItemRender(option: Option, states: ItemRenderStates) {
const {menuTpl, render, data, labelField = 'label'} = this.props;
const {menuTpl, render, data} = this.props;
if (menuTpl) {
return render(`item/${states.index}`, menuTpl, {
data: createObject(createObject(data, states), option)
});
}
return BaseSelection.itemRender(option, {labelField, ...states});
}
@autobind
resultItemRender(option: Option, states: ItemRenderStates) {
const {valueTpl, render, data} = this.props;
if (valueTpl) {
return render(`value/${states.index}`, valueTpl, {
onChange: states.onChange,
data: createObject(createObject(data, states), option)
});
}
return ResultList.itemRender(option, states);
}
@autobind
renderCell(
column: {
@ -508,6 +500,10 @@ export class BaseTransferRenderer<
case 'selectAll':
this.tranferRef?.selectAll();
break;
case 'clearSearch': {
this.tranferRef?.clearSearch(data);
break;
}
}
}
@ -533,6 +529,7 @@ export class BaseTransferRenderer<
selectTitle,
resultTitle,
menuTpl,
valueTpl,
searchPlaceholder,
resultListModeFollowSelect = false,
resultSearchPlaceholder,
@ -597,8 +594,8 @@ export class BaseTransferRenderer<
statistics={statistics}
labelField={labelField}
valueField={valueField}
optionItemRender={this.optionItemRender}
resultItemRender={this.resultItemRender}
optionItemRender={menuTpl ? this.optionItemRender : undefined}
resultItemRender={valueTpl ? this.resultItemRender : undefined}
onSelectAll={this.onSelectAll}
onRef={this.getRef}
virtualThreshold={virtualThreshold}