【实战】 五、CSS 其实很简单

您所在的位置:网站首页 jq更改css样式 【实战】 五、CSS 其实很简单

【实战】 五、CSS 其实很简单

2023-07-04 03:58| 来源: 网络整理| 查看: 265

文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求1~56~10 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式1.安装与使用 antd 组件库安装 antd安装 cracoantd 组件替换原生组件 2.CSS-in-JS(1)传统CSS的缺陷①缺乏模块组织②缺乏作用域③隐式依赖,让样式难以追踪④没有变量⑤CSS选择器与HTML元素耦合 (2)Emotion 介绍 3.emotion & 登录注册页美化全局样式安装 emotion原生标签使用 emotionantd 标签使用 emotion进一步美化

学习内容来源:React + React Hook + TS 最佳实践-慕课网

相对原教程,我在学习开始时(2023.03)采用的是当前最新版本:

项版本react & react-dom^18.2.0react-router & react-router-dom^6.11.2antd^4.24.8@commitlint/cli & @commitlint/config-conventional^17.4.4eslint-config-prettier^8.6.0husky^8.0.3lint-staged^13.1.2prettier2.8.4json-server0.17.2craco-less^2.0.0@craco/craco^7.1.0qs^6.11.0dayjs^1.11.7react-helmet^6.1.0@types/react-helmet^6.1.6react-query^6.1.0@welldone-software/why-did-you-render^7.0.1@emotion/react & @emotion/styled^11.10.6

具体配置、操作和内容会有差异,“坑”也会有所不同。。。

一、项目起航:项目初始化与配置 【实战】 一、项目起航:项目初始化与配置 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(一) 二、React 与 Hook 应用:实现项目列表 【实战】 二、React 与 Hook 应用:实现项目列表 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二) 三、TS 应用:JS神助攻 - 强类型 【实战】三、 TS 应用:JS神助攻 - 强类型 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(三) 四、JWT、用户认证与异步请求 1~5 【实战】四、 JWT、用户认证与异步请求(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(四) 6~10 【实战】四、 JWT、用户认证与异步请求(下) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(五) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式

antd + emotion

1.安装与使用 antd 组件库

官网:Ant Design - 一套企业级 UI 设计语言和 React 组件库

安装 antd # npm i antd # yarn add antd npm i antd --force jira-dev-tool 依赖树中包含 antd,可尝试不安装直接使用鉴于 jira-dev-tool 长时间没有更新,依赖树有较多问题,建议清理 node_modules,执行 npm i --force 重新安装依赖 在 src\index.tsx 中引入 antd.less(一定要在 jira-dev-tool 之后引入,以便后续修改主题样式能够覆盖到 jira-dev-tool) import { loadDevTools } from "jira-dev-tool"; import 'antd/dist/antd.less' 安装 craco

为对 create-react-app 进行自定义配置,需要安装 craco 和它的子依赖 craco-less:

# npm i @craco/craco # yarn add @craco/craco npm i @craco/craco --force npm i -D craco-less --force

https://4x.ant.design/docs/react/use-with-create-react-app-cn#高级配置

按文档中,替换 package.json 中脚本指令 "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", + "start": "craco start", + "build": "craco build", + "test": "craco test", }

项目根目录下新建文件 craco.config.js,复制文档中对应部分代码,并配置需要修改的主题变量:

const CracoLessPlugin = require('craco-less'); module.exports = { plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: { '@primary-color': 'rgb(0, 82, 204)', '@font-size-base': '16px' }, javascriptEnabled: true, }, }, }, }, ], }; npm start 重新启动项目 antd 组件替换原生组件 先修改登录页面 src\unauthenticated-app\login.tsx: import { useAuth } from "context/auth-context"; import { Form, Button, Input } from "antd" export const Login = () => { const { login, user } = useAuth(); const handleSubmit = (values: { username: string, password: string }) => { login(values); }; return ( [{ required: true, message: '请输入用户名' }]}> required: true, message: '请输入密码' }]}> 登录 ); };

查看页面效果,并尝试 登录 功能

修改注册页面 src\unauthenticated-app\register.tsx:

import { useAuth } from "context/auth-context"; import { Form, Button, Input } from "antd" export const Register = () => { const { register, user } = useAuth(); const handleSubmit = (values: { username: string, password: string }) => { register(values); }; return ( [{ required: true, message: '请输入用户名' }]}> required: true, message: '请输入密码' }]}> 注册 ); };

从登录页切换到注册页,查看页面效果,并尝试 注册 功能

接下来修改 src\unauthenticated-app\index.tsx:

import { useState } from "react"; import { Login } from "./login"; import { Register } from "./register"; import { Card, Button } from 'antd'; export const UnauthenticatedApp = () => { const [isRegister, setIsRegister] = useState(false); return ( display: 'flex', justifyContent: 'center' }}> {isRegister ? : } isRegister ? "登录" : "注册"} ); };

现在较之前页面好看多了

修改 src\screens\ProjectList\components\List.tsx(部分未改动省略): import { Table } from "antd"; import { User } from "./SearchPanel"; ... export const List = ({ users, list }: ListProps) => { return [{ title: '名称', dataIndex: 'name', sorter: (a, b) => a.name.localeCompare(b.name) }, { title: '负责人', render: (text, project) => {users.find((user) => user.id === project.personId)?.name || "未知"} }]} dataSource={list}> }; localeCompare 可排序中文字符

在引入 antd 的 Table 后,先不给 columns 属性赋值,而是先赋值 dataSource,然后将鼠标放于 columns 上,这时便可见: (property) TableProps.columns?: ColumnsType | undefined TS 的类型推断起作用了:

通过 list 的值类型为 Project[] ,推断出 dataSource?: RcTableProps['data'] 中 data 类型为 Project[]推断出 dataSource?: RcTableProps['data'] 中 RecordType 类型为 Project[]推断出 columns 类型为 (property) TableProps.columns?: ColumnsType | undefined 修改 src\screens\ProjectList\components\SearchPanel.tsx import { Form, Input, Select } from "antd"; ... export const SearchPanel = ({ users, param, setParam }: SearchPanelProps) => { return ( (evt) => setParam({ ...param, name: evt.target.value, }) } /> value => setParam({ ...param, personId: value, }) } > 负责人 {users.map((user) => ( user.id}> {user.name} ))} ); }; 尝试功能,正常! 2.CSS-in-JS

以下部分是课件原文:

CSS-in-JS 不是指某一个具体的库,是指组织CSS代码的一种方式,代表库有 styled-component 和 emotion

(1)传统CSS的缺陷 ①缺乏模块组织

传统的JS和CSS都没有模块的概念,后来在JS界陆续有了 CommonJS 和 ECMAScript Module,CSS-in-JS可以用模块化的方式组织CSS,依托于JS的模块化方案,比如:

// button1.ts import styled from '@emotion/styled' export const Button = styled.button` color: turquoise; ` // button2.ts import styled from '@emotion/styled' export const Button = styled.button` font-size: 16px; ` ②缺乏作用域

传统的CSS只有一个全局作用域,比如说一个class可以匹配全局的任意元素。随着项目成长,CSS会变得越来越难以组织,最终导致失控。CSS-in-JS可以通过生成独特的选择符,来实现作用域的效果

const css = styleBlock => { const className = someHash(styleBlock); const styleEl = document.createElement('style'); styleEl.textContent = ` .${className} { ${styleBlock} } `; document.head.appendChild(styleEl); return className; }; const className = css(` color: red; padding: 20px; `); // 'c23j4' ③隐式依赖,让样式难以追踪

比如这个CSS样式:

.target .name h1 { color: red } body #container h1 { color: green } doctype html> 我是啥颜色?

那么这个h1元素最终显式为什么颜色?加入你想要追踪这个影响这个h1的样式,怎么追踪? 而CSS-in-JS的方案就简单直接、易于追踪

export const Title = styled.h1` color: green; ` 我是啥颜色? ④没有变量

传统的CSS规则里没有变量,但是在 CSS-in-JS 中可以方便地控制变量

const Container = styled.div(props => ({ display: 'flex', flexDirection: props.column && 'column' })) ⑤CSS选择器与HTML元素耦合 .target .name h1 { color: red } body #container h1 { color: green } doctype html> 我是啥颜色?

