样式化的组件,两层className-如何在组件声明中应用样式?

时间:2020-09-11 22:02:29

标签: css reactjs styles next

我在next.js中创建了具有组件样式的Container组件。 当我在整个站点中声明使用此容器组件时,我想为其添加一个className并根据其使用的上下文主观地设置其样式。

这是我的容器组件的一个示例:

    const Container = (props) => (
    <>
        <div className="container">
            {props.children}
        </div>

        <style jsx>{`
            .container{
                width: 100%;
                max-width: 1200px;
                margin: 0 auto;
            }
        `}</style>
    </>
)

export default Container;

所以,我想给它最大宽度为1200px,并用自动边距将其居中。没问题,我已经做到了。

现在,我打算在我的网站标题中使用此组件。但是对于标题,我希望Container组件是一个flexbox:

import Container from './Container'

const Header = (props) => (
    <>
        <header>
            <Container className="header-col">
                <div>
                    <h1>{props.title}</h1>
                </div>
                <nav>
                    <ul>
                        {/* Navigation items */}
                    </ul>
                </nav>
            </Container>
        </header>

        <style jsx>{`
            .header-col{
                display: flex;
                justify-content: space-between;
            }
        `}</style>
    </>
)

export default Header;

当我查看站点时,我注意到为标题中的Container组件指定的flexbox样式不存在。

我希望className生效,并允许我添加其他样式。

我认为这与类名有关,因为className不是类名,而是道具。但是,我想通过在组件上创建样式继承来保持代码干燥。

我该怎么办?

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

这是样式组件的工作:

import React from "react";
import styled from "styled-components";

export default function App() {
  return (
    <>
      <Container custom={"header"}>
        <h1>Very fancy h1 with flex display</h1>
      </Container>
      <Container custom={"regular"}>
        <h1>Non-fancy h1 with no flex display</h1>
      </Container>
    </>
  );
}

const Container = styled.div`
  display: ${(props) => (props.custom === "header" ? "flex" : "block")};
  /* you can call your prop ^^^^^^ whatever you want, 
  just change it on the container element too*/

  & h1 {
    /* you can apply css to children like so */

    font-family: ${(props) =>
      props.custom === "header"
        ? '"Courier New", Courier, monospace'
        : '"Arial Black", Gadget, sans-serif'};
  }
`;

在上面,我创建了一个自定义样式的组件,该组件接收custom道具,然后有条件地更改要调整的值。为了使更改更直观,我还对字体进行了样式设置,以便您可以看到两个<Container>元素之间的直接差异。


对于更具可扩展性的解决方案(例如,针对不同主题),请使用ThemeProvider

import React from "react";
import styled, { ThemeProvider } from "styled-components";

export default function App() {
  return (
    <>
      <ThemeProvider theme={ContainerHeader}>
        <Container>
          <h1>Very fancy h1 with flex display</h1>
        </Container>
      </ThemeProvider>
      <Container theme={"regular"}>
        <h1>Non-fancy h1 with no flex display</h1>
      </Container>
    </>
  );
}

const Container = styled.div`
  display: ${(props) => props.theme.display};
  & h1 {
    font-family: ${(props) => props.theme.h1Font};
  }
`;

Container.defaultProps = {
  theme: {
    display: "block",
    h1Font: '"Arial Black", Gadget, sans-serif'
  }
};

const ContainerHeader = {
  display: "flex",
  h1Font: '"Courier New", Courier, monospace'
};

CodeSandbox:https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773

答案 1 :(得分:0)

相信我已经找到了我自己问题的答案(为了让问题得以改善,我还会再待几天这个问题)。

为了传递样式,可以在样式化的JSX中添加“ global”标志,并在组件中使用props.className附加其他类名。

使用props.className的父容器组件:

const Container = (props) => (
    <>
        <div className={`container ${props.className}`}>
            {props.children}
        </div>

        <style jsx>{`
            .container{
                width: 100%;
                max-width: 1200px;
                margin: 0 auto;
            }
        `}</style>
    </>
)

export default Container;

然后,当您要使用该组件时,可以在global中使用带有<style jsx>标志的其他样式:

在标题中使用和设置样式更多的容器:

import Container from './Container';

const Header = (props) => (
    <>
        <header>
            <Container className="header-col">

                <div>
                    <h1>{props.title}</h1>
                </div>


                <nav>
                    <ul>
                        <li>Hello</li>
                        <li>There</li>
                    </ul>
                </nav>
            </Container>
        </header>

        <style jsx global>{`
            .header-col{
                display: flex;
                justify-content: space-between;
            }
        `}</style>
    </>
)

export default Header;

虽然这并不是100%完美(但我认为它仍然相当不错):

  • 全局标志使您的样式具有全局性。所以其他组件可以使用 这些样式(我相信)
  • 您需要确保组件采用props.className才能为该全局样式附加其他类名。