前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >styled-components不完全手册

styled-components不完全手册

作者头像
前端柒八九
发布2024-03-25 18:18:57
530
发布2024-03-25 18:18:57
举报

❝一周是一年的2% ❞

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

最近在做项目梳理,然后无意中在一些国外的UI库中发现如下的代码示例。

大家仔细观察上面的代码,其实就是对常规的布局做了封装,我们可以通过通过<XXX >{chilren}</XXX>将对应的组件进行包裹。

这样做的好处就是

  1. 见名知意,通过组件的名称我们就可以知晓该页面使用了何种布局
  2. 布局样式和组件内部样式进行分割
  3. 统一管理

然后,它背后用的技术就是我们在CSS-in-JS。针对CSS-in-JS业界是褒贬不一。

上面列举了CSS-in-JS的各种利弊。这其实就是仁者见仁,智者见智。但是,我更看中它在抽离公共布局方面的应用。就像最开头的截图所示,我们可以不把现有项目中所有组件都css-in-js处理,但是我们可以对系统种常规布局进行抽离,这样我们项目就层级就更加清晰明了。

既然,它是有用的,那么我们今天就来聊聊CSS-in-JS。因为,CSS-in-JS有很多解决方案。(emotion[1]/styled-components[2])。

下面,我们就挑业界比较受欢迎的styled-components来进行讲解。

好了,天不早了,干点正事哇。

我们能所学到的知识点

  1. 初始化项目
  2. 基本用法
  3. 使用 Props
  4. 扩展样式
  5. 嵌套样式
  6. 扩展 React 组件
  7. CSS变量
  8. 添加主题
  9. 处理动画
  10. 使用 as 属性
  11. 默认属性


❝Styled-components[3] 是一个库,它允许你在构建 Reactjs 自定义组件时,使用 JavaScriptCSS。 ❞

1. 初始化项目

由于我们这里是一个技术讲解的文章,不需要额外的配置,所以我们就不用我们的f_cli[4]来构建项目了,我们就用最简单的方式(cra)来构建项目(当然也可以使用vite)

代码语言:javascript
复制
npx create-react-app styled_demo

由于每个脚手架都有自己内置的逻辑,我们需要删除一些默认的逻辑。在初始化后,我们只保留index.jsapp.js。并且对其做一些简单的修改,使其更适合我们的需求。

App.js

代码语言:javascript
复制
function App() {
  return <h1>Hello, Front789!</h1>;
}

export default App;

index.js

代码语言:javascript
复制
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <>
    <App />
  </>
);

安装 styled-components

安装 styled-components 的命令如下:

代码语言:javascript
复制
npm install styled-components

虽然我们这个项目就寥寥几个文件,但是它已经支持了styled-components的功能了。下面,我们就来学习一下它是如何工作的。


2. 基本用法

app.js 中,

  • 使用 <h1> 标签创建一个标题
  • 使用 <p> 标签创建一个段落
  • 使用 <button> 标签创建一个按钮
代码语言:javascript
复制
function App() {
  return (
    <div>
      <h1>Front789</h1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <button>我是按钮!</button>
    </div>
  );
}

export default App;

我们需要在 app.js 文件中导入 styled-components

代码语言:javascript
复制
import styled from "styled-components";

然后我们将创建我们的自定义组件 H1,并使用它代替 <h1> 标签,并添加自定义样式。

代码语言:javascript
复制
const H1 = styled.h1`
  color: red;
  font-size: 4rem;
`;
  • 首先,我们需要给它一个自定义的名称(H1)。
  • 然后,我们将从 styled.<HTML 标签名称> 开始,并用「反引号」括起样式。

现在,当我们使用这个自定义组件时,它将具有带有样式的 <HTML 标签名称> 属性。

代码语言:javascript
复制
import styled from "styled-components";

const H1 = styled.h1`
  color: red;
  font-size: 4rem;
`;

function App() {
  return (
    <div>
      <H1>Front789</H1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <button>我是按钮!</button>
    </div>
  );
}

export default App;

我们在页面中就会看多对应的效果图。

上面有几个点需要注意

  1. 我们使用了 styled.h1 来创建 H1,此时H1就是一个自定义组件,在 React 中, 始终使用「大写字母」来自定义组件名称
  2. 我们在浏览器DevTool->Elements种看到,与H1对应的h1元素自动添加了一个class,并且其值是一组hash值,这样做是为了避免「命名冲突」

