CSS 解决方案
由于 CSS 都是全局的,因此在大项目中容易出现样式污染的问题。
可以通用用程序生成全局不冲突(即唯一的)的选择器来解决样式污染的问题。
React 栈推荐使用 CSS Modules 和 CSS in JS
classnames
classnames 是一个动态设置样式类的库,比如不同用户组使用不同样式。 首先来安装库
npm i classnames
在一些复杂的场景中,一个元素可能对应多个 className,而每个 className 又基于一些条件来决定是否出现。 这时,classnames 这个库就非常有用。
import classnames from 'classnames';
function App(props) {
const cls = classnames({
btn: true,
btnLarge: props.type === 'submit',
btnSmall: props.type === 'edit',
});
return (
<div className={cls} />
);
}
这样,传入不同的 type 给 App 组件,就会返回不同的 className 组合:
<App type="submit" /> // btn btnLarge
<App type="edit" /> // btn btnSmall
function mergeClass(...source: any[]) {
const classes: string[] = [];
source.filter(Boolean).forEach((s) => {
if (!s) {
return;
}
if (typeof s === 'string') {
classes.push(s);
return;
}
if (Array.isArray(s)) {
classes.push(mergeClass(...s));
return;
}
if (typeof s === 'object') {
Object.entries(s).forEach(([key, value]) => {
if (!key || !value) {
return;
}
classes.push(String(key));
});
}
});
return classes.join(' ');
}
export default mergeClass;
export const classnames = mergeClass;
styled-components
使用社区提供的第三方库来控制样式,下面是使用 styled-components 组件来控制样式
安装扩展包
npm i styled-components
CSS Modules
一般来说用上了css module之后,涉及到一些第三方组件,想要改里面的类样式,常常需要:global
比如 要改.third-party-class类的样式,假设父级业务类为customClass,则编码如下:
.customClass {
:global {
.third-party-class {
// 这里改第三方类的样式
font-size: 28px;
}
}
}
但如果你的customClass碰巧是和third-party-class同级,比如:(虽然少见,但偶尔也会有)
<div class="customClass third-party-class"></div>
这个时候:global的写法就要这么写了
.customClass {
&:global(.third-party-class) {
// 这里改第三方类的样式
font-size: 28px;
}
}
也可以是:(省了三个字符)
.customClass:global(.third-party-class) {
// 这里改第三方类的样式
font-size: 28px;
}
React 中五种常见的样式策略
https://juejin.cn/post/7041745627323056142 React中的样式策略主要有以下几种:
内联样式: 内联样式就是在JSX元素中,直接定义行内的样式; CSS样式表: 这也是我们最常用的样式策略,使用单独的样式表,使用CSS或者SCSS等来为元素设置样式; CSS模块: CSS模块是一个文件,默认情况下所有类名和动画名都在本地范围; styled-components:这是一个用于React和React Native的样式组件库,它允许我们早应用中使用组件级样式,这些样式就是使用CSS-in-JS的技术来编写的; JSS:JSS是一个CSS创作工具,它允许我们使用JavaScript以声明式、无冲突和可重复的方式来描述样式。
内联样式
React中的组件是由JSX元素组件的,虽然编写的不是常规的HTML,但是仍然是可以使用内联样式去定义样式的。
与普通的HTML内联样式唯一的区别就是,JSX中的内联样式是一个对象,而不是一个字符串。 由于style属性是一个对象,所以我们也可以将这个对象定义成一个常量来分隔样式,这样就可以根据需要在其他组件上重用它:
import React from 'react';
const h1Style = {
color: 'red',
textAlign: 'center'
};
export default function App() {
return (
<h1 style={h1Style}>Hello World</h1>
);
}
如果想要在重用时继续扩展这个样式对象,就可以使用ES6中的扩展运算符来实现:
import React from 'react';
const h1Style = {
color: 'red',
textAlign: 'center'
};
export default function App() {
return (
<h1 style={{ ...h1Style, fontSize: '25px' }}>Hello World</h1>
);
}
除此之外,我们还可以在样式对象中使用变量,这样就能实现样式的动态变化:
import React from 'react';
export default function App({ themeColor }) {
const h1Style = {
color: themeColor,
textAlign: 'center'
};
return (
<h1 style={h1Style}>Hello World</h1>
);
}
这也是内联样式最重要的特性之一。但是,React团队并不推荐使用内联样式。内联样式也是CSS-in-JS技术的最基本的示例。
内联样式的优点:
使用简单: 使用内联样式的好处就是简单的以组件为中心来实现样式的添加; 扩展方便: 通过使用对象进行样式设置,可以方便的扩展对象来扩展样式; 避免冲突: 样式通过对象的形式定义在组件中,避免了和其他样式的冲突。
在大型项目中,内联样式可能并不是一个很好的选择,因为内联样式还是有局限性的:
不能使用伪类: 这意味着 :hover、:focus、:actived、:visited
等都将无法使用;
不能使用媒体查询: 媒体查询相关的属性不能使用。
减低代码可读性: 如果使用很多的样式,代码的可读性将大大降低。
没有代码提示:当使用对象来定义样式时,是没有代码提示的,所以如果拼错样式属性,也很难检查出来。