Создание отзывчивого реквизита для стилизованных компонентов - PullRequest
0 голосов
/ 27 октября 2019

Я пытаюсь создать отзывчивый реквизит для стилизованных компонентов следующим образом. Для начала у нас есть компонент (скажем, кнопка):

<Button primary large>Click Me</Button>

Эта кнопка получит цвет фона основного и большого размера (как определено в файле темы).

Теперь я хочу создать адаптивную версию этой кнопки. Вот как я бы хотел, чтобы это работало:

<Button 
  primary 
  large 
  mobile={{size: 'small', style: 'secondary'}}
  tablet={size: 'small'}} 
  widescreen={{style: 'accent'}}
>
  Click Me
</Button>

Теперь у меня есть та же кнопка, но с разными стилями и размерами для разных размеров экрана.

Теперь я получил этоработать - но это включает в себя много дублирующегося кода. Вот пример того, как это выглядит:

const Button = styled('button')(
  ({
    mobile,
    tablet,
    tabletOnly,
    desktop,
    widescreen
  }) => css`

      ${mobile &&
      css`
        @media screen and (max-width: ${theme.breakpoints.mobile.max}) {
          background-color: ${colors[mobile.style] || mobile.style};
          border: ${colors[mobile.style] || mobile.style};
          border-radius: ${radii[mobile.radius] || mobile.radius};
          color: ${mobile.style && rc(colors[mobile.style] || mobile.style)};

        }
      `}

    ${tablet &&
      css`
        @media screen and (min-width: ${theme.breakpoints.tablet.min}), print {
          background-color: ${colors[tablet.style] || tablet.style};
          border: ${colors[tablet.style] || tablet.style};
          border-radius: ${radii[tablet.radius] || tablet.radius};
          color: ${tablet.style && rc(colors[tablet.style] || tablet.style)};
        }
      `}

    ${tabletOnly &&
      css`
        @media screen and (min-width: ${theme.breakpoints.mobile.min}) and (max-width: ${theme.breakpoints.tablet.max}) {
          background-color: ${colors[tabletOnly.style] || tabletOnly.style};
          border: ${colors[tabletOnly.style] || tabletOnly.style};
          border-radius: ${radii[tabletOnly.radius] || tabletOnly.radius};
          color: ${tabletOnly.style &&
            rc(colors[tabletOnly.style] || tabletOnly.style)};
        }
      `}
`

Я ищу способ упростить этот код. По сути, я хочу написать CSS-стили ОДИН РАЗ, а затем сгенерировать различные реквизиты и медиа-запросы на основе объекта запроса, который выглядит примерно так:

const mediaQueries = {
  mobile: {
    min: '0px',
    max: '768px'
  },
  tablet: {
    print: true,
    min: '769px',
    max: '1023px'
  },
  desktop: {
    min: '1024px',
    max: '1215px'
  },
  widescreen: {
    min: '1216px',
    max: '1407px'
  },
  fullhd: {
    min: '1408px',
    max: null
  }
}

Я думаю, что я смогу создать функциюон проходит через объект mediaQueries и вставляет соответствующий css для каждой итерации. Однако я не могу понять, как это сделать.

Есть идеи, как это сделать?

Кроме того, заранее спасибо за любую помощь, которую вы можете предложить.

Ответы [ 2 ]

2 голосов
/ 27 октября 2019

Может быть, что-то вроде этого - то, что вы ищете:

import { css } from "styled-components";

//mobile first approach min-width
const screenSizes = {
  fullhd: 1408,
  widescreen: 1215,
  desktop: 1023,
  tablet: 768,
  mobile: 0
}
const media = Object
    .keys(screenSizes)
    .reduce((acc, label) => {
        acc[label] = (...args) => css`
            @media (min-width: ${screenSizes[label] / 16}rem) {
                ${css(...args)}
            }
        `
        return acc
    }, {});

Затем вы просто импортируете и используете так:

import media from './media'
const button = styled.button`
   ${({large , small})=> media.mobile`
      color: red;
      font-size: ${large ? '2em' : '1em'};
   `}
`

Вот некоторые дополнительные чтения, включая использование с темами:

Медиа-запросы в styleled-компонентах

Использование реквизитов:

Использование того же объекта медиа-запроса сверху:

Создание вспомогательной функции для форматирования объекта стилей в строку css:

const formatCss = (styleObject) => {
    return JSON.stringify(styleObject)
        .replace(/[{}"']/g,'')
        .replace(/,/g,';') 
        + ';'
}

Создание еще одной вспомогательной функции для сопоставления стилей и генерации запросов путем сопоставления ее ключей и динамического использования скобочной записи. запросы:

const mapQueries = (myQueries) =>{
    return Object.keys(myQueries).map(key=> media[key]`
        ${formatCss(myQueries[key])}
    `)
}

В вашем стилевом компоненте:

export const Button = styled.button`
    ${({myQueries}) => !myQueries ? '' : mapQueries(myQueries)}
`

Наконец добавьте реквизит myQueries к вашему компоненту следующим образом (обратите внимание на использование ключей css-formatted вместо javascriptFormattedключи для простоты):

<Button myQueries={{
    mobile:{ color:'red' },
    tablet:{ color:'blue', "background-color":'green'},
    desktop:{ height:'10rem' , width:'100%'}
}}>Button</Button>
0 голосов
/ 28 октября 2019

Для перебора всех ваших медиазапросов вы можете создать функцию, подобную:

import { css } from "styled-components";

const sizes = {
  desktop: 992,
  tablet: 768,
  phone: 576
};

// Iterate through the sizes and create a media template
const media = Object.keys(sizes).map(screenLabel => {
  return {
    query: (...args) => css`
      @media (max-width: ${sizes[screenLabel] / 16}em) {
        ${css(...args)}
      }
    `,
    screenLabel
  };
});

export default media;

Для использования в компоненте:

import media from "./media";

// The labels for this has to be same as the ones in sizes object
const colors = {
  phone: "red",
  tablet: "yellow",
  desktop: "green"
};

const Heading = styled.h2`
  color: blue;

  ${media.map(
    ({ query, screenLabel }) => query`
    color: ${colors[screenLabel]};
  `
  )}
`;
...