Ant Design Pro - 實踐React Hooks - 組件

需求

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

設計

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

單元格寬度

這一列咱們只能使用相對寬度,由於整個表格是自適應寬度的,若是用固定寬度,可能在大屏上,這一列顯得很窄。 dom

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

組件寬度

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

提示框

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

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

  • 文本真實寬度:渲染完成後,經過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的依賴設置很是靈活好用。ip

    • 不設置,每次更新都會觸發。
    • 設置爲空,只在第一次加載時觸發。
    • 設置爲其餘狀態、或props中的狀態時,只在這些狀態變化時觸發(*注意,依賴爲對象時,不會深比較)。
  • 得益於useState, useEffect的用法靈活,Hooks組件寫法上確實簡潔很多。
相關文章
相關標籤/搜索