需求:
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
阿里巴巴中台前端团队开发,配置好以后,会自动把类名转换为{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使用体验就差不多了,和我一开始想找的差不多。
结论
目前推荐第四种,没有条件的话用第一种也可以