现在让我们为我们的按钮组件添加样式:

代码语言:javascript
复制
const DefaultButton = styled.button`
  background-color: #645cfc;
  border: none;
  padding: 10px;
  color: white;
`;

DefaultButton 是我们的自定义组件名称。在我们给它样式之后,我们可以给它任何我们想要的 HTML 标签,以便这个自定义组件将拥有该标签。

现在我们将使用上面创建的 DefaultButton 作为我们的自定义组件在 React.js 中使用。

代码语言:javascript
复制
import styled from "styled-components";

const H1 = styled.h1`
  color: red;
`;

const DefaultButton = styled.button`
  background-color: #645cfc;
  border: none;
  padding: 10px;
  color: white;
`;

function App() {
  return (
    <div>
      <H1>Front789</H1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <DefaultButton>我是按钮!</DefaultButton>
    </div>
  );
}

export default App;

我们也可以通过为每个不同的组件在 styled-components 中创建一个不同的文件来保持我们的文件清晰。

我们将在 src 中创建一个名为 components 的新文件夹,并创建文件 Title.jsButtons.js 来分离标题和按钮的样式。

我们将 H1 样式复制并粘贴到 Title.js 中,并将 DefaultButton 样式复制并粘贴到 Buttons.js 中。

现在我们的App.js 看起来是这样的:

代码语言:javascript
复制
import H1 from "./components/Title";
import { DefaultButton } from "./components/Buttons";

function App() {
  return (
    <div>
      <H1>Front789</H1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <DefaultButton>我是按钮!</DefaultButton>
    </div>
  );
}

export default App;

3. 使用 Props

对于React组件来讲,Props是一个至关重要的特性,通过Props我们可以从组件调用处向组件内部传入对应的运行时参数,然后基于运行时的逻辑进行展示操作。

使用styled components定义的组件也可以接受props

代码语言:javascript
复制
import H1 from './components/Title'
import {DefaultButton} from './components/Buttons'


function App() {
  return (
    <div>
      <H1>Front789</H1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <DefaultButton>我是按钮!</DefaultButton>
      <DefaultButton red>带属性的按钮!</DefaultButton>
    </div>
  );
}

export default App;

在上面的代码中,我创建了另一个 DefaultButton。但是相较于之前的DefaultButton,第二个DefaultButton拥有了额外的属性red

也就是说,我们希望第二个DefaultButton在运行时执行额外的展示逻辑。

代码语言:javascript
复制
import styled from 'styled-components'

export const DefaultButton = styled.button`
background-color:  ${(props) => (props.red && 'red') || '#645cfc'};
border: none;
padding: 10px;
color: white;
`

我们在使用styled-components定义组件时,使用了模板字面量也就意味着可以在其中写 JavaScript。在这些大括号中,我们声明了一个箭头函数,它有一个 props 参数,可以访问自定义组件的属性。箭头函数表示如果给定了 red 属性,则背景颜色应为红色,否则应为蓝莓色。

当然,我们还可以通过对props进行解构处理,通过 {} 和属性名称来解构 props

与其使用 props.red 进行访问,我们可以。

代码语言:javascript
复制
import styled from 'styled-components'

export const DefaultButton = styled.button`
background-color:  ${({red}) => (red && 'red') || '#645cfc'};
border: none;
padding: 10px;
color: white;
`

现在我们可以直接使用 red 而不是 props.red


4. 扩展样式

通过上述的操作,我们已经拥有了一定样式封装能力的自定义组件了。此时,我们想在之前组件的基础上进行二次封装。从语言开发的角度来讲,就是我们想继承之前的样式,并且做额外的操作。此时我们可以使用在 styled components 中扩展样式来实现。

我们只需要简单一步操作即可完成。之前我们是用styled.<html 标签>来定义自定义组件,而进行样式扩展的话,我们可以使用styled(xx)

我们以DefaultButton为例,想要在DefaultButton样式的基础上做额外的扩展,我们可以通过styled(DefaultButton)来重新定义一个新的组件,并且在实现过程中,它拥有除了DefaultButton之外的样式逻辑。

ExtendedButton定义