如果你想把 h1 改成h2,必须要同时改动 CSS 和 HTML。而在CSS-in-JS中,HTML和CSS是结合在一起的,易于修改

(2)Emotion 介绍

Emotion 是目前最受欢迎的 CSS-in-JS 库之一,它还对 React 作了很好的适应,可以方便地创建 styled component,也支持写行内样式:

/** @jsx jsx */ import { jsx } from '@emotion/react' render( /* rem em */ /* em 相对于父元素的 font-size */ /* rem 相对于根元素的 font-size,r root */ /* 浏览器默认 font-size 16px */ /* 16px * 62.5% = 10px */ /* 1rem === 10px */ font-size: 62.5%; } html body #root .App { min-height: 100vh; }

删掉文件 src\index.css 并去掉在 src\index.tsx 中的引用,后续全局样式都在 src\App.css 中添加

安装 emotion npm i @emotion/react @emotion/styled --force 原生标签使用 emotion

编辑 src\unauthenticated-app\index.tsx(部分原有内容省略)

... import { Card, Button } from "antd"; import styled from "@emotion/styled"; export const UnauthenticatedApp = () => { ... return ( ... ); }; const Container = styled.div` display: flex; flex-direction: column; align-items: center; min-height: 100vh; justify-content: center; `

相当于将 div 添加以 css-[hashcode] 命名的 class 并自定义样式后 封装为 StyledComponent 类型的 自定义组件 Container (仅添加样式)

const Container: StyledComponent}> antd 标签使用 emotion

继续编辑 src\unauthenticated-app\index.tsx(部分原有内容省略)

... import { Card, Button } from "antd"; import styled from "@emotion/styled"; export const UnauthenticatedApp = () => { ... return ( ... ); }; const ShadowCard = styled(Card)` width: 40rem; min-height: 56rem; padding: 3.2rem 4rem; border-radius: 0.3rem; box-sizing: border-box; box-shadow: rgba(0,0,0,0.1) 0 0 10px; text-align: center; ` ...

相当于将 Card 添加以 css-[hashcode] 命名的 class 并自定义样式后 封装为 StyledComponent 类型的 自定义组件 ShadowCard (不仅添加样式,还将 CardProps 原有属性原封不动还原)

const ShadowCard: StyledComponent}, {}> 进一步美化

新建 src\assets,将预置 svg 文件放入(left.svg、logo.svg、right.svg)

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

继续编辑 src\unauthenticated-app\index.tsx(部分原有内容省略):切换文案修改并使用 link 类型 button;添加 logo、标题和背景图

... import { Card, Button, Divider } from "antd"; import styled from "@emotion/styled"; import left from 'assets/left.svg' import logo from 'assets/logo.svg' import right from 'assets/right.svg' export const UnauthenticatedApp = () => { ... return ( {isRegister ? '请注册' : '请登录'} {isRegister ? : } isRegister ? "已经有账号了?直接登录" : "没有账号?注册新账号"} ); }; const Title = styled.h2` margin-bottom: 2.4rem; color: rgb(94, 108, 132); ` const Background = styled.div` position: absolute; width: 100%; height: 100%; background-repeat: no-repeat; background-attachment: fixed; // 背景图片是否会随着页面滑动 background-position: left bottom, right bottom; background-size: calc(((100vw - 40rem) / 2) - 3.2rem), calc(((100vw - 40rem) / 2) - 3.2rem), cover; background-image: url(${left}), url(${right}); ` const Header = styled.header` background: url(${logo}) no-repeat center; padding: 5rem 0; background-size: 8rem; width: 100%; ` ... background-image 使用多个图时,默认会有一个重叠关系(后来者居下),可以通过 巧妙的 size 计算和 position 使其达到想要的效果

美化登录页 src\unauthenticated-app\login.tsx(部分原有内容省略):按钮宽度撑开,并导出供注册页使用

... import { Form, Button, Input } from "antd"; import styled from "@emotion/styled"; export const Login = () => { ... return ( Form, Input } from "antd"; import { LongButton } from "./login"; export const Register = () => { ... return (


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3