Пользовательский интерфейс материала реагирует на размер элемента

Я использую React и MaterialUI для создания системы, которая будет отображать виджеты внутри другого (не основанного на React) веб-сайта. Я хотел бы сделать виджеты адаптивными, но они должны реагировать на ширину своего контейнера, а не на ширину окна, так как я не знаю, какую часть страницы займет виджет.

Варианты, которые я рассмотрел:

  • Опрос размера контейнера на интервальной основе
  • Опрос размера контейнера в событиях изменения размера окна
  • Настройка точек останова темы на основе размера контейнера и окна при запуске

Мне все эти решения кажутся довольно уродливыми. Есть ли элегантный способ делать то, что я хочу?


person Marten Jacobs    schedule 08.03.2019    source источник


Ответы (2)


Чтобы различные @material-ui/core элементы занимали ровно столько места, сколько контейнер, в который вы их помещаете, я бы использовал компонент Grid.

Я использовал следующее:

<Grid container spacing={24}>
  <Grid item>
    Your content here
  </Grid>
</Grid>

Если вы также хотите, чтобы ваш элемент сетки реагировал на такие вещи, как размер экрана, вы можете сделать:

const grid = {
    xs: 24,
    sm: 24,
    md: 24,
    lg: 12,
    xl: 12,
};

а также

<Grid item {...grid}>

Документация: https://material-ui.com/layout/grid/

person Andrei    schedule 08.03.2019
comment
Спасибо, но я не это имел в виду. Проблема в том, что точки останова (где элемент сетки в вашем примере изменится с 24 на 12 столбцов) относятся к фактическому размеру окна браузера, а не к размеру контейнера для моего виджета. - person Marten Jacobs; 08.03.2019
comment
@MartenJacobs, вы нашли решение, которое вам подходит? У меня такая же потребность - person Xavier; 10.02.2020

Вместо точек останова вы можете прослушивать изменения размера компонента. Вы можете использовать хук response-use useMeasure для достижения этой цели (он полагается на ResizeObserver, который поддерживается всеми основными браузерами), как в следующем примере:

/** @jsx jsx */
import { css, jsx } from '@emotion/core';
import { faAddressBook, faCoffee } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useMeasure } from 'react-use';

const useMyComponentStyle = (params) => {
    const { color } = params;
    const [ref, { width }] = useMeasure();

    const borderColor = width < 150 ? 'red' : width < 400 ? 'yellow' : 'green';
    const icon = width < 250 ? faCoffee : faAddressBook;

    const style = css`
        color: ${color};
        padding: 10px;
        border: 1px solid ${borderColor};
    `;

    return {
        ref,
        style,
        icon,
        width,
    };
};

export const MyComponent = (props) => {
    const { ref, style, icon, width } = useMyComponentStyle(props);

    return (
        <div ref={ref} css={style}>
            <FontAwesomeIcon icon={icon} />
            {props.children} [[{parseInt('' + width)}px]]
        </div>
    );
};

const containerStyle = css`
    padding: 100px 200px;
    border: 1px solid blue;
`;

export const MyContainer = () => (
    <div css={containerStyle}>
        <MyComponent color='blue'></MyComponent>
    </div>
);

ReactDOM.render(<MyContainer />, document.getElementById('root'));

В приведенном выше примере для стилей css используется эмоция, но стиль можно определить с помощью другой библиотеки, например jss или стилизованные компоненты или даже простой встроенный стиль реакции.

Компонент MyComponent включен в компонент контейнера MyContainer, который имеет левую и правую padding со значением 200px, и при изменении размера окна браузера вы можете видеть, что border цвет MyComponent основан на размере самого компонента (red, если ширина компонента меньше 150px, yellow, если она меньше 400px, иначе green), не в зависимости от размера окна.

person Lucas Basquerotto    schedule 24.09.2020