#javascript #reactjs #react-redux #react-hooks #material-ui
Вопрос:
У меня есть автозаполнение пользовательского интерфейса материала, подобное этому
Я хочу вычислить, что четвертая микросхема перенесена на следующую строку, чтобы я мог выполнить дальнейшие вычисления. Есть ли способ сделать это в javascript/реагировать с помощью этого автозаполнения пользовательского интерфейса материала.
До сих пор документация пользовательского интерфейса материала автозаполнения не помогает в этом случае.
В основном то, что мне нужно сделать, это сделать число 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 amp;amp; 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;
};
And useOnResize
is using Resize Observer API to calculate width of the changing autocomplete container
import { useEffect } from 'react';
import isFunction from 'lodash-es/isFunction';
const useOnResize = (componentRef, callback) => {
const shouldMountObserver = isFunction(callback) amp;amp; componentRef?.current;
const resizeObserver =
shouldMountObserver amp;amp;
new ResizeObserver((entries) => {
for (const entry of entries) {
const { width: detectedWidth } = entry.contentRect;
callback(detectedWidth);
}
});
useEffect(() => {
const savedRef = componentRef?.current;
shouldMountObserver amp;amp; 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;