内容简介:随着管理的文章数量增多,默认的几个分类满足不了现状了...趁着重构的过程把相关的功能考虑进去本来想自己从头写过一个,看了下
随着管理的文章数量增多,默认的几个分类满足不了现状了...
趁着重构的过程把相关的功能考虑进去
本来想自己从头写过一个,看了下 Antd 有内置该类型的控件了,就没必要自己造了
一般自己写,肯定优先考虑数组对象格式 [{tagName:'a',value:1}] ;
Antd 提供的是纯数组, [string,string] ,那如何不改变它提供的格式情况下拿到我们想要的!
拓展部分我们需要的东东,有兴趣的瞧瞧,没兴趣的止步..
效果图
需求分析及思路
需求梳理
- 从接口拿到
tags数组,tags支持删除添加 - 高亮
tag,追加删除的情况要考虑进去(删除要考虑进去); - 第一个为默认分类,不允许删除
- 标签文字过长,则截断,用气泡悬浮来展示完全的文本
- 不允许添加同样的(阻止并给予反馈)
- 默认值初始化并且回馈
- 把值丢给父
实现
- 用
dva的effect维护接口数据的获取 - 子组件除了暴露返回值,不做任何涉及
Dva这类不纯的东西,一切靠props丢进去
代码实现
在引用处的父组件构建数据获取,主要构建两个,一个待渲染的数组,一个是 枚举 (其实就是 key-value 映射);
因为要考虑和以前的版本兼容,所有一些固定的 key-value ,还有默认值也要考虑进去(请求失败的时候)
DocumentType.js
/*
* @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();
};
// 显示input后,直接聚焦
showInput = () => {
this.setState({ inputVisible: true }, () => this.input.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);
}
};
// 记录控件的ref
saveInputRef = input => (this.input = input);
render() {
const { tags, inputVisible, inputValue, hightlightIndeX } = this.state;
const { plusBtnText } = this.props;
return (
<div>
{tags.map((tag, index) => {
const isLongTag = tag.length > 10;
const tagElem = (
<Tag
key={tag}
closable={index !== 0}
style={hightlightIndeX === index ? { color: '#fff', background: '#108ee9' } : {}}
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.saveInputRef}
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>
);
}
}
复制代码
用法
写成受控组件,无数据不渲染
{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="草稿"
plusBtnText="新的分类"
/>
</Row>
) : null}
复制代码
props |
解释 | 格式类型 |
|---|---|---|
data |
待遍历的数组 | 数组 |
onChange |
选中的回调 | 函数 |
addTag |
添加标签的回调 | 函数 |
remvoeTag |
移除标签的回调 | 函数 |
defaultValue |
默认值 | 字符串 |
plusBtnText |
追加按钮文本替换 | 字符串 |
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- hibernate多对多,单个修改很伤神
- php取出数组单个值的方法
- 巧断梯度:单个loss实现GAN模型
- Oracle 11g 起停RAC中单个节点
- 后台接收Json请求参数兼容数组和单个对象
- 使用单个Windows命令从文件中提取N行
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Intersectional Internet
Safiya Umoja Noble、Brendesha M. Tynes / Peter Lang Publishing / 2016
From race, sex, class, and culture, the multidisciplinary field of Internet studies needs theoretical and methodological approaches that allow us to question the organization of social relations that ......一起来看看 《The Intersectional Internet》 这本书的介绍吧!