代码语言:javascript
复制
export const ExtendedButton = styled(DefaultButton)`
display: block;
width: 100vw;

App.js

代码语言:javascript
复制
import H1 from "./components/Title";
import { DefaultButton,ExtendedButton } from "./components/Buttons";

function App() {
  return (
   <div>
      <H1>Front789</H1>
      <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      <DefaultButton>我是按钮!</DefaultButton>
      <ExtendedButton red>扩展按钮!</ExtendedButton>
  </div>
  );
}

export default App;

这样,我们就可以拥有一个在DefaultButton样式基础上,扩展了width:100vw的新组件。


5. 嵌套样式

当然,现在的前端样式已经不满足之前介绍的针对单个元素的样式封装。我们还可以拥有像less/scss一样的样式嵌套。这样我们就可以在一个样式逻辑种处理其内部的多个子元素。实现更好的封装。

代码语言:javascript
复制
import styled from 'styled-components';

const Wrapper = styled.div`
h1{
  text-align: center;
  color: violet;
}

p{
  font-size: 40px;
}

button{
  background-color: pink;
  padding: 4px 8px;
  border: none;  
}
`
function App() {
  return (
    <div>
      <Wrapper>
        <h1>Front789</h1>
        <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
        <button>我是按钮!</button>
      </Wrapper>
  </div>
  );
}

export default App;

当我们在页面中使用了Wrapper后,内部的所有<p>标签都将具有 40px 的字体大小,<button>将具有粉色的背景颜色、指定的填充和无边框。


6. 扩展 React 组件

我们使用styled components还可以处理用常规方式构建的React组件。此时,我们只需要将之前的组件放到styled(xx)中即可。(需要做一点小的变更)

假如我们有如下的 react 组件

代码语言:javascript
复制
const Oldcom = () => {
  return (
    <div>
        <h2>Front789</h2>
        <button>按钮!</button>
    </div>
  )
}

如果我们想通过styled components对其处理,我们需要对其做一下改造。需要在props中接受className,并且讲其放置到组件的根元素上,然后就可以利用styled components嵌套样式对其内部的元素进行样式处理。

代码语言:javascript
复制
import React from 'react'
import styled from 'styled-components'

export const Oldcom = ({className}) => {
  return (
    <div className={className}>
        <h2>Front789</h2>
        <button>按钮!</button>
    </div>
  )
}

export const NewCom = styled(Oldcom)`
h2{
    color: green;
    text-align: center;
}

button{
    padding: 4px 10px;
    background-color: violet;
    border: none;
}
`


7. CSS变量

使用styled components构建的组件,还支持使用css变量。这样,我们在组件内部接收一些团队定义的变量,来处理指定的样式逻辑。

让我们来看看它是如何实现的。

现在在 src 文件夹中创建一个 index.css 文件,该文件中编写一些 CSS 变量,这些变量是从任何地方都可以访问的「全局样式」

index.css

代码语言:javascript
复制
:root{
--primary-color: #8F00FF
}

现在 :root{} 就像在 CSS 中选择 html{} 一样。但是 :root{} 的优先级比 html{} 更高。

CSS有两种方式来选择HTML文档的根元素

  1. :root 伪类
  2. html 选择器

选择器的特异性

:root 选择器的优先级高于 html 选择器。这是因为 :root 是一个伪类选择器,而 html 是一个类型选择器

代码语言:javascript
复制
:root {
 background-color: red;
}
html {
 background-color: blue;
}
/* HTML 文档的根元素将具有红色的背景颜色。 */

目标化根元素

除了 HTML 外,CSS 还可以用于样式化其他类型的文档。这就是 :root 元素发挥作用的地方,它允许你样式化文档的根元素。当样式化 SVG 文档时,这可能特别重要,因为 html 选择器不起作用。

然后,我们可以在styled components定义的组件种使用这个css变量。(当然,别忘了在index.js中导入index.css

代码语言:javascript
复制
const Newcom = styled(Oldcom)`
h2{
    color: green;
    text-align: center;
}

button{
    padding: 4px 10px;
    background-color: var(--primary-color);
    border: none;
}

8. 添加主题

有些网站还需要一些明暗主题的切换。使用styled components可以轻松实现这一点。

  1. 首先,我们需要从 styled components 中导入 ThemeProvider
  2. 然后将整个应用程序包装在 ThemeProvider 中,并在其中提供我们的主题。
  3. 使用styled component定义一个组件(Container),在其内部可以访问主题及其属性,并帮助用户更改背景颜色和文本颜色
  4. 我们可以定义一个操作(按钮点击)来更换theme变量 具体实现代码如下:
代码语言:javascript
复制
import styled, { ThemeProvider } from 'styled-components'
import React, { useState } from 'react'
import {DefaultButton } from './components/Buttons'

