【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六)

这篇具有很好参考价值的文章主要介绍了【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


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


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

版本
react & react-dom ^18.2.0
react-router & react-router-dom ^6.11.2
antd ^4.24.8
@commitlint/cli & @commitlint/config-conventional ^17.4.4
eslint-config-prettier ^8.6.0
husky ^8.0.3
lint-staged ^13.1.2
prettier 2.8.4
json-server 0.17.2
craco-less ^2.0.0
@craco/craco ^7.1.0
qs ^6.11.0
dayjs ^1.11.7
react-helmet ^6.1.0
@types/react-helmet ^6.1.6
react-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 (
    <Form onFinish={handleSubmit}>
      <Form.Item name='username' rules={[{ required: true, message: '请输入用户名' }]}>
        <Input placeholder="用户名" type="text" id="username" />
      </Form.Item>
      <Form.Item name='password' rules={[{ required: true, message: '请输入密码' }]}>
        <Input placeholder="密码" type="password" id="password" />
      </Form.Item>
      <Form.Item>
        <Button htmlType="submit" type="primary">登录</Button>
      </Form.Item>
    </Form>
  );
};

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

  • 修改注册页面 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 (
    <Form onFinish={handleSubmit}>
      <Form.Item name='username' rules={[{ required: true, message: '请输入用户名' }]}>
        <Input placeholder="用户名" type="text" id="username" />
      </Form.Item>
      <Form.Item name='password' rules={[{ required: true, message: '请输入密码' }]}>
        <Input placeholder="密码" type="password" id="password" />
      </Form.Item>
      <Form.Item>
        <Button htmlType="submit" type="primary">注册</Button>
      </Form.Item>
    </Form>
  );
};
  • 从登录页切换到注册页,查看页面效果,并尝试 注册 功能

  • 接下来修改 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 (<Card style={{ display: 'flex', justifyContent: 'center' }}>
      {isRegister ? <Register /> : <Login />}
      <Button type='primary' onClick={() => setIsRegister(!isRegister)}>
        切换到{isRegister ? "登录" : "注册"}
      </Button>
    </Card>
  );
};

现在较之前页面好看多了

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

  • localeCompare 可排序中文字符

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

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

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>
<html lang="en">
<body>
  <div id='container'>
   <div class='target'>
     <div class='name'>
       <h1>我是啥颜色?</h1>
     </div>
   </div>
  </div>
</body>
</html>

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

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

传统的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>
<html lang="en">
<body>
  <div id='container'>
   <div class='target'>
     <div class='name'>
       <h1>我是啥颜色?</h1>
     </div>
   </div>
  </div>
</body>
</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(
  <div
    css={{
      backgroundColor: 'hotpink',
      '&:hover': {
        color: 'lightgreen'
      }
    }}
  >
    This has a hotpink background.
  </div>
)

这种写法比起React自带的style的写法功能更强大,比如可以处理级联、伪类等style处理的不了的情况

3.emotion & 登录注册页美化

全局样式
  • 编辑 src\App.css 清除原有样式,填入如下内容:
