前言
在多人开发的时候,或者说二开的时候,不知道大家有没有这样一种体会:
- 我明明给一个组件添加
className
了,居然样式不生效?!仔细一看,我靠,原来是别人写的样式影响了我的这个组件的样式,或者说他正好className
和我一样,改他的样式吧,又怕影响他,改我的样式吧,又烦,而且别人下次写样式,也有可能会受我的这个影响。 - 每次我创一个组件,就要另外新建一个
.css
文件,而且样式又不是很多,但偏偏要新建一个文件,就很烦,而且还要自己想一个className
,我懒!直接写在组件上吧,多起来了又显得代码不整洁。 - 如果组件的样式是动态的,需要根据别人传的
props
来决定,那我又要面临事先写好两套样式,想两个className
- 既然
react
里面支持jsx
语法,那我就相当于可以把html代码
写在js文件
,那为什么就不能在js文件
里面写css代码
?如果支持的话,不说一定很爽,但至少也可以带来不一样的体验
Tip: 这个时候可能会有人会想到用
sass + css module
的方案来解决上面的一些问题和疑问,但你都来看这篇文章了,想必你想寻找更好的解决办法,或者说css module
也没想到,那这个可以看下阮一峰大佬的文章
正片
在项目中,往往会这样给一个组件加样式:
// App.js
import "./App.css"
function App() {
return (
<div className="app">
<p>
hello world
</p>
</div>
);
}
/* App.css */
.app p{
background-color: burlywood;
font-size: 24px;
}
效果:
但是现在这里要介绍一种css in js
库-----styled-components
,先下载:
npm i styled-components -D
常规用法
然后我们就能将上面的常规步骤写成如下这样:
import styled from "styled-components";
const Div = styled.div`
padding: 6px;
p{
background-color: burlywood;
font-size: 24px;
}
`
function App() {
return (
<Div>
<p>
hello world
</p>
</Div>
);
}
效果:
这时你就会发现两个写法不一样,但是却能达到同样的效果,而且这个新的写法你会发现,其实就是给这个元素加上一个唯一的className
,但是不是你自己加啊,它不仅可以可以应用于外层的div
元素的padding样式
,它还能同时在里面写上后代元素p
标签,且样式也是能生效的,甚至你还可以嵌入其他className
、伪元素
、sass
写法等等,就像下面这样写:
import styled from "styled-components";
const Div = styled.div`
padding: 6px;
p{
background-color: burlywood;
font-size: 24px;
}
.test{xxx: xxx}
&:hover{
background-color: antiquewhite;
}
`
function App() {
return (
<Div>
<p>
hello world
</p>
</Div>
);
}
通过props来决定样式
import styled from "styled-components";
const Div = styled.div`
width: 100px;
padding: 5px;
margin: 10px;
text-align: center;
border: 2px solid pink;
background-color: ${(props) => {
console.log(props);
return props.type === 'primary' ? '#3498db' : 'white'
}};
`
function App() {
return (
<>
<Div >
default
</Div>
<Div type='primary'>
primary
</Div>
</>
);
}
效果:
这个时候你就会发现我是通过div
的type
属性来决定它的背景色,且确实能够在你写css中使用js语法,通过${}
的形式传入一个回调函数,回调函数中props
对象里面,包括你自己加的type
属性,以及自己自带的theme
属性,如下:
而其中的children
属性其实是react它自己会给组件加一个children
属性,来代表子元素;theme
属性是用来给你传入不同的主题对象,也许为了type
不同,你可以直接应用于不同的主题,这里就不过多解释了。
控制组件的其他属性
有些元素本身是具备一些特有的属性的,如input
的type
属性,button
的onclick
属性,你可以这样写:
import styled from "styled-components";
const Input = styled.input.attrs({
type: 'text'
})``
const Password = styled.input.attrs({
type: 'password'
})``
const Button = styled.button.attrs({
onClick: () => {
console.log('按钮被点击了...');
}
})``
function App() {
return (
<>
<Input />
<br />
<Password />
<br />
<Button>按钮</Button>
</>
);
}
也确确实实可以控制元素本身的一些属性
css混入(mixin、变量化)
import styled, { css } from "styled-components";
const complexMixin = css`
color: ${props => (props.redColor ? 'red' : 'black')};
`
const StyledComp = styled.div`
${props => (props.complex ? complexMixin : 'color: blue;')};
`
function App() {
return (
<>
<StyledComp>
无complex
</StyledComp>
<StyledComp complex redColor>
有complex 且 redColor
</StyledComp>
</>
);
}
效果:
keyframes变量化
import { keyframes } from 'styled-components';
const fadeIn = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;
const FadeInButton = styled.button`
animation: 1s ${fadeIn} ease-out;
`;
总结
当然我上面讲诉的是一些比较常用的用法,更多的你可以看下官网文档,不过看了那么多例子,想必也会有些体会:
优点:
- 它能让你组件拥有一个唯一的
className
,不同文件的之间的组件不会受到彼此之间的影响 - 它能让你的
css
支持js
语法,从而更加的灵活,而且还能让你同时享受sass
写法 - 如果你现在就想使用,直接下载依赖包就可以了,不用担心之前的写法不兼容,友好升级
那有没有缺点呢?
我自己体会到的,不知道算不算是缺点:
- 虽然可以不用再专门创建一个
css
文件了,但是如果组件多了,那我这个js
文件岂不是越来越大?,越写越多?那后面维护,岂不是很难受? - 我已经习惯于把
js
和css
分开写的习惯了,且react中jsx
里面本来也可以直接在组件上面写样式 - 如果这个项目是自己一个人写,用这种可能是挺方便的,人多了,是不是还不如用
css module
? - 本质上它是在
js
运行时,通过webpack
的一些loader
向header
标签里面插入style
标签,这无疑会增加js文件的加载效率 - 如果不能把css抽离出去,那岂不是不能享受缓存?
总之看个人和项目吧,这篇文章也仅是学习和记录