首页 > 解决方案 > 如何在材料 ui 自动完成中找到哪个芯片被包裹到下一行

问题描述

我有一个像这样的材料 ui 自动完成

自动完成

我想计算第四个芯片包裹到下一行,以便我可以进行进一步的计算。有没有办法在 javascript/react 中使用这种材料 UI 的自动完成来做到这一点。

到目前为止,自动完成材料 ui 的文档在这种情况下没有帮助。

基本上我要做的是使数字limitTags动态化,以便在更改自动完成的宽度时相应地设置limitTags,而不是静态数字。到目前为止,我的想法是计算每个标签的宽度,将其全部添加并与容器宽度进行比较。这已经完成但它仍然是错误的,因为正如您在所附图像中看到的那样,即使标签的组合长度小于容器宽度,limitTags 是 4,但它应该是 3,因为最后一个包裹到下一个线。现在我又被困住了。如何检测包装到下一行的第一个标签中的哪一个以计算limitTags

这是我到目前为止所做的

const DEFAULT_LIMIT_TAGS = -1;

const useLimitTags = (value, autoCompleteContainerRef, tagRef) => {
  const [limitTags, setLimitTags] = useState(DEFAULT_LIMIT_TAGS);
  const [autoCompleteContainerWidth, setAutoCompleteContainerWidth] = useState(0);
  const parentNode = useRef(null);

  useOnResize(autoCompleteContainerRef, setAutoCompleteContainerWidth);

  useLayoutEffect(() => {
    if (!parentNode.current && tagRef?.current) {
      parentNode.current = tagRef.current.parentNode;
    }

    if (parentNode?.current) {
      const children = [...parentNode.current.children];
      const tags = children.slice(0, value.length);
      const endAdornmentWidth = children[children.length - 2].offsetWidth;
      const containerWidth = autoCompleteContainerWidth - endAdornmentWidth - 20; // 20 is the margin around the last closing icon and the dropd own icon

      const tagsCombinedWidth = tags.reduce((sum, child, index, arr) => {
        const tagsWidth = sum + child.offsetWidth;

        if (tagsWidth > containerWidth) {
          setLimitTags(index - 1);
          arr.splice(0, index + 1); // break
        }

        return tagsWidth;
      }, 0);

      if (tagsCombinedWidth <= containerWidth) {
        setLimitTags(DEFAULT_LIMIT_TAGS);
      }
    }
  }, [value, autoCompleteContainerWidth, tagRef]);

  return limitTags;
};

并且useOnResize正在使用 Resize Observer API 来计算不断变化的自动完成容器的宽度

import { useEffect } from 'react';
import isFunction from 'lodash-es/isFunction';

const useOnResize = (componentRef, callback) => {
  const shouldMountObserver = isFunction(callback) && componentRef?.current;
  const resizeObserver =
    shouldMountObserver &&
    new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width: detectedWidth } = entry.contentRect;
        callback(detectedWidth);
      }
    });
  useEffect(() => {
    const savedRef = componentRef?.current;
    shouldMountObserver && resizeObserver?.observe(componentRef.current);

    return () => {
      if (savedRef) {
        resizeObserver?.unobserve(savedRef);
      }
    }; // Resized observer omitted in deps array on purpose as it is not supposed to change between rerender
  }, [componentRef?.current]); // eslint-disable-line react-hooks/exhaustive-deps
};

export default useOnResize;

标签: javascriptreactjsreact-reduxreact-hooksmaterial-ui

解决方案


推荐阅读