const lightTheme = {
  background: '#fff',
  color: '#222',
}
const darkTheme = {
  background: '#222',
  color: '#fff',
}

const Container = styled.div`
color: ${(props) => props.theme.color};
background-color: ${(props) => props.theme.background};
height: 100vh;
`
function App() {
  const [theme,setTheme] = useState(lightTheme)
  return (
    <ThemeProvider theme={theme}>
      <DefaultButton onClick={() => 
        setTheme(theme === lightTheme ? darkTheme : lightTheme)
      }>切换主题</DefaultButton>
      <Container>
        <p>专注于前端开发技术/Rust及AI应用知识分享的Coder</p>
      </Container>
    </ThemeProvider>
  );
}

export default App;


9. 处理动画

styled components还支持动画,我们可以从 styled-components 中导入 keyframes,用它来创建动画。

代码语言:javascript
复制
import styled, {keyframes} from 'styled-components'

const spinner = keyframes`
to{
 transform: rotate(360deg);
}
`

const Loading = styled.div`
width: 6rem;
height: 6rem;
border: 5px solid #ccc;
border-radius: 50%;
border-top-color: black;
animation: ${spinner} 0.6s linear infinite;
`

export default Loading

在上面的代码中,我们定义了 spinner 动画,spinner 是动画的名称。在 Loading 中,我们使用了 spinner 动画名称,以便 Loading 使用该动画。


10. 使用 as 属性

如果我有一个按钮,并给它一个 href 属性,我们用它来跳转到另一个网站,它将不起作用。这是因为 href<a>标签的特有属性。

代码语言:javascript
复制
import React from 'react'
import {DefaultButton} from './components/Buttons'

const App = () => {
  return (
    <div>
      <DefaultButton as="a" href="https://www.google.com">跳转到指定网站</DefaultButton>
    </div>
  )
}

export default App

运行代码后,我们发现是跳转不了的,但是呢,通过styled-components定义的组件,我们可以使用as ="x",使其给定的组件能够拥有x的功能。

代码语言:javascript
复制
import React from 'react'
import {DefaultButton} from './components/Buttons'

const App = () => {
  return (
    <div>
      <DefaultButton 
        as='a' 
        href="https://www.google.com"
      >
        跳转到指定网站
      </DefaultButton>
    </div>
  )
}

export default App

现在 DefaultButton 是一个<a>

  • 它将具有 text-decoration,因为在默认锚标签中它具有 text-decoration
  • 当我们点击我们的 DefaultButton 时,它将打开 Google

11. 默认属性

HTML 的某些元素上我们有属性。例如在按钮上,我们有 type="submit"type="button"。但是每次我们都必须手动设置它们。

代码语言:javascript
复制
import React from 'react'
import styled from 'styled-components'

const Button = styled.button`
border: none;
padding: 5px 10px;
background-color: #87CD11;
margin: 10px;
`

const App = () => {
  return (
    <div>
      <Button type="button">点击!</Button>
      <Button type="submit">提交</Button>
    </div>
  )
}

export default App

使用styled-components定义的组件,设置默认属性非常方便。我们可以将对象或函数传递给它们。但是,如果我们将对象传递给属性,那么它们将是静态的。为了具有动态控制,我们将一个函数传递给属性。

代码语言:javascript
复制
import React from 'react'
import styled from 'styled-components'

const Button = styled.button.attrs((props) => {
  return {type: props.type || "button"}
})`
border: none;
padding: 5px 10px;
background-color: #87CD11;
margin: 10px;
`

const App = () => {
  return (
    <div>
      <Button>点击!</Button>
      <Button type="submit">提交</Button>
    </div>
  )
}

export default App

在上面的代码中,我们为按钮设置了属性。这意味着

  • 如果给定了 type,则它将将该 type 设置为给定的 props
  • 如果没有给定 props,则默认将其设置为按钮
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端柒八九 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
    • 我们能所学到的知识点
    • 1. 初始化项目
      • App.js
        • index.js
          • 安装 styled-components
          • 2. 基本用法
          • 3. 使用 Props
          • 4. 扩展样式
            • ExtendedButton定义
              • App.js
              • 5. 嵌套样式
              • 6. 扩展 React 组件
              • 7. CSS变量
                • index.css
                • 选择器的特异性
                • 目标化根元素
                • 8. 添加主题
                • 9. 处理动画
                • 10. 使用 as 属性
                • 11. 默认属性
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档