Styled Components入门教程

发布于1/17/2020 来自:「前端知否」微信公众号

Styled components是React社区中流行的CSS-in-JS库,它允许样式轻松地确定组件的范围,而不必担心CSS类命名约定。 实际上,您根本不会使用样式化的组件来创建类名称! 让我们深入了解更多信息,包括它们是否可以与TypeScript完美配合使用。

VS Code extension

推荐一个很棒的VS代码扩展,称为vscode-styled-components组件,它可以帮助我们在使用styled components时,突出显示语法并提供智能。

xxx

安装 styled components

我们可以使用以下npm命令安装具有相应TypeScript类型的styled components:

npm install styled-components
npm install @types/styled-components --save-dev

开始-无样式列表

我们以下边无样式列表为起点:

...

<div>
<ul>
{posts.map(({ id, title, body }) => (
<li key={id}>
<div>
<span>{title}</span>
<span>{body}</span>
</div>
</li>
))}
</ul>
</div>

...

浏览器中效果如下:

xxx

这效果不咋样,接下来我们使用styled components对其应用一些样式。

基本样式组件

我们使用样式化组件库中的样式化工厂函数创建样式化的组件,并在标记的模板文字中指定我们要呈现的HTML标签以及CSS:

import styled from 'styled-components';

const Container = styled.div`
width: 400px;
margin: 30px auto;
`;

const App = () => (
<Container>
<ul>
{posts.map(({ id, title, body }) => (
<li key={id}>
<div>
<span>{title}</span>
<span>{body}</span>
</div>
</li>
))}
</ul>
</Container>;
);

现在,我们创建了一个容器样式的组件,可以将其用作常规的React组件。

在CSS中引用变量

我们要在CSS中引用一些全局样式变量:

/* Grays */
export const gray1 = "#383737";
export const gray2 = "#565555";
export const gray3 = "#857c81";
export const gray4 = "#b9b9b9";
export const gray5 = "#e0dddd";

/* Colors */
export const primary1 = "#6ca583";
export const accent1 = "#9b8dab";

/* Fonts */
export const fontFamily = "'Segoe UI', 'Helvetica Neue',sansserif";
export const fontSize = "15px";

我们的样式化组件是带标签的模板文字,那么,我们可以使用插值法来引用变量:

...
import { fontFamily, fontSize, gray2 } from './Styles';

const Container = styled.div`
width: 400px;
margin: 30px auto;
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
`;

...

嵌套结构

我们可以嵌套CSS定义来像SCSS一样设置嵌套元素的样式:

const Container = styled.div`
width: 400px;
margin: 30px auto;
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
ul {
list-style: none;
padding: 0px 20px;
background-color: #fff;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top: 3px solid ${accent1};
box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.16);
li {
padding: 10px 0px;
border-top: 1px solid ${gray5};
:first-of-type {
border-top: none;
}
}
}
`;

还要注意我们如何引用伪元素。 我们在上面使用一个伪元素来删除第一个列表项的顶部边框。

创建单独的样式化的组件

最好将以上内容分成单独的组件,从而创造更多重用的机会:

const Container = styled.div`
width: 400px;
margin: 30px auto;
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
`;

const List = styled.ul`
list-style: none;
padding: 0px 20px;
background-color: #fff;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top: 3px solid ${accent1};
box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.16);
`;

const ListItem = styled.li`
display: flex;
flex-direction: column;
padding: 10px 0px;
border-top: 1px solid ${gray5};
:first-of-type {
border-top: none;
}
`;

const Title = styled.span`
font-size: 18px;
color: ${gray1};
margin-bottom: 5px;
`;

const App = () => (
<Container>
<List>
{posts.map(({ id, title, body }) => (
<ListItem key={id}>
<Title>{title}</Title>
<span>{body}</span>
</ListItem>
))}
</List>
</Container>;
);

现在,我们为列表及其项目以及每个项目中的标题创建了样式化的组件。

响应式组件

媒体查询怎么用呢?我们来看一看:

const Container = styled.div`
width: 400px;
margin: 30px auto;
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
@media (max-width: 400px) {
width: 100%;
}
`;

我们使列表在小型设备上占据了整个宽度。

继承

我们可以在另一个样式化的组件基础上建立样式化的组件:

const Text = styled.div`
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
`;

const Title = styled(Text)`
font-size: 18px;
color: ${gray1};
margin-bottom: 5px;
`;

现在,我们有一个Title组件,它从常规Text组件继承而来。

渲染不同的标签

在引用通用组件时,在某些情况下,我们可能希望将该组件渲染为其他标记。 我们可以使用as属性来做到这一点:

<Text size={20} as="p">
{body}
</Text>

我们一般的Text组件通常呈现为跨度,但我们使用as道具将其呈现为p。

Props(属性)

我们可以将属性传递给样式化的组件吗? 我们当然可以!

我们可以使用TypeScript接口定义道具,然后使用模板文字中的箭头函数在CSS中引用它们。 然后,我们照常在JSX中引用该prop:

...

interface ITextProps {
size?: string;
}

const Text = styled.div<ITextProps>`
font-family: ${fontFamily};
font-size: ${props => props.size || fontSize};
color: ${gray2};
`;

...


const App = () => (
<Container>
<List>
{posts.map(({ id, title, body }) => (
<ListItem key={id}>
<Title>{title}</Title>
<Text size="14px" as="p">
{body}
</Text>
</ListItem>
))}
</List>
</Container>
);

我们在Text组件上创建了一个可选的size属性,该属性回落到fontSize全局变量。

在浏览器中看起来啥样?

我们的列表看起来不错,但是那些奇怪的CSS类名是什么?

xxx

这些CSS类引用了我们在样式化组件中定义的样式。 因此,这些样式不是我可能认为的元素上的内联样式。 而是将样式保存在唯一的CSS类中。

呈现的页面中那些CSS类在哪里? 原来它们是通过样式标签注入HTML头的:

xxx

最后

Styled components是一种精巧的方法,用于对React组件的样式进行范围界定。 就像我们在SCSS中一样,我们能够使用嵌套的结构和变量来使用常规CSS编写样式非常好。 我们可以利用TypeScript对传递给样式化组件的道具进行强类型化。 乍看之下,随机出现的CSS类名称很奇怪,但是过一会儿您就会习惯它。