隨着管理的文章數量增多,默認的幾個分類知足不了現狀了,趁着重構的過程把相關的功能考慮進去javascript
原本想本身從頭寫過一個,看了下Antd
有內置該類型的控件了,就不必本身造了java
通常本身寫,確定優先考慮數組對象格式[{tagName:'a',value:1}]
;react
Antd
提供的是純數組,[string,string]
,那如何不改變它提供的格式狀況下拿到咱們想要的!git
拓展部分咱們須要的東東,有興趣的瞧瞧,沒興趣的止步..github
需求梳理數組
tags
數組且構建枚舉對象,tags
支持刪除添加 ,tag
,追加刪除的狀況要考慮進去;實現antd
dva
的effect
維護接口數據的獲取Dva
這類不純的東西,一切靠props
丟進去在引用處的父組件構建數據獲取,主要構建兩個,一個待渲染的數組,一個是枚舉(其實就是key-value
映射);ide
由於要考慮和之前的版本兼容,全部一些固定的key-value
,還有默認值也要考慮進去(請求失敗的時候)函數
/* * @Author: CRPER * @LastEditors: CRPER * @Github: https://github.com/crper * @Motto: 折騰是一種樂趣,求知是一種追求。不懂就學,懂則分享。 * @Description: 文檔類型維護 */
import React, { PureComponent } from 'react';
import { Tag, Input, Tooltip, Icon, message } from 'antd';
// 對象深比較
import isEqual from 'lodash/isEqual';
export default class DocumentType extends PureComponent {
static getDerivedStateFromProps(nextProps, prevState) {
if (isEqual(nextProps.data, prevState.prevData)) {
return null;
}
if (nextProps.data) {
return {
defaultValue: nextProps.defaultValue ? nextProps.defaultValue : null,
tags: nextProps.data,
prevData: nextProps.data,
};
} else {
return null;
}
}
state = {
tags: [], // 標籤列表
hightlightIndeX: 0, // 如果外部沒有
inputVisible: false, // 輸入框默認隱藏
inputValue: '', // 輸入框默認值
};
//獲取默認值
initDefaultValue = () => {
const { defaultValue, hightlightIndeX, tags } = this.state;
// 如果有,則取遍歷取得;如果外部沒有傳入默認值則取數組第一位
if (defaultValue) {
let index = tags.indexOf(defaultValue);
// 如果傳入的默認值不存在,則默認取下標爲0的
index = index === -1 ? 0 : index;
this.setState({ hightlightIndeX: index }, () => {
this.props.onChange(this.getTagValueFromIndex(index));
});
} else {
this.props.onChange(this.getTagValueFromIndex(hightlightIndeX));
}
};
componentDidMount = () => {
this.initDefaultValue();
};
// 記錄控件的ref
input = React.createRef();
// 顯示input後,直接聚焦
showInput = () => {
this.setState({ inputVisible: true }, () => this.input.current.focus());
};
// 保存input輸入的值
handleInputChange = e => {
this.setState({ inputValue: e.target.value });
};
// 新增斷定
handleInputConfirm = () => {
const { inputValue, tags: prevTags, defaultValue } = this.state;
// 如果輸入的值已經存在或空值,則不添加
if (inputValue === defaultValue) {
message.error('已存在一樣的類型!!!');
this.setState({ inputValue: '' });
this.input.focus();
return false;
}
if (!inputValue) {
this.setState({ inputVisible: false, inputValue: '' });
return false;
}
let tags = prevTags;
if (inputValue && tags.indexOf(inputValue) === -1) {
tags = [...tags, inputValue];
}
this.setState({
tags,
inputVisible: false,
inputValue: '',
});
// 傳遞給父的新增標籤回調
if (this.props.addTag) {
this.props.addTag(inputValue);
}
};
// 取得對應index下的tag的值
getTagValueFromIndex = index => {
const { tags } = this.state;
return tags[index];
};
// 高亮TAG
hightlightTag = index => {
this.setState({ hightlightIndeX: index });
if (this.props.onChange) {
this.props.onChange(this.getTagValueFromIndex(index));
}
};
// 刪除tag
handleClose = removeTag => {
const { hightlightIndeX, tags } = this.state;
if (this.props.removeTag) {
this.props.removeTag(removeTag);
}
// 如果刪除的位置和高亮的位置同一個,則高亮往前一位
if (tags.indexOf(removeTag) === tags.length - 1) {
this.hightlightTag(hightlightIndeX - 1);
}
};
render() {
const { tags, inputVisible, inputValue, hightlightIndeX } = this.state;
const { plusBtnText, activeColor } = this.props;
return (
<div>
{tags.map((tag, index) => {
const isLongTag = tag.length > 10;
const tagElem = (
<Tag
key={tag}
color={hightlightIndeX === index ? (activeColor ? activeColor : '#40a9ff') : ''}
closable={index !== 0}
onClick={() => this.hightlightTag(index)}
afterClose={() => this.handleClose(tag)}
>
{isLongTag ? `${tag.slice(0, 10)}...` : tag}
</Tag>
);
return isLongTag ? (
<Tooltip title={tag} key={tag}>
{tagElem}
</Tooltip>
) : (
tagElem
);
})}
{inputVisible && (
<Input
ref={this.input}
type="text"
size="small"
style={{ width: 78 }}
value={inputValue}
onChange={this.handleInputChange}
onBlur={this.handleInputConfirm}
onPressEnter={this.handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag onClick={this.showInput} style={{ background: '#fff', borderStyle: 'dashed' }}>
<Icon type="plus" /> {plusBtnText ? plusBtnText : 'New Tag'}
</Tag>
)}
</div>
);
}
}
複製代碼
寫成受控組件,無數據不渲染flex
props |
解釋 | 格式類型 | 是否可選 |
---|---|---|---|
data |
待遍歷的數組 | 數組 | 必選 |
onChange |
選中的回調 | 函數 | 必選 |
addTag |
添加標籤的回調 | 函數 | 必選 |
remvoeTag |
移除標籤的回調 | 函數 | 必選 |
defaultValue |
默認值 | 字符串 | 可選 |
plusBtnText |
追加按鈕文本替換 | 字符串 | 可選 |
activeColor |
高亮的顏色 | 字符串 | 可選 |
{typeNames && typeNames.length > 0 ? (
<Row type="flex" justify="start" align="middle">
<span style={{ fontSize: 16, fontWeight: 700 }}>文章類型</span>
<Divider type="vertical" />
<DocumentType
data={typeNames}
onChange={this.getTagValue}
addTag={this.addTag}
removeTag={this.removeTag}
defaultValue="草稿"
activeColor="#108ee9"
plusBtnText="新的分類"
/>
</Row>
) : null}
複製代碼
不對之處請留言,會及時修正.謝謝閱讀.