我在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不是类名,而是道具。但是,我想通过在组件上创建样式继承来保持代码干燥。
我该怎么办?
感谢您的帮助!
答案 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%完美(但我认为它仍然相当不错):