React--》掌握styled-components重塑React样式管理

想象一下,如果你的React组件不仅能自描述其逻辑,还能直接声明自己的样式,这种“所见即所得”的编程体验是不是让人心动不已?styled-components正是这样一把钥匙,它彻底颠覆了我们对React样式管理的传统认知,让样式与组件的结合变得如此自然与和谐。

目录

初识styled-components

styled-components基础使用

props传值

样式扩展(继承)

附加属性(道具)

伪元素(选择器)和嵌套

动画操作

设置公共样式

设置全局样式

styled-components高级操作

设置主题

as多态道具


初识styled-components

styled-components:是针对react中一个前端广泛使用的css-in-js样式库,它利用了ES里面最新的语法:模板字符串,通过模板字符串就把css和js打通,样式与组件直接结合,为react开发者提供了一种全新的、灵活的方式来处理样式问题,其官网文档:地址 和github地址:地址,也可以查阅具体内容,官方文档如下所示:

使用styled-components理由:要知道我们平常写的react语法无非就两种情况:jsx或tsx。jsx语法相当于对js原来的语法进行一个扩展,它允许你在js语法里面通过函数的返回值里面嵌入html模板,这样就相当于jsx语法把html和js两种进行打通了,可以让html模板化、组件化、可编程等,但在原生的react里面,jsx或tsx语法对样式的解决并不是很完美,如果在react里面进行书写样式的话,除内联样式外写css代码还是比较割裂的,需要单独再抽离一个css文件出来再进行一个引入的操作,等于react它就没有把css和js进行打通,而且后续写项目的话也是要来回在jsx和css文件中进行一个来回的切换,说实话还是比较繁琐的。如果在react基础上再加上styled-components就相当于js可以通吃html和css了。

vue能使用styled-components嘛?:vue已经将js和css放在一个文件中并且通过scoped进行了一个样式隔离,vue自身也已经具备样式管理且相当强大和易于使用,因此并不需要额外的css-in-js库来管理样式,如果是写vue的朋友转react开发,一时间有点难以接收说实话,毕竟react语法就摆在这没办法!正应正了那句老话:“由简入奢易,由奢入俭难”啊。

styled-components的优势有哪些?:在react项目中通过将样式与组件直接结合,为react开发者提供了一种全新的、灵活的方式来处理样式问题,以下是styled-components的一些主要优势:

1)样式局部化:生成的样式是局部化的,即样式仅应用于当前组件,避免了全局污染和样式冲突,可以确保不同组件之间的样式互不干扰。

2)动态样式和主题化:允许开发者根据组件的props或全局主题来动态调整样式,而无需手动管理多个类名。

3)易于删除和维护:样式与组件直接关联,所以很容易知道哪些样式是多余的,从而轻松删除,此外由于样式和组件的紧密耦合,维护也变得更为简单,无需在不同的文件中查找影响组件的样式。

4)避免类名冲突:每个样式组件生成唯一的类名(通常是通过哈希算法生成的),彻底解决了类名冲突的问题,即使在不同的子应用或组件库中定义了相同的类名,也不会相互干扰。

5)强大的嵌套和组合能力:支持类似于预处理器(如 SASS/SCSS)样式的嵌套和组合,可以使用css选择器、伪元素、媒体查询等特性来编写复杂的样式,而无需担心样式的作用域问题。

6)无缝集成和兼容性:完美支持所有css特性,包括媒体查询、伪选择器、动画等。

7)支持单元测试:通过使用像jest-styled-components这样的库,可以对样式组件进行单元测试,以确保样式的正确性和可维护性。

8)提升开发体验:对于习惯在vue框架中工作的开发者来说,styled-components减少了在 js和css文件之间切换的需要,从而提高了开发效率。

接下来我们通过代码进行一个演示,终端执行如下命令对styled-components进行一个安装:

npm install styled-components

我们在react组件中使用styled加上一个html标签即可实现html+css的样式,演示代码如下。

注意:作为样式组件,组件设置的名称必须符合规范,然后首字母必须大写!!!

