1
头图
自动计算宽高的 react 组件

github地址:https://github.com/niexq/reac... 欢迎 Star

🏠 主页预览

📦 安装

  yarn add @oyyds/react-auto-sizer  # or npm i @oyyds/react-auto-sizer -S

🔨 使用

import AutoSizer from '@oyyds/react-auto-sizer';

const AutoSizeComponent = () => {
  return (
    <div>
      <AutoSizer>
        {({ width, height }) => (
          <div
            style={{
              width,
              height,
            }}
          >
            内容区
          </div>
        )}
      </AutoSizer>
    </div>
  );
};

🧩 业务场景

现在大部分业务场景需要兼容大数据,例如大数据表格,大数据树,大数据下拉框等等,而所有的大数据组件都需要指定 宽高,实际业务界面大部分需要实时计算宽高,而 react-auto-sizer就是来完成自动计算宽高的使命

🧑‍💻 编码实现

期初预研 windows 上绑定 resize,但因 resize 会在窗体变化时,会有性能问题,部分极端像素情况下会出现抖动;

ResizeObserver,接口可以监听到 Element 的内容区域或 SVGElement 的边界框改变。内容区域则需要减去内边距padding。 -- 摘自 MDN

ResizeObserver天选之子, 使用 react hook useEffect,核心代码如下:


const updateState = useCallback(
    (newWidth: number, newHeight: number, entry: ResizeObserverEntry) => {
      // 省略更新state
      // 回调传入 width, height
      props.onResize({ width: newWidth, height: newHeight }, entry);
    },
    [childParams, disableHeight, disableWidth, onResize],
  );

const observer = useMemo(
    () =>
      new ResizeObserver((entries: ResizeObserverEntry[]) => {
        for (const entry of entries) {
          const contentRect = entry.contentRect;
          const width = Math.trunc(contentRect?.width || 0);
          const height = Math.trunc(contentRect?.height || 0);
          updateState(width, height, entry);
        }
      }),
    [updateState],
  );
  
useEffect(() => {
    if (!_autoSizerRef?.current?.parentNode) {
      throw new Error('Not Found AutoSizer parentNode');
    }
    observer.observe(_autoSizerRef?.current?.parentNode as Element);
    return () => {
      observer.disconnect();
    };
  }, [observer]);

重点:

observer.observe(_autoSizerRef?.current?.parentNode as Element),监听父级dom节点

contentRect: ResizeObserverEntry返回一个DOMRectReadOnly 的只读属性contentRect, 包含观察元素的新大小的对象,属性:

{
  "x": 0,
  "y": 0,
  "width": 300,
  "height": 200,
  "top": 0,
  "right": 300,
  "bottom": 200,
  "left": 0
}

contentRect返回是content box,也就是内容区域的尺寸(详细原因可参考张鑫旭大佬的ResizeObserver简介)

所以 contentRect.widthcontentRect.height就是我们最终需要的宽高

🐳 灵感来源

react-virtualized-auto-sizer
ResizeObserver
检测DOM尺寸变化JS API ResizeObserver

🐠 往期水文

不用递归生成无限层级的树

基于qiankun微前端实战部署


八米乐
12 声望0 粉丝