Ant Design Pro - 實踐React Hooks - 組件

需求

後臺項目,使用Ant Design Pro, 有這樣一個需求:有一個表格,寬度是自適應的,表格中有一列是備註,文本長度不定,我們希望在文本過長的時候,使用省略樣式(ellipsis),同時鼠標懸浮時有提示框展示完整文本。

設計

我計劃設計一個React Hooks組件,嵌在表格裏面,實現文本的自適應省略樣式。

單元格寬度

這一列我們只能使用相對寬度,因爲整個表格是自適應寬度的,如果用固定寬度,可能在大屏上,這一列顯得很窄。

這裏我用百分比,同時在頁面組件維護一個寬度狀態,在mounted之後,按百分比計算這一列的寬度並更新狀態,如:clientWidth * 0.2。另外,監聽window resize事件,更新寬度狀態。

組件寬度

列寬計算出來之後,會通過props傳給組件,有了寬度,利用:text-overflow: ellipsis; 就可以實現動態寬度的文本省略了。

提示框

這個提示框是在超長時纔有,不超長時是沒有的。這個是比較麻煩的一點,因爲你要知道當前是不是在超長省略狀態,我們需要這個狀態來設置是否加提示框。

爲了實現這個功能,我加了兩個Hooks狀態:是否超長、文本真實寬度。

  • 文本真實寬度:渲染完成後,通過dom獲取元素寬度。
  • 是否超長:比較文本真實寬度和組件的寬度。

實現

這裏我就直接貼代碼了,在後面會理一下關鍵點。

export default function LineEllipsis(props) {
  const { children, width = '200px', ...restProps } = props;
  const [textWidth, setTextWidth] = useState(0);
  const [isOverflow, setIsOverflow] = useState(false);
  const textRef = useRef(null);
  const textStyles = {
    width,
    display: 'inline-block',
    overflow: 'hidden',
    wordWrap: 'nowrap',
    textOverflow: 'ellipsis',
  };

  useEffect(
    () => {
      if (textRef) {
        const { current } = textRef;
        const clientWidth = current.clientWidth;
        setTextWidth(clientWidth);
        if (!isOverflow && clientWidth > parseInt(width)) {
          setIsOverflow(true);
        } else if (isOverflow && clientWidth < parseInt(width)) {
          setIsOverflow(false);
        }
      }
    },
    [children]
  );

  useEffect(
    () => {
      if (textRef && textWidth > 0) {
        if (!isOverflow && textWidth > parseInt(width)) {
          setIsOverflow(true);
        } else if (isOverflow && textWidth < parseInt(width)) {
          setIsOverflow(false);
        }
      }
    },
    [width]
  );

  const textRender = () => {
    return (
      <span
        ref={textRef}
        style={isOverflow ? textStyles : { display: 'inline-block' }}
        {...restProps}
      >
        {children}
      </span>
    );
  };

  return (
    <div style={{ width }}>
      {isOverflow ? (
        <Popover content={<pre className={styles.pop}>{children}</pre>}>{textRender()}</Popover>
      ) : (
        textRender()
      )}
    </div>
  );
}

關鍵點:

  • span的樣式,要設置爲inline-block,方便取到文本寬度。
  • 文本可能會更新,所以需要監聽children對象,變化時更新文本寬度、是否超長。
  • 組件寬度是根據props參數動態適應,所以也需要監聽,變化時要更新是否超長的狀態。

總結

第二次使用React Hooks,確確實實感受到了好處。

  • userEffect的依賴設置非常靈活好用。

    • 不設置,每次更新都會觸發。
    • 設置爲空,只在第一次加載時觸發。
    • 設置爲其他狀態、或props中的狀態時,只在這些狀態變化時觸發(*注意,依賴爲對象時,不會深比較)。
  • 得益於useState, useEffect的用法靈活,Hooks組件寫法上確實簡潔不少。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章