html {
  /* 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 (
    <Container>
      <Card>
        ...
      </Card>
    </Container>
  );
};

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<{
   theme?: Theme | undefined;
   as?: React.ElementType<any> | undefined;
}, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>
antd 标签使用 emotion

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

...
import { Card, Button } from "antd";
import styled from "@emotion/styled";

export const UnauthenticatedApp = () => {
  ...
  return (
    <Container>
      <ShadowCard>
        ...
      </ShadowCard>
    </Container>
  );
};

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<CardProps & React.RefAttributes<HTMLDivElement> & {
    theme?: Theme | undefined;
}, {}, {}>
进一步美化

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

【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六),javascript,css,react.js
【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六),javascript,css,react.js
【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六),javascript,css,react.js

继续编辑 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 (
    <Container>
      <Header/>
      <Background/>
      <ShadowCard>
        <Title>
          {isRegister ? '请注册' : '请登录'}
        </Title>
        {isRegister ? <Register /> : <Login />}
        <Divider/>
        <Button type="link" onClick={() => setIsRegister(!isRegister)}>
          切换到{isRegister ? "已经有账号了?直接登录" : "没有账号?注册新账号"}
        </Button> 
      </ShadowCard>
    </Container>
  );
};

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 onFinish={handleSubmit}>
      ...
      <Form.Item>
        <LongButton htmlType="submit" type="primary">
          登录
        </LongButton>
      </Form.Item>
    </Form>
  );
};

export const LongButton = styled(Button)`
  width: 100%
`

美化注册页 src\unauthenticated-app\register.tsx(部分原有内容省略):引入登录页导出的“长按钮”

...
import { Form, Input } from "antd";
import { LongButton } from "./login";

export const Register = () => {
  ...
  return (
    <Form onFinish={handleSubmit}>
      ...
      <Form.Item>
        <LongButton htmlType="submit" type="primary">
          注册
        </LongButton>
      </Form.Item>
    </Form>
  );
};

tips:在 emotion 编写css, 若是发现代码没有高亮,则需要安装 vscode/webstrom 插件:

  • vscode styled-components插件
  • Ctrl + P, 输入 ext install vscode-styled-components 第一个即是
  • 或者手动点过去搜索
  • https://github.com/styled-components/styled-components

本次美化成果:
【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六),javascript,css,react.js


部分引用笔记还在草稿阶段,敬请期待。。。文章来源地址https://www.toymoban.com/news/detail-521292.html

到了这里,关于【实战】 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(六)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 在JavaScript中添加css样式 js追加类

    一、原生js中添加类的方法 二、jquery中添加类的方法 三、检查是否含有某个类的方法 四、在JavaScript中添加CSS样式: 五、使用HTML DOM的setAttribute()方法更改CSS属性: 六、使用JavaScript可以通过动态创建样式表 style标签 来添加CSS样式。 例如,以下代码创建一个新的style标签,并

    2024年02月03日
    浏览(54)
  • CSS设置鼠标样式和添加视频样式

    CSS用户界面样式 轮廓线outline 使图片和文字对齐 vertical-align: baseline | top | middle | bottom baseline 默认元素设置在父元素的基线上 top把元素的顶端与行中最高元素的顶端对齐 middle把元素放置父元素的中部 bottom把元素的顶端与行中最低的元素的顶端对齐 这个用法限于行内和行内块

    2024年02月07日
    浏览(39)
  • 第一个react应用程序并添加样式

    将目录下的文件、src文件夹、public文件夹清空,项目根目录下新建一个文件index.js 在文件中写入以下代码 react开发需要引入多个依赖文件:React和ReactDOM. ReactDOM.render是 React 的最基本方法用于将模板转为 HTML 语言,并插入指定的 DOM 节点。 该方法接收两个参数: 创建的模板,

    2024年02月11日
    浏览(49)
  • 步入React前厅 - Css In React

    目录 扩展学习资料 行内样式 引入样式表 CSS Module @/src/components/common.module.css @/src/components/listitem.module.css css管理进阶 Css管理工具 练习 资料名称 链接 css module CSS Modules 用法教程 - 阮一峰的网络日志       在React中使用css预编译 https://juejin.im/post/5c3d67066fb9a049f06a8323      sty

    2024年02月13日
    浏览(72)
  • CSS给元素添加边框(样式、颜色、宽度)

    CSS边框属性允许你指定一个元素边框的样式和颜色, 和边框宽度。 可以使用 border 属性将边框样式,颜色,和宽度 一起设置。 如果不设置其中的某个值,也不会出问题,比如 border: solid #ff0000; 也是允许的。 边框样式属性指定要显示什么样的边界。除了在 border 属性里面设置边框

    2024年01月21日
    浏览(44)
  • 在油猴脚本中添加css样式的方法

    由于项目要求,需要在系统页面注入dom元素,且对这些注入的元素在UI界面层有美观度要求,就避免不了要对其CSS样式优化。 通常在油猴脚本中添加CSS样式的方法如下: 一、引入外部css文件 二、使用油猴自带样式添加请求 三、自定义样式函数 四、js添加样式 或 以上是在油

    2024年01月23日
    浏览(40)
  • 通过使用html的css样式来达到给背景色添加渐变色的效果

    这里我直接添加了两个div,并且给两个div添加了基本的css样式,有问题请私信          在演示开始之前我们先来认识一下实现渐变效果的一个属性  background: linear-gradient 这个是我们设置背景渐变色的关键属性,然后我们开始演示(这里我们通过修改第二个div)          

    2024年02月08日
    浏览(50)
  • 微信小程序通过js动态修改css样式的方法,以及css变量

    不知道各位小帅有没有遇到这种问题,在微信小程序开发的时候,我们想要将某个文字大小变大,那么本篇文章就是解决这个问题。

    2024年02月06日
    浏览(53)
  • 【React】如何简单快速地修改antd组件UI内部样式如字体颜色

    最近刚开始学习react 在写一个登录的页面 发现组件的颜色不太合适,默认是黑色字体 那我想修改成白色字体以适应我的页面 运用多种css文件打包策略太过复杂 对我这种小白不友好 两行代码搞定 实现需求 通过:global加上!important 在Umi项目中,在global.less文件夹下面,通过roo

    2024年02月13日
    浏览(45)
  • Vue3通过JS修改Css样式(附节点获取相关知识)

    方法一:通过获取节点style(获取标签节点) 方法二:通过动态设置class 方法三:直接动态设置style  附节点获取相关知识

    2024年02月16日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包