【react】文本内容超过一行,显示为单行省略,并且出现icon图标;点击此图标,可以进行展开或收起文本功能实现

需求:

  1. 多条数据展示,每条数据的文本内容不超过一行
  2. 文本内容为一行时,不显示 展开收起icon图标
  3. 文本超过一行时,内容单行省略,并且显示⬇️
  4. 点击图标,图标切换为收起按钮, ⬆️
// 后端返回数据
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 }

总结:

  1. 注意是每一条数据,因此需要给每一条数据添加 isShow
  2. 点击时传入每一条数据的id值,如果没有id也可以使用index,将此条数据的item.isShow变为!item.isShow,然后进行重新刷新数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值