Component
import React, {useMemo} from 'react';
import {Form} from 'antd-mobile';
import ReactSelect, {components} from 'react-select';
import AsyncSelect from 'react-select/async';
import contentCanvasStyle from '../../../ContentCanvas.less';
import style from './style.less';
const CommonSelect = props => {
const {loadOptions, isMulti, isSearchable, maxCount, attribute = {}, id, children, dragProps = {}, onEvent, ...rest} = props;
const {options = []} = attribute;
const required = !!attribute.required;
const rules = required ? [{required, message: '请选择选项!'}] : [];
return (
<div {...dragProps} {...rest} className={`${style.common_select} ${contentCanvasStyle.form_control_item_wrap}`}>
<Form.Item name={id} label={attribute.name} rules={rules}>
<MySelect loadOptions={loadOptions} isMulti={isMulti} maxCount={maxCount} options={options} />
</Form.Item>
{children}
</div>
);
};
function NoOptionsMessage(props) {
return (
<div className={style.no_options_message}>
<span className={style.content}>没有选项了</span>
</div>
);
}
function Option(props) {
const {isSelected} = props;
return (
<span className={style.select_option}>
<components.Option {...props} className={style.select_content} title="1111" />
{!!isSelected && <span className={style.selected} />}
</span>
);
}
const MultiValue = props => {
const {selectProps, index} = props;
const {value} = selectProps || {};
if (index == 0) {
return (
<components.MultiValue {...props}>
<span className={style.ell_multi} title={props.data.label}>
{props.data.label}
</span>
</components.MultiValue>
);
} else if (index == 1) {
// 超过两个值的则直接显示+N
const overLength = value.length - 1;
const _value = JSON.parse(JSON.stringify(value));
_value.splice(0, 1);
let title;
_value.forEach(el => {
if (title) {
title = `${title},${el.label}`;
} else {
title = el.label;
}
});
return (
<components.MultiValue {...props}>
<span title={title} className={style.ell_multi}>
+{overLength}
</span>
</components.MultiValue>
);
} else {
// 其余都不显示
return null;
}
};
function SelectionPrompt(props) {
return <span style={{color: '#cccccc'}}>请选择</span>;
}
function OptionLabel(props) {
const {option} = props;
return (
<div className={style.ell} title={option.label}>
{option.label}
</div>
);
}
const MySelect = ({onChange, value, options = [], maxCount = 1000, loadOptions, isMulti, isSearchable, isClearable}) => {
const customStyle = useMemo(
() => ({
menuPortal: styles => ({...styles, zIndex: 9999}),
menu: styles => ({...styles}),
control: styles => ({...styles}),
option: (styles, {data, isDisabled, isFocused, isSelected}) => {
let _styles = {...styles};
if (isSelected) {
_styles = {
...styles,
backgroundColor: 'transparent',
color: 'inherit'
};
}
if (isFocused) {
_styles.backgroundColor = '#DEEBFF';
}
return _styles;
},
multiValue: styles => ({...styles}),
multiValueLabel: styles => ({...styles}),
multiValueRemove: styles => ({...styles})
}),
[]
);
const selectOptions = useMemo(
() =>
options.map((v, i) => {
if (v.label) {
return v;
} else {
return {
label: v,
value: v
};
}
}),
[options]
);
const handleChange = (newValue, actionMeta) => {
if (isMulti && newValue && typeof newValue == 'string') {
onChange(newValue.slice(0, maxCount), actionMeta);
} else {
onChange(newValue, actionMeta);
}
};
const TheSelect = loadOptions ? AsyncSelect : ReactSelect;
const components = {NoOptionsMessage, Option};
if (isMulti) {
components.MultiValue = MultiValue;
if (value && value.length > 0) {
components.inputValue = value.map(option => option.label).join(', '); // ??
}
}
return (
<TheSelect
placeholder={<SelectionPrompt />}
components={components}
getOptionLabel={option => <OptionLabel option={option} />}
styles={customStyle}
className={style.origin_select}
isMulti={isMulti}
isSearchable={isSearchable}
isClearable={isClearable}
// 是否要隐藏选中的选项Options
hideSelectedOptions={false}
// 选中后是否要关闭菜单
closeMenuOnSelect={false}
menuPosition="fixed"
options={selectOptions}
cacheOptions
defaultOptions
loadOptions={loadOptions}
onChange={handleChange}
value={value}
menuPortalTarget={document.body}
/>
);
};
export default CommonSelect;
less
.origin_select {
width: 100%;
padding-right: 3px; // 防止选中框被遮挡
font-size: 14px;
& > div {
border-color: rgb(238 232 232);
}
}
.common_select {
* {
max-width: 100%;
}
[role='button'] {
flex: none;
}
}
.no_options_message {
display: 'flex';
justify-content: 'center';
.content {
text-align: center;
color: #ccc;
font-size: 16px;
padding: 5px;
}
}
.select_option {
display: inline-flex;
width: 100%;
.select_content {
width: 100%;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
white-space: nowrap;
}
.selected {
display: inline-block;
position: absolute;
flex: none;
width: 20px;
height: 20px;
right: 10px;
align-self: center;
}
.selected::after {
content: '';
position: absolute;
top: 2px;
left: 6px;
width: 6px;
height: 12px;
border: solid black;
border-width: 0 1px 1px 0;
transform: rotate(45deg);
}
}
.ell {
width: 100%;
word-break: break-all;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ell_multi {
max-width: 85px;
display: inline-block;
word-break: break-all;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}