原因:由于使用了一些比较老的react组件,导致现有的antd 无法升级到3X、4X, 并且最近产品提的需求比较骚操作。
这种select.Option中有按钮的
撸起袖子开始干
1、现引入要使用的其他组件和工具包 (主要需要三个元素 输入框、图标、下拉菜单)
import * as React from 'react'
import { Menu, Dropdown, Input, Icon } from 'antd'
import * as _ from 'lodash'
2、仿照现有的select,export两个东东
export class NewOption extends React.Component<IOptionPorps, IState> {
// 中间层组件div来组织react合成事件冒泡
click = e => {
// react合成事件数量大于当前节点现有的事件数量即 menuItem 和div两个表示子组件可能存在合成事件
const hasChildEvent = e._dispatchListeners.length > 2
if (hasChildEvent) {
e.stopPropagation()
return false
}
}
render() {
const { children, value, key } = this.props
return (
<Menu.Item {...this.props} eventKey={key ? key + '' : value + ''}>
<div className="option-item" onClick={this.click}>
{children}
</div>
</Menu.Item>
)
}
}
export default class NewSelect extends React.Component<IProps, IState> {
state: IState = {
inputValue: undefined,
showOption: false,
placeholder: undefined
}
public clear = () => {
this.setState({
inputValue: undefined,
placeholder: undefined
})
this.body.focus()
}
body = undefined
input = undefined
// option选中时间
onSelect = ({ item, key }) => {
const value = this.findChildContent(item)
this.setState(
{
inputValue: value,
placeholder: value,
showOption: false
},
() => {
const { onSelect } = this.props
if (!!onSelect) {
onSelect(key)
}
this.inputBlur()
}
)
}
// 找到子元素内容
findChildContent = item => {
if (item.props.children) {
const next = _.isArray(item.props.children)
? item.props.children[0]
: item.props.children
if (_.isString(next)) {
return next
} else {
return this.findChildContent(next)
}
} else {
return undefined
}
}
inputBlur = () => {
this.input.blur()
this.setState({
showOption: false,
inputValue: this.state.placeholder
})
}
// 输入框输入事件
onChangeInput = _.debounce(value => {
const { onSearch } = this.props
if (!!onSearch) {
onSearch(value)
}
}, 500)
// mousedown listener函数
mousedown = e => {
event.preventDefault()
this.input.focus()
this.setState({
showOption: true,
inputValue: undefined
})
}
componentDidMount() {
this.body.addEventListener('mousedown', this.mousedown)
}
componentDidUpdate() {
if (this.state.showOption && this.input) {
this.input.focus()
}
}
componentWillUnmount() {
this.body.removeEventListener('mousedown', this.mousedown)
}
// 需要三个元素 输入框、图标、下拉菜单
public render() {
const { showOption } = this.state
const { children, loading } = this.props
const width = this.props.width || '180px'
const menu = (
<Menu style={{ width }} onClick={this.onSelect}>
{children}
</Menu>
)
const downIcon = <Icon type="down" className="icon" />
const upIcon = <Icon type="up" className="icon" />
const loadingIcon = <Icon type="loading" className="icon" />
return (
<Dropdown
overlay={menu}
visible={showOption}
getPopupContainer={() => this.body}
>
<div
className="customize-select"
style={{ width }}
ref={ref => (this.body = ref)}
>
<Input
disabled={loading}
onChange={e => {
this.setState({ inputValue: e.target.value })
this.onChangeInput(e.target.value)
}}
value={this.state.inputValue}
ref={ref => (this.input = ref)}
style={{ width: '100%' }}
placeholder={this.state.placeholder}
onBlur={this.inputBlur}
/>
{showOption && !loading && downIcon}
{!showOption && !loading && upIcon}
{loading && loadingIcon}
</div>
</Dropdown>
)
}
}
忘记贴出interface 了
interface IProps {
width?: string | number
value?: string
loading: boolean
onSelect?: (params) => void
onSearch?: (params) => void
}
interface IState {
inputValue: string
showOption: boolean
placeholder: string
}
interface IOptionPorps {
value: string
key?: string
disabled?: boolean
selectedKeys?: string[]
eventKey?: string
}
备注:
如果其中的阻止事件的中间层不理解,或者mousedown事件也不理解,那么请去看看react合成事件原理,即onClick等事件到底是怎么执行的
style.less 不要忘记欧!
.customize-select {
position: relative;
display: inline-block;
.icon {
position: absolute;
right: 12px;
top: calc(50% - 6px);
}
.option-item {
width: 100%;
}
}
接下来看看怎么用吧:
<NewSelect
width="180px"
loading={loading}
onSearch={this.onSearch}
onSelect={this.onSelect}
ref={ref => (this.select = ref)}
>
<NewOption
value={'1'}
key={'1'}
disabled={this.state.disabled}
>
<div className="item">
<span>我是label</span>
<span>
<Button
size="small"
onClick={this.onClick}
>
点击
</Button>
</span>
</div>
</ NewOption>
好了,可以用了,好开心,关于失焦和聚焦可以自行更改来达到自己使用的目的。