我的方式:
- 用自己的组件替换
Option
了组件(来自 Material-UI 库的几个组件)。
- 重写的事件处理程序 - 这是来自 ReactSelect 道具
onClick
的一些逻辑和调用处理程序。onChange
在onClick
处理程序的末尾添加event.stopPropagation()
import React from 'react';
import MenuItem from '@material-ui/core/MenuItem/MenuItem';
import Checkbox from '@material-ui/core/Checkbox/Checkbox';
import ListItemText from '@material-ui/core/ListItemText/ListItemText';
const MultiOption = props => (
<MenuItem
buttonRef={props.innerRef}
{...props.innerProps}
onClick={event => {
let values = [];
if (props.isSelected) {
values = props.selectProps.value.filter(
item => item.value !== props.value,
);
} else {
values = [props.data].concat(props.selectProps.value);
}
props.selectProps.onChange(values);
event.stopPropagation();
}}
style={{
overflow: 'initial',
padding: 0,
}}
>
<Checkbox
checked={props.isSelected}
style={{
padding: 4,
}}
/>
<ListItemText
primary={props.label}
classes={{
root: props.selectProps.classes.optionRoot,
}}
/>
</MenuItem>
);
export default MultiOption;
import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-select';
import { withStyles } from '@material-ui/core/styles';
import { getComponents } from './components';
import { styles, getSelectStyles } from './styles';
class Combobox extends React.Component {
handleChange = () => value => {
const { onChange } = this.props;
onChange(value);
};
render() {
const {
classes,
theme,
options,
label,
rootStyle,
value,
error,
isInner,
isMulti,
fullWidth,
...props
} = this.props;
return (
<div className={classes.root} style={{ ...rootStyle }}>
<Select
{...props}
isClearable
classes={classes}
styles={getSelectStyles({
theme,
fullWidth,
})}
options={options}
menuPortalTarget={document.body}
menuPlacement="auto"
value={value || null}
onChange={this.handleChange()}
components={getComponents({
isInner,
isMulti,
})}
textFieldProps={{
label,
error: !!error,
helperText: error,
InputLabelProps: { shrink: true },
}}
isMulti={isMulti}
hideSelectedOptions={!isMulti}
closeMenuOnSelect={!isMulti}
loadingMessage={() => 'Loading...'}
/>
</div>
);
}
}
Combobox.propTypes = {
options: PropTypes.arrayOf(PropTypes.shape({})),
label: PropTypes.string,
classes: PropTypes.shape({}).isRequired,
theme: PropTypes.shape({}).isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.bool,
PropTypes.arrayOf(PropTypes.any),
PropTypes.shape({}),
]),
error: PropTypes.string,
onChange: PropTypes.func.isRequired,
isInner: PropTypes.bool,
isMulti: PropTypes.bool,
fullWidth: PropTypes.bool,
};
Combobox.defaultProps = {
options: [],
label: '',
value: null,
error: '',
isInner: false,
isMulti: false,
fullWidth: false,
};
export default withStyles(styles, { withTheme: true })(({ ...props }) => (
<Combobox {...props} />
));
import Control from './Control';
import InnerControl from './InnerControl';
import InputComponent from './InputComponent';
import MenuList from './MenuList';
import Option from './Option';
import MultiOption from './MultiOption';
import SingleValue from './SingleValue';
import MultiValue from './MultiValue';
import NoOptionsMessage from './NoOptionsMessage';
import Placeholder from './Placeholder';
import ValueContainer from './ValueContainer';
const getComponents = ({ isInner, isMulti }) => ({
Control: isInner ? InnerControl : Control,
...(isMulti && { MenuList }),
MultiValue,
NoOptionsMessage,
Option: isMulti ? MultiOption : Option,
Placeholder,
SingleValue,
ValueContainer,
});
export {
Control,
InnerControl,
InputComponent,
MenuList,
Option,
MultiOption,
SingleValue,
MultiValue,
NoOptionsMessage,
Placeholder,
ValueContainer,
getComponents,
};