关于react样式隔离

543 阅读2分钟

需求:

spa项目中,当一个子组件直接引入某个css文件的时候,那么父组件相同类名的元素的样式也会受到影响。所以我们需要样式隔离。

实现

vue文件中的style标签可以通过设置scoped属性来为每个css选择器添加唯一标识(元素也有该标识),以此和元素一一对应,防止样式污染。

但是react中并没有这样的属性,那么我们要怎么实现样式隔离呢?

1.设置唯一前缀

为每个组件的父级包裹元素设置一个唯一类名,然后通过less语法的树状结构写法将其写到根节点,相当于统一为当前组件下的所有css选择器加一个共同前缀。

缺点是每个组件的都得起一个不重复的名字,起名困难症不太合适。

2.模块化css

把样式文件改为xx.module.less

引用和使用:

import styles from "./index.module.scss"

render() {
        return (
            <div className={styles.testColor}>
                <h1 className={styles["test-bg"]}>城市列表</h1>
            </div>
        )
    }
//命名的样式名注意用法 ,这个- 横杠的写法在js里面不合法所以用["a-b"]的形式使用

缺点是写法有限制,只支持类名,且不能使用连接符”-“,而且使用的时候还需要多写一个前置对象。

3.styled-components

styled-components 的本质是通过函数的调用,最终创建出一个组件:这个组件会被自动添加上一个不重复的className,styled-components会给该class添加相关的样式

const Box= styled.div`
    color: blue;
  `;
  render(
    <Box>
        Hello  styled-components!
    </Box>
  );

貌似没法用antd这种ui库了?而且我不喜欢把js和css写在一起,不符合直觉,不建议用。

4.webpack-loader

阿里巴巴中台前端团队开发,配置好以后,会自动把类名转换为className{className}-{hash}的格式

npm i scope-jsx-loader scope-css-loader --save-dev
module.exports = {
  module: {
    rules: [
      {
        test: /.(t|j)sx$/i,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader'
          },
          {
            loader: 'ts-loader'
          },
          {
            loader: 'scope-jsx-loader'
          }
        ],
      },
      {
        test: /.(c|sc|sa)ss$/i,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'sass-loader',
          },
          {
            loader: 'scope-css-loader'
          }
        ],
      }
    ]
  }
}

配置完之后,和vue的scoped使用体验就差不多了,和我一开始想找的差不多。

结论

目前推荐第四种,没有条件的话用第一种也可以