import styled from "styled-components"const App = () => {return (<><MyButton>hello world</MyButton></>)
}
export default App
// 组件样式(定义在渲染方法外面)
const MyButton = styled.button`width: 100px;height: 30px;background-color: #008c8c;color: white;border-radius: 5px;border: none;cursor: pointer;&:hover {background-color: #005252;}
`

页面的呈现的效果如下所示,可以看到这是我们想要的结果:

注意:从上面代码可以看出,我是将样式组件(元素和样式规则的组合)定义在渲染方法App之外的,因为渲染组件每次数据发生变化重新渲染时都会重新创建,在渲染方法之外定义样式组件将避免阻碍缓存从而降低渲染速度!!!

styled-components基础使用

上面我们演示了styled-components的一个简单使用,可以看出我们没有定义html标签的button按钮而是被styled-components连同样式一起定义了。可见其删除了组件和样式之间的映射,这也就意味着我们实际上在创建一个普通的react组件且组件也可以附加自定义样式:

import styled from "styled-components"const App = () => {return (<><AppContainer><Title>hello styled-components</Title></AppContainer></>)
}
export default App
// 组件样式
const AppContainer = styled.div`width: 100%;height: 100vh;background-color: #ccc;
`
const Title = styled.h1`width: 100%;height: 100%;fs-size: 20px;display: flex;align-items: center;justify-content: center;color: #ff0000;
`

props传值

styled-components也支持通过props传值来实现动态改变样式,css样式中通过类型jq的方式来实现条件判断的方式,这里我们做一个简单的代码演示:

import styled from "styled-components"const App = () => {return (<><MyDiv>正常按钮</MyDiv><MyDiv primary>primary</MyDiv></>)
}
export default App
// 组件样式
const MyDiv = styled.div<{ primary?: boolean }>`width: 100px;height: 50px;background-color: ${props => props.primary ? "red" : "blue"};color: ${props => props.primary ? "white" : "black"};padding: 10px;font-size: 16px;border-radius: 10px;
`

当然props传值也可以写成箭头函数的方式进行,这里通过一段示例代码演示:

const LabelText = styled.span`${(props) => {switch (props.$mode) {case "dark":return css`background-color: black;color: white;${Input}:checked + && {color: blue;}`;default:return css`background-color: white;color: black;${Input}:checked + && {color: red;}`;}}}
`

样式扩展(继承)

如果经常使用一个组件,现在有一个需求,需要对经常使用的组件进行一个样式的改变,但是大部分的样式是一致的,正常我们还是需要再写一遍样式或通过逗号分隔两个类名的方式来实现,但是在styled-components可以使用styled()构造函数实现样式继承,示例代码如下:

import styled from "styled-components"const App = () => {return (<><MyDiv>基础样式</MyDiv><MyDivInherit>继承样式</MyDivInherit></>)
}
export default App
// 组件样式
const MyDiv = styled.div`width: 100px;height: 50px;background-color: red;color: white;padding: 10px;font-size: 16px;border-radius: 10px;
`
const MyDivInherit = styled(MyDiv)`background-color: blue; // 修改背景颜色
`

当然样式继承同样可以用于自定义组件,如下我们记住MyDiv的样式,然后通过js反转标签内容

import styled from "styled-components"const App = () => {return (<><MyDiv>基础样式</MyDiv><ReversedButton>基础样式</ReversedButton></>)
}
export default App
// 组件样式
const MyDiv = styled.div`width: 100px;color: #BF4F74;font-size: 1em;border: 2px solid #BF4F74;border-radius: 3px;text-align: center;padding: 10px;
`
const ReversedButton = props => <MyDiv {...props} children={props.children.split('').reverse()} />

附加属性(道具)

像一个标签可能有许多不同的属性,而不同的属性又呈现不同的效果,像input默认情况下就是text输入框,如果修改成checkbox属性则会变成勾选框,所以这里我们可以通过借助attrs构造函数实现添加不同的属性或者接收属性的数据,这里我们通过代码进行简单的演示:

