内容简介:随着管理的文章数量增多,默认的几个分类满足不了现状了...趁着重构的过程把相关的功能考虑进去本来想自己从头写过一个,看了下
随着管理的文章数量增多,默认的几个分类满足不了现状了...
趁着重构的过程把相关的功能考虑进去
本来想自己从头写过一个,看了下 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行
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。