实现的组件样式
focus效果
代码:
import React from 'react'
import { Input, Tag, Tooltip } from 'antd';
import { CloseCircleFilled } from '@ant-design/icons'
import isEqual from 'lodash/isEqual'
import './index.less'
interface ITagState {
tags: string[]
inputValue: string
}
interface ITagProps {
value?: []
onChange?: (value) => void
}
class EditableTagGroup extends React.Component<ITagProps, ITagState> {
constructor(props) {
super(props)
this.state = {
tags: props.value || [],
inputValue: ''
}
}
input: HTMLElement
handleClose = removedTag => {
const tags = this.state.tags.filter(tag => tag !== removedTag);
this.setState({ tags });
};
refDom = () => {
return <>
{this.state.tags.map((tag, index) => {
const isLongTag = tag.length > 20
const tagElem = <Tag
key={index}
closable={true}
onClose={() => this.handleClose(tag)}
closeIcon={<CloseCircleFilled className='close-icon' />}
>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</Tag>
return isLongTag ? (
<Tooltip title={tag} key={tag}>
{tagElem}
</Tooltip>
) : (
tagElem
);
})}
</>
}
inputChange = (e) => {
this.setState({
inputValue: e.target.value
})
}
addTag = (e) => {
const value = e.target.value
if (value) {
this.setState({
tags: [
...this.state.tags,
value
],
inputValue: ''
})
}
}
componentDidUpdate(prevProps, prevState) {
if (!isEqual(prevProps.value, this.props.value)) {
this.setState({
tags: this.props.value
})
}
if (!isEqual(prevState.tags, this.state.tags)) {
console.log(prevState.tags, this.state.tags);
if (this.props.onChange) {
this.props.onChange(this.state.tags)
}
}
}
saveInputRef = input => {
this.input = input;
};
clickEdit = () => {
this.input.focus()
}
render() {
const { inputValue } = this.state
return (
<div className='editable' onClick={this.clickEdit}>
<div className='show'>{this.refDom()}</div>
<Input className='input' ref={this.saveInputRef} placeholder='在此输入,回车添加' onPressEnter={this.addTag} value={inputValue} onChange={this.inputChange} />
</div>
)
}
}
export default EditableTagGroup
.editable {
height: 80px;
border-radius: 2px;
background-color: rgba(255, 255, 255, 1);
border: 1px solid #d9d9d9;
display: flex;
flex-direction: column;
justify-content: space-between;
&:focus-within,
&:hover {
border-color: rgba(22, 119, 254, 1);
box-shadow: 0 0 4px 0 rgba(10, 42, 97, 0.2);
}
.ant-input {
border: none;
height: 32px;
&:hover,
&:focus {
box-shadow: none;
border: none;
}
}
.show {
flex: 1;
min-height: '47px';
overflow: auto;
padding: 0 5px;
.ant-tag {
color: #5a5e66;
padding: 2px 8px;
font-size: 12px;
border: none;
border-radius: 3px;
background-color: rgba(240, 242, 245, 1);
.close-icon {
color: rgba(192, 196, 204, 1);
margin-left: 2px;
font-size: 12px;
}
}
}
}