import styled from "styled-components";const App = () => {return (<><Input placeholder="请输入" /><br /><Input placeholder="请输入" $size="2em" /></>)
}export default Appconst Input = styled.input.attrs<{ $size?: string }>(props => ({type: "text",$size: props.$size || "1em"
}))`color: #008c8c;font-size: 1em;border: 2px solid #BF4F74;border-radius: 3px;margin: ${props => props.$size};padding: ${props => props.$size};
`

 

这里我们也可以借助上文介绍的样式扩展(继承)搭配附加属性进行操作,这里我们可以制作一个登录框的账户密码进行一个简单的演示:

import styled from "styled-components";const App = () => {return (<><Input placeholder="请输入" $size="2em" /><br /><PasswordInput placeholder="请输入" $size="2em" /></>)
}export default App
// 样式组件
const Input = styled.input.attrs<{ $size?: string }>(props => ({type: "text",$size: props.$size || "1em"
}))`border: 2px solid #BF4F74;margin: ${props => props.$size};padding: ${props => props.$size};
`
// 继承输入框设置成密码框
const PasswordInput = styled(Input).attrs({type: "password"
})`border-color: #009688;
`

伪元素(选择器)和嵌套

因为styled-components支持嵌套样式类似scss语法,所以其也是支持一些高级的选择器模式的,这里对这些高级选择器模式做一个简单的概述:

&:单个&符号是指组件的所有实例,常用于广泛的内容覆盖,如下是常用的&的操作,当然这里也通过代码进行一个简单演示:

1)&: :&后面加一个冒号就是我们常用的对伪类选择器进行操作

2)& ~ &:用于选择紧跟在另一个具有相同选择器 “之后” 的同级元素

3)& + &:选择所有紧跟在当前组件之后的同级且相邻的相同组件,并为它们应用样式

4)&.something:类选择器,单独为一个或多个相同的类名设置单独样式

import styled from "styled-components"const App = () => {return (<><MyDiv className="change">基础样式</MyDiv><MyDiv>基础样式</MyDiv><MyDiv>基础样式</MyDiv><MyDiv>基础样式</MyDiv><MyDiv>基础样式</MyDiv></>)
}
export default App
// 组件样式
const MyDiv = styled.div`width: 100px;height: 40px;background-color: #BF4F74;font-size: 1em;text-align: center;line-height: 40px;color: #fff;&:hover { // 伪类选择器background-color: #008c8c;}& ~ & { // 同级选择器margin-bottom: 10px;}& + & { // 相邻选择器background-color: orange;}&.change { // 类选择器color: #008c8c;}
`

&&:双&符号引用组件的一个实例,如果您正在进行条件样式覆盖并且不希望样式应用于特定组件的所有实例,这很有用:

import React from "react";
import styled, { css } from "styled-components";interface LabelTextProps {$mode?: "dark" | "light";
}const App = () => {return (<><React.Fragment><Label><Input defaultChecked /><LabelText>Foo</LabelText></Label><Label><Input /><LabelText $mode="dark">Foo</LabelText></Label><Label><Input defaultChecked /><LabelText>Foo</LabelText></Label><Label><Input defaultChecked /><LabelText $mode="dark">Foo</LabelText></Label></React.Fragment></>)
}export default Appconst Input = styled.input.attrs({ type: "checkbox" })``;const Label = styled.label`align-items: center;display: flex;gap: 8px;margin-bottom: 8px;
`const LabelText = styled.span<LabelTextProps>`${(props) => {switch (props.$mode) {case "dark":return css`background-color: black;color: white;${Input}:checked + & {color: blue;}`;case "light":return css`background-color: white;color: black;${Input}:checked + & {color: red;}`;default:return css`background-color: white;color: black;${Input}:checked + & {color: red;}`;}}}
`;

当然双&符号有一种称为“优先级提升”的特殊行为;如果您正在处理可能存在冲突样式的混合样式组件和普通CSS环境,这可能很有用:

const Thing = styled.div`&& {color: blue;}`const GlobalStyle = createGlobalStyle`div${Thing} {color: red;}`render(<React.Fragment><GlobalStyle /><Thing>I'm blue, da ba dee da ba daa</Thing></React.Fragment>)

动画操作

因为带有@keyframes的css动画可能不仅仅只限于单个组件,但是你只想在单个组件中使用从而避免全局样式名称的冲突,styled-components也给我们提供了keyframes助手从而生成一个整个应用程序中使用的唯一实例,这里通过一段代码进行演示操作:

这里我们将控制动画的函数抽离出一个工具函数,然后统一暴露出去,然后在组件中进行引入使用我们设置的动画函数:

设置公共样式

学习了styled-components之后肯定要掌握如何设置公共样式呢?这里我们可以使用styled-components提供的css函数来生成一个公共样式,这里我单独将公共样式抽离出来,后期如果要使用公共样式直接引入即可:

设置全局样式

学习了styled-components之后肯定要掌握如何设置全局样式呢? 这里styled-components也是提供了全局组件的API函数,注意这个函数要求styled-components版本必须在v4以上,如果是低版本的话就不能使用了。

要知道浏览器是存在默认样式的,这里我们可以通过全局样式对浏览器的默认样式进行一个清除:

import { createGlobalStyle } from "styled-components";// 设置全局样式组件
const GlobalStyle = createGlobalStyle`body {margin: 0;padding: 0;}
`

可以看到我们的浏览器存在的默认内外边距被清除掉了:

styled-components高级操作

对于styled-components还有许多高阶的操作的内容,这里就挑几个实用的方法进行一个简单的讲解吧,如果想了解具体的内容,可以参考官方文档的内容即可,如下:

设置主题

styled-components也是提供了设置主题的操作,这里我们可以通过导出的ThemeProvider包装器组件实现主题内容的支持,并且主题还可以嵌套多层,这里通过一段代码进行示例演示:

import styled, { ThemeProvider } from "styled-components";const App = () => {return (<><ThemeProvider theme={theme}><Button>默认主题</Button><ThemeProvider theme={changeTheme}><Button>主题改变</Button></ThemeProvider></ThemeProvider></>)
}export default App
// 样式组件
const theme = {defaultColor: "#008c8c",borderColor: "#f0f00f",
}
const changeTheme = {defaultColor: "#ff000f",borderColor: "#00ff00",
}const Button = styled.button`color: ${(props) => props.theme.defaultColor};border: 1px solid ${(props) => props.theme.borderColor};font-size: 1.5rem;padding: 1rem;border-radius: 0.5rem;
`

如果想在没有样式组件的情况下获取主题,可以采用下面几种方式:

withTheme:在样式组件之外(例如在大型组件内部)使用当前主题

// App.tsx组件
import InnerComponent from "./components/InnerComponent"
const theme = {color: "red",background: "#008c8c",border: "1px solid orange",
}const App = () => {return (<><InnerComponent theme={theme}></InnerComponent></>)
}export default App// 注入主题组件
import styled, { withTheme } from 'styled-components'interface ThemeProps {color: string;background: string;border?: string;
};function InnerComponent({ theme }: { theme: ThemeProps }) {console.log('Current theme: ', theme);return (<StyledContent theme={theme}>Use withTheme API</StyledContent>)
}export default withTheme(InnerComponent);const StyledContent = styled.div<{ theme: ThemeProps }>`color: ${props => props.theme.color};background: ${props => props.theme.background};border: ${props => props.theme.border || 'none'};
`;

useContext与ThemeContext:访问样式组件之外的当前主题

import { useContext } from 'react';
import { ThemeContext } from 'styled-components';function InnerComponent() {const themeContext = useContext(ThemeContext);console.log('themeContext: ', themeContext);
}

useTheme:访问样式组件之外的当前主题

import { useTheme } from 'styled-components';function InnerReactComponent() {const theme = useTheme()console.log('theme: ', theme); // { color: '#333', background: '#fff', border: '1px solid #eee' }
}

as多态道具

如果想保留应用于组件的所有样式,但仅仅只是切换最终呈现的内容,无论是不同的超文本标记语言还是不同的自定义组件,可以使用 “as” 在运行时执行此操作:

import styled from "styled-components";
// 自定义组件
interface MyDivProps {onClick?: () => void;as?: React.ElementType;
}const App = () => {return (<><MyDiv as="button" onClick={() => alert('hello world')}>按钮</MyDiv></>);
}export default App;
// 样式组件
const MyDiv = styled.div<MyDivProps>`color: red;
`;

当然还有其他的用法,这里博主就不再赘述了,大家自行查阅官网吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/391518.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CH571F蓝牙orUSB摇杆鼠标

演示视频&#xff1a; 短视频刷个爽 程序基本上是基于官方的例程上改的&#xff0c;用到的例程有&#xff1a;蓝牙的HID_Mouse,USB的CompoundDev&#xff0c;还有ADC&#xff0c;按键中断。 主要原理 就是ADC采集采集摇杆电压&#xff0c;通过蓝牙HID或者USB的HID发送给电脑或…

Java中操作文件

认识⽂件 我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进⾏数据保存时&#xff0c; 往往不是保存成⼀个整体&#xff0c;⽽是独⽴成⼀个个的单位进⾏保存&#xff0c;这个独⽴的单位就被抽象成⽂件的概 念&#xff0c;就类似办公桌…

Parallels Desktop19让你的Mac无缝运行Windows!

大家好&#xff0c;我是你们的科技小伙伴&#xff0c;今天我要给大家安利一款神奇的软件——Parallels Desktop 19虚拟机。这款产品真的是让我眼前一亮&#xff0c;用起来简直不能更爽&#xff01; 让我们来聊聊为什么我们需要一个虚拟机。 想象一下&#xff0c;你是一个Mac用…

多租户系统数据隔离方案

目录 前言 数据行 数据表 基于业务场景 基于数据量 数据库 数据源表 动态数据源 前言 多租户系统是一种将多个客户的数据和应用程序分开的系统&#xff0c;每个客户被视为一个独立的租户&#xff0c;互不干扰。实现多租户系统的关键之一是确保数据的隔离。 数据隔离的…

[云原生]三、Kubernetes(1.18)

主要内容: 1、kubernetes 简介 2、kubernetes 集群搭建  方式搭建  二进制方式搭建 3、 kubeadm kubernetes 核心技术  YAML 文件详解  kubectl 命令工具  Pod  Label  Controller 控制器 …

职业教育大数据实验实训室建设应用案例

大数据作为一种重要的信息技术&#xff0c;对各行各业产生了深远的影响。职业教育作为培养应用型人才的摇篮&#xff0c;建设大数据实验实训室&#xff0c;对于提高学生的数据分析能力和解决实际问题的能力具有重要意义。唯众作为一家专注于教育技术领域的企业&#xff0c;凭借…

从零开始:MySQL安装与配置完全指南

前言 哇&#xff0c;终于进入到令人激动的MySQL环节了 它可以说是你编程生涯中的最佳朋友&#xff0c;因为它总是能存储你的数据&#xff0c;从不说&#xff1a;“我忘记了你的信 息”。而且&#xff0c;它是免费的&#xff0c;不像一些昂贵的数据库&#xff0c;它从不让你的…

量产部落SM2258XT开卡软件,SM2258XT主控128G SSD固态卡死修复

故障现象&#xff1a;连接此固态硬盘后电脑就会卡死&#xff0c;拔掉重新连接概率性显示盘符&#xff0c;显示了之后也不能正常操作&#xff0c;一点击打开&#xff0c;电脑就立马卡死。 解决过程&#xff1a;下载了很多款量产工具&#xff0c;都不能开卡成功&#xff0c;点击…

Elasticsearch 未授权访问漏洞

Elasticsearch 未授权访问漏洞 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是当前流行的企业级搜索…

iAppv3无白银会员使用SDK

前言 一个实用小技巧分享给大家。 工具 iapp&#xff1a;百度或点我获取 Mt管理器&#xff1a;百度或点我获取 教程 1.移出“项目路径/apk/lib/”内的全部文件 2.在iapp内测试打包&#xff0c;打包完成后直接返回&#xff0c;不要安装 3.在mt管理器里面点击“项目路径/b…

【课程总结】Day18:Seq2Seq的深入了解

前言 在上一章【课程总结】Day17&#xff08;下&#xff09;&#xff1a;初始Seq2Seq模型中&#xff0c;我们初步了解了Seq2Seq模型的基本情况及代码运行效果&#xff0c;本章内容将深入了解Seq2Seq模型的代码&#xff0c;梳理代码的框架图、各部分组成部分以及运行流程。 框…

【大模型系列】LanguageBind(ICLR2024.01)

Paper&#xff1a;https://arxiv.org/abs/2310.01852Github&#xff1a;https://github.com/PKU-YuanGroup/LanguageBindHuggingface&#xff1a;https://huggingface.co/spaces/LanguageBind/LanguageBindAuthor&#xff1a;Bin Zhu et al. 北大袁粒团队 文章目录 1 LanguageB…

入门mem0.NET

入门mem0.NET 安装包 如果你的项目使用了EntityFrameworkCore,那么你可以跟随这个教程走 <ItemGroup><PackageReference Include"mem0.NET" Version"0.1.7" /><PackageReference Include"mem0.NET.Qdrant" Version"0.1.7…

软件测试需要具备的基础知识【功能测试】---前端知识(一)

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 为了更好的学习软件测试的相关技能&#xff0c;需要具备一定的基础知识。需要学习的基础知识包括&#xff1a; 1、计算机基础 2、前端知识 3、后端知识 4、软件测试理论 后期分四篇文章进行编写&#xff0c;这是第二篇 …

【精选】通信与感知(ISAC)必读好文

微信公众号&#xff1a;EW Frontier 个人博客&#xff1a;106.54.201.174 QQ交流群&#xff1a;949444104 简介 通信与感知&#xff08;ISAC&#xff09;也被称为联合雷达通信 (JRC) / 联合通信和雷达传感 (JCAS) / 双功能雷达通信 (DFRC) 定义&#xff1a;将传感和通信系统集…

记录一次学习过程(msf、cs的使用、横向渗透等等)

目录 用python搭建一个简单的web服务器 代码解释 MSF msfvenom 功能 用途 查看payloads列表 msfconsole 功能 用途 msfvenom和msfconsole配合使用 来个例子 msf会话中用到的一些命令 在windows中net user用法 列出所有用户账户 显示单个用户账户信息 创建用户账…

学python的第一天:PyCharm创建项目

创建项目 打开工具 PyCharm 点击“新建项目” 点击“创建” 环境 系统会创建虚拟环境&#xff0c;稍等 初始设置 创建完成后会进入main.py文件 性能 可以看到 右下角提示我们增强性能&#xff0c;点“自动” 会获取到管理员权限 完成后会提示完成

【数据结构】栈和队列(c语言实现)(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 一、栈 1.栈的概念与结构 2.栈的实现 2.1 栈的结构定义 2.2 方法的声明 2.3 方法的实现 2.3.1 初始化 2.3.2 销毁 2.3.3 判空 2.3.4 压…

常见CMS漏洞(WordPress、DeDeCMS、ASPCMS、PHPMyadmin、Pageadmin)

目录 一&#xff1a;WordPress 步骤一:进入Vulhub靶场并执行以下命令开启靶场;在浏览器中访问并安装好子... 步骤二:思路是修改其WP的模板写入一句话木马后门并访问其文件即可GetShel;登陆WP后点击【外观】--》【编辑】 --》 404.php 步骤三:访问以下连接即可获取WebShel...…

用VBA在Word中随机打乱单词表,进行分列

一、效果展示&#xff08;以下是三次随机打乱的结果&#xff09; 二、代码 Sub 随机分单词到后面的单元格()Dim C1 As CellDim str, str1, aDim shuffledArray() As VariantSet C1 Selection.Range.Tables(1).Cell(1, 1)str C1.Range.textstr mid(str, 3, Len(str) - 4)str…