跳至主要內容

样式私有化

xiaoye大约 4 分钟ReactReact样式私有化

样式私有化

单页应用开发中,所有组件的css最终会整合到一个html中,样式私有化在单页应用中是一个需要去解决的问题。

vue css样式私有化

vue中样式私有化十分简单,style上加入scoped即可。要覆盖第三方样式使用::v-deep即可,原理如下:

原理就是 属性选择器

第三方样式无法覆盖的原理,

react css样式私有化

react并没有vue这一套机制,目前没有一个特定的方式。所以当前市面上流行的有如下几种,这几种各有优缺点,请根据实际应用场景进行选择。

1. 行内样式【*】

优点:

- **使用简单:** 简单的以组件为中心来实现样式的添加
- **扩展方便:** 通过使用对象进行样式设置,可以方便的扩展对象来扩展样式
- **避免冲突:** 最终都编译为元素的行内样式,不存在样式冲突的问题

局限性,(不适合大型项目)

  • 不能使用伪类: 这意味着 :hover、:focus、:actived、:visited 等都将无法使用
  • 不能使用媒体查询: 媒体查询相关的属性不能使用
  • 减低代码可读性: 如果使用很多的样式,代码的可读性将大大降低
  • 没有代码提示: 当使用对象来定义样式时,是没有代码提示的
  • js文件过大:css-in-js都会有此问题

2. 样式表【***】

CSS样式表应该是我们最常用的定义样式的方式!但多人协作开发中,很容易导致组件间的样式类名冲突,从而导致样式冲突;所以此时需要我们人为有意识的避免冲突

具体做法如下:

  • 保证组件最外层的类名比较独特:路径名称-组件名称的方式
  • 组件的其他样式以嵌套的方式写在最外成那个独特的类名之下

优点:

  • 样式与js分离:(不会存在js比较大)
  • 能使用所有css的功能
  • 容易编写

缺点:

  • 人为的规避,还是容易出现冲突
  • 性能低:选择器过长

3. Css-modules【**】

原理:CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效;产生局部作用域的唯一方法,就是使用一个独一无二的class名字;这就是 CSS Modules 的做法!

不经过编译的类名

:global(.fl) {
    display: flex;
}

CSS Modules 允许使用 :global(.className) 的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。

继承(类似于sass中的mixin)

.title {
    font-size: 20px;
    color: pink;
}

.til {
    composes: title;
    border: 1px solid red;
}

优点:

  • 不需要人为去约束

缺点:

  • 稍显麻烦
  • 不能使用sass,less等高级语法

4. React-JSS【****】

React-JSS 使用新的 Hooks API 将 JSS 与 React 结合使用。 使用步骤如下:

  • 安装react-jss: yarn add react-jss
  • 借助它的方法createUseStyles ,返回一个hook函数
  • 执行hook函数,得到一个一个的类
import React from 'react'
// import './SubChild.scss'
import {createUseStyles} from 'react-jss'

const useStyle = createUseStyles({
  title: {
    color: 'red',
    fontSize: '24px',
    fontWeight: 'bold'
  },
  subTitle: {
    color: props => {
      console.log(props)
      if(props.theme === 'gray') return '#eee'
      return 'red'
    },
    fontSize: '20px',
    // 基于 & 实现后代选择
    '& span': {
      color: '#000'
    },
    '&:hover': {
      color: 'yellow'
    }
  }
})



export default function SubChild() {
  const { title, subTitle } = useStyle({
    theme: 'gray'
  })
  return (
    <div className="box">
        <h1>SubCHild box 下的h1</h1>
        <p className={title}>我是title</p>
        <p className={subTitle}>我是 <span>subtitle</span> </p>

    </div>
  )

优点

  • 功能强大: 不仅支持css的所有东西,也能和js想结合
  • 灵活: 样式可以根据传入的props生成

缺点:

  • 只能在hook组件中使用
    • 如果硬要在类组件中使用它,请使用函数组件将其包一层(高阶组件的使用)

5. styled-components【****】

基本用法

  • 安装

    • yarn add styled-components
  • 创建一个样式js文件,编写样式。基本语法如下:

    import styled from 'styled-components'
    
    // 安装插件:vscode-styled-components
    export const ChildComWrapper = styled.div`
        .title {
            color: red;
        }
        .sub-title {
            color: ${props => {
                console.log(props)
                if(props.theme === 'gray') return 'gray'
                return 'green'
            }};
            &:hover {
                color: red;
            }
        }
    `
    
    

    返回的是一个组件哟

  • 在组件中使用

    import React from 'react'
    import { ChildComWrapper } from './style'
    
    // style-component
    export default function ChildCom() {
      return (
        <ChildComWrapper theme={'gray'}>
            <p className='title'>我是title</p>
            <p className='sub-title'>我是sub-title</p>
        </ChildComWrapper>
      )
    }
    

扩展用法(抽取变量,抽取公共的组件)

  • 创建一个公共样式文件

    import styled from 'styled-components'
    
    
    export const NavWrapper = styled.ul`
        display: flex;
        color: #000;
        li {
            margin-right: 10px;
            list-style-type: none;
            &.active {
                color: red;
            }
        }
    `
    
  • 需要的地方使用

    import React from "react";
    import { ChildComWrapper } from "./style";
    import { NavWrapper } from '../../assets/common'
    
    // style-component
    export default function ChildCom() {
      return (
        <>
          <ChildComWrapper theme={"gray"}>
            <p className="title">我是title</p>
            <p className="sub-title">我是sub-title</p>
          </ChildComWrapper>
          <NavWrapper>
            <li className="active">登录</li>
            <li>我的</li>
            <li>秒杀</li>
          </NavWrapper>
        </>
      );
    }