组件化天下的CSS
组件化开发中合适的CSS应该符合以下条件:
- 可以编写局部css:css具备自己的局部作用域,不会随意污染其他组件内的原生;
- 可以编写动态的css:可以获取当前组件的一些状态,根据状态的变化生成不同的css样式;
- 支持所有的css特性:伪类,动画,媒体查询等;
- 编写简洁方便,符合一贯的css风格;
一. 内联样式
官方推荐的一种写法:
- style接受一个小驼峰命名属性的JS对象,而不是CSS字符串。
- 并且可以引用state中的状态来设置相关的样式。
优点:
- 内联样式之间不会有冲突;
- 可以动态获取state中的状态。
缺点:
- 写法上使用驼峰标识(和原来css有差异);
- 某些样式没有提示;
- 大量的样式,代码混乱;
- 某些样式无法编写(比如:伪类/伪元素)。
- 所以官方仍热希望内联样式和普通的css来结合编写。
export default class app extends PureComponent {
render() {
const pStyle = {
color: "orange",
textDecoration: "underline",
}
return (
我是标题
我是一段文字描述
)
}
}
二. 普通样式
- 单独文件引入。
- 直接子代选择器 > 用来选择。
缺点:样式之前会相互层叠掉。
三. css modules
不是React特有解决方案,所有使用了类似webpack配置的环境下都可以使用的。
- 配置需要我们自己来修改,比如webpack.config.js中modules: true等。
React脚手架已经内置了css modules的配置: - .css/.less/.scss等样式文件都修改成.module.css/.module.less/.module.scss等;
- 之后就可以引用并使用了。
- .module.css文件使用时,会动态生成一个name,防止重叠。
import React, { PureComponent } from 'react'
// import './style.module.css'
import style from './style.module.css'
export default class Profile extends PureComponent {
render() {
return (
我是Profile的标题
- 设置列表1
- 设置列表2
- 设置列表3
)
}
}
缺陷:
css module确实解决了局部作用域的问题,但仍有缺陷。
- 引用的类名,不能使用连接符;
- 所有className都必须使用{style.className}的形式来编写;
- 不方便动态来修改某些样式,依然需要使用内联样式的方式;
- 看情况选择,相对受欢迎。
四. CSS in JS
官方文档也有相关内容:
- 一种模式,其中CSS由JS生成而不是在外部文件中定义;
- 不是React的一部分,由第三方库提供;
传统开发中,通常会将HTML,CSS,JS进行分离: - 但React思想认为JS本身和UI是无法分离的,所以有了JSX语法;
- 样式也是UI的一部分;
事实上CSS-in-JS模式就是一种将样式CSS也写到JS中的方式,并可以方便地使用JS中的状态; - 某种程度React:All in JS。
- 比较适用,但这种方式也有很多批评
- CSS-in-JS通过JS来为CSS赋予一些能力,包括类似于CSS预处理器一样的样式嵌套,函数定义,逻辑复用,动态修改状态等等;
- CSS处理器中,获取动态状态不好处理;
- 所以CSS-in-JS是React编写css最为受欢迎的一种解决方案。
流行的css-in-js库 - styled-components
- emotion
- glamorous
语法补充:标签模板字符串
可以通过模板字符串的方式对一个函数进行调用。
function test(...args) {
console.log(args);
}
// 普通方式
test("aaa","bbb","ccc")
// 模板字符串调用函数
test`aaaa`
- 模板字符串将传进来的东西,当作参数,传入函数中。
- 将传入的东西默认放到一个数组中
test`my name is ${name}, age is ${age}`
- 先把传进的所有东西放入数组中;
- 把数组中东西切割成一个个元素;
- 插值${}语法取到的放在该数组里,并分割模板字符串;
- 框架用类似正则表达式对模板字符串解析;
// 插值动态赋值
test`
font-size: 15px;
color: ${props => props.color};
`
五. styled-components使用
import React, { PureComponent } from 'react'
import styled from 'styled-components';
const HomeWrapper = styled.div`
font-size: 50px;
color: red;
`
export default class Home extends PureComponent {
render() {
return (
我是home的标题
轮播图
)
}
}
- 支持伪类,伪元素 。
import React, { PureComponent } from 'react'
import styled from 'styled-components';
const HomeWrapper = styled.div`
font-size: 50px;
color: red;
.banner {
background-color:blue;
span {
color: #fff;
&.active {
color: #f00;
}
&:hover{
color:green;
}
&::after{
content: "aaa"
}
}
}
`
const TitleWrapper = styled.h2`
text-decoration: underline;
font-size
`
export default class Home extends PureComponent {
render() {
return (
我是home的标题
轮播图1
轮播图2
轮播图3
轮播图4
)
}
}
- 以下真实开发中应该把css提到单独文件中。
import React, { PureComponent } from 'react'
import {
HomeWrapper,
TitleWrapper
} from "./style"
export default class Home extends PureComponent {
render() {
return (
我是home的标题
轮播图1
轮播图2
轮播图3
轮播图4
)
}
}
styled-components特点:
- props穿透,可以添加属性
// 第一种写法
// 第二种写法,更加强大,可以定义其他属性
const HYInput = styled.input.attrs({
placeholder: "coderwwq",
bColor: "red",
})`
background-color: lightblue;
border-color: ${props => props.bColor};
`
完整代码
import React, { PureComponent } from 'react'
// import './style.module.css'
import styled from 'styled-components'
/**
* 特点:
* 1. props穿透
* 2. attrs的使用
* 3. 传入state作为props的属性
* 4. 继承
* 5. 主题设置
*/
const HYInput = styled.input.attrs({
placeholder: "coderwwq",
bColor: "red",
})`
background-color: lightblue;
border-color: ${props => props.bColor};
color: ${props => props.color}
`
export default class Profile extends PureComponent {
constructor(props) {
super(props);
this.state = {
color: "purple",
}
}
render() {
return (
我是Profile的标题
- 设置列表1
- 设置列表2
- 设置列表3
)
}
}
主题可以提供共享样式。
// 主题设置 + 继承,代码