React styles 方案

32 阅读3分钟

demo-style:react styles 和 css in js 样式方案

1. 代码仓库

github.com/chuxin-cs/r…

2. 主线任务

2.1. react 官方基础用法

css方案

// App.tsx
import './App.css';
export default function App() {
  return <div className={'css_style'}></div>;
}

// App.css
.css_style{ display:flex }

2.2. Module.css

create-react-appVite 中默认支持:

1、module 的方式 css 文件必须要加 .module

// App.tsx
import globalStyle from './global.module.css';

export default function App() {
  return <div className={globalStyle.flex}>1</div>
}

// global.module.css
.flex{ display:flex }

2、module 方案的css name 会自动生成 hash 值

2.3. styled-components

styled-components 是一个流行的 CSS-in-JS ****库,用于在 React(或其他框架)中以组件化的方式编写和管理 CSS 样式。它通过将样式直接嵌入 JavaScript/TypeScript 代码,解决了传统 CSS 的全局污染、命名冲突、动态样式难维护等问题

1、依赖下载:

pnpm add styled-components -S

2、ts 项目类型声明:

pnpm add @types/styled-components -D

3、App.tsx:

import styled from 'styled-components';
interface StyleButtonProps {
  bg?: boolean;
}
//                  styled.* 范围(html元素,或者组件)
const StyleButton = styled.button<StyleButtonProps>`
  color: #fff;
  border: 0;
  background: ${(props) => (props.bg ? '#000' : '#666')};
`;

export default function App() {
  // 这里直接绑定 bg 会被渲染到 button dom 上 但是button没有这个属性 react会抛出警告 Warning: Received `true` for a non-boolean attribute `bg`
  return <StyleButton bg={true}>3</StyleButton>;
}

4、自动生成hash值:

2.3.1. 解决渲染不是元素属性的警告

button 按钮没有 bg 这个属性,会抛警告

1、第一种解决办法 属性前面加 $ 告知 styled-components 这是仅用于样式的属性,不传递到 DOM

import styled from "styled-components";
interface StyleButtonProps {
    $bg?: boolean;
}
//                  styled.* 范围(html元素,或者组件)   
const StyleButton = styled.button<StyleButtonProps>`
    color: #fff;
    border: 0;
    background: ${props => props.$bg ? "#000" : "#666"};
`
export default function App() {
    return (<StyleButton $bg={true}>111</StyleButton>)
}

2、过滤属性(使用 shouldForwardProp

import styled from "styled-components";

interface StyleButtonProps {
  bg?: boolean;
}

const StyleButton = styled.button.withConfig({
  shouldForwardProp: (prop) => !['bg'].includes(prop) // 过滤 bg 属性
})<StyleButtonProps>`
    color: #fff;
    border: 0;
    background: ${(props) => (props.bg ? "#000" : "#666")};
`

export default function Home() {
  return (<StyleButton bg>111</StyleButton>)
}

2.4. @vanilla-extract/css

@vanilla-extract/css 是一个用于在 JavaScript 或 TypeScript 项目中编写 CSS 的工具包,它采用了 CSS-in-JS 的思想,但与传统的 CSS-in-JS 库(如 styled-components、emotion 等)有所不同。@vanilla-extract 是基于构建时的 CSS 解决方案,它在构建阶段将样式代码编译成普通的 CSS 文件,避免了运行时的性能开销,同时还保留了 JavaScript 的灵活性和类型安全

@vanilla-extract/css 的主题方案在:www.yuque.com/chuxin-cs/c…

1、依赖下载

pnpm add @vanilla-extract/css -S
pnpm add @vanilla-extract/vite-plugin -D

2、Vite 中使用:

import {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'
import {vanillaExtractPlugin} from '@vanilla-extract/vite-plugin'

export default defineConfig({
    plugins: [
      react(),
      vanillaExtractPlugin()
    ],
})

3、基础用法:style.css.ts 注意如果是ts项目需要加 .ts 后缀,js项目就加.js

// style.css.ts
import { style } from '@vanilla-extract/css';

export const containerStyle = style({
  padding: 20,
  backgroundColor: '#fff',
  vars: {
    '--primary-color': '#007bff',
  },
});

export const buttonStyle = style([
  containerStyle, // 继承样式
  {
    color: 'white',
    backgroundColor: 'var(--primary-color)',
    ':hover': {
      opacity: 0.8,
    },
  },
]);

4、App.tsx 中:

import { containerStyle, buttonStyle } from './styles.css.ts';

export default function App() {
  return (
    <div className={containerStyle}>
      <button className={buttonStyle}>点击我</button>
    </div>
  );
}

5、hash 值

2.4.1. globalstyle 设置全局样式

import { globalStyle } from '@vanilla-extract/css';

globalStyle('html, body', {
  margin: 0
});

转换输出:

html, body {
  margin: 0;
}

3. 支线任务

3.1. clsx

合并 css 类名

pnpm add clsx -S

1、App.tsx:

import clsx from "clsx";

export defaultfunction App(){
  const className = clsx({
    btn: true,
    'btn-active': true,
    'btn-error': true
  })
  // 最终dom结果:<div class="btn btn-error btn-active"></div>
  return (
    <div className={ className }></div>
  )
}

2、效果

3.1.1. css modules 与 clsx 结合

import clsx from 'clsx';
import globalStyle from './global.module.css';

function App() {
  const mergeClassName = clsx({
    btn: true,
    'btn-active': true,
    'btn-error': true,
  });

  // css module 和 clsx 结合
  const mergeClassNameModule = clsx(mergeClassName, {
    // global.module.css 中的 flex 编译成 _btn_wyasb_1 这种hash规则 这是 module.css 自带的功能
    [globalStyle.flex]: true,
  });
  
  return  <div className={mergeClassNameModule}>6</div>
}

效果:

3.2. classnames

合并 CSS 类名

1、依赖下载

pnpm add classnames -S

2、App.tsx

import classNames from 'classnames'

export default function App(){
  // classNames
  const names = classNames('foo', 'bar'); // => 'foo bar'
  // 动态
  const key = 'classKey';
  const names1 = classNames({ [key]: true }); // => 'classKey'
  const names2 = classNames(names1,names)
  
  return <div className={names2}></div> //最终结果:<div class="classKey foo bar"></div>
}

3、效果