需求:
- 多条数据展示,每条数据的文本内容不超过一行
- 文本内容为一行时,不显示 展开收起icon图标
- 文本超过一行时,内容单行省略,并且显示⬇️
- 点击图标,图标切换为收起按钮, ⬆️
// 后端返回数据
const data = [
{
name: '测试测试测试',
time: '2022-07-06 18:50:08',
remark:
'测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试',
},
{
name: '测试测试测试',
time: '2022-07-06 18:50:08',
remark:
'测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试',
},
{
name: '测试测试测试',
time: '2022-07-06 18:50:08',
remark:
'测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试',
},
]
使用useEffect处理
// 监听文本的可视宽度(ref.current.clientWidth)和滚动宽度 (ref.current.scrollWidth)
const ref = useRef<HTMLDivElement>(null)
// 利用可视宽度和滚动宽度比较来判断是否显示此按钮
// 依赖数据长度以及刷新
useEffect(() => {
if (data && !isLoading) {
const dataObj = [...data]
dataObj.map((item: { isShow: boolean }) => {
// 为每一条数据添加isShow 来控制文本显示和按钮显示
if (!item.isShow) {
item.isShow = false
}
})
mutate(dataObj) // mutate 重新请求数据
}
}, [data?.length, isLoading])
函数方法
// 点击展示或收起数据
const handlerChange = (val: number) => {
const arr = [...data]
arr.map((item: { isShow: boolean }, index: number) => {
if (index === val) {
item.isShow = !item.isShow
}
})
mutate(arr) // mutate 重新请求数据
}
数据渲染
// 数据渲染
{data.map(
(item: {
name: string
time: string
remark: string
isShow: boolean
},
index: number
) => (
<Main rows={!item.isShow ? 1 : 9999} key={index}>
<div className="point_title">
<div className="title_text">{item.name}</div>
</div>
<div className="point_time">
{item.time.replace(/-/g, '/')}
</div>
<div className="point_remark">
<div className="remark_text" ref={ref}>
{item.remark}
</div>
{(item.isShow ||
(ref.current &&
ref.current.clientWidth < ref.current.scrollWidth)) && (
<div
onClick={() => handlerChange(index)}
className="remark_icon"
>
{item.isShow ? (
<ArrowUp className="icon" />
) : (
<ArrowDown className="icon" />
)}
</div>
)}
</div>
</Main>
)
)}
样式渲染
const Main = styled.div<{
rows: number
}>`
margin: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #ededed;
.icon {
width: 14px;
height: 14px;
}
.point_title {
display: flex;
justify-content: space-between;
.title_text {
font-family: 'PingFangSC-Medium';
font-size: 14px;
color: #262626;
line-height: 22px;
font-weight: 500;
flex: 1 1;
}
}
.point_time {
margin-top: 4px;
margin-bottom: 4px;
font-family: 'PingFangSC-Regular';
font-size: 12px;
color: #8c8c8c;
line-height: 20px;
font-weight: 400;
height: 20px;
}
.point_remark {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #8c8c8c;
line-height: 20px;
font-weight: 400;
.remark_text {
width: 313px;
${(p) => MultiLineOmission(p.rows)}; // 多行省略
}
.remark_icon {
display: flex;
align-items: center;
}
}
`
export { Main }
多行省略的实现
// 多行省略
const MultiLineOmission = (line = 3) => css`
display: ${() => line !== 1 && '-webkit-box'};
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: ${() => line};
-webkit-box-orient: vertical;
word-break: break-all;
white-space: ${() => line === 1 && 'nowrap'};
`
export { MultiLineOmission }
总结:
- 注意是每一条数据,因此需要给每一条数据添加 isShow
- 点击时传入每一条数据的id值,如果没有id也可以使用index,将此条数据的item.isShow变为!item.isShow,然后进行重新刷新数据。