前言
React/Vue/Angular等框架出现之前的前端是html+css+js来渲染和实现页面交互,那时候更关注的点是分离,尽量不要耦合使结构更清晰
<div style="width:100px;height:32px" onclick="alert('hello world')">hello world</div>
这样出现三大件在同一段代码里面是被认为极度不规范的,但框架出现以后采用组件化的开发方式,为了封装结构、样式、逻辑,实现组件隔离和复用,使调用者更方便使用,这种组件化的方式反而逐渐成为主流
const Index = ({width,height,onClick,children})=>{
const style = {
width: `${width}px`,
height: `${height}px`,
}
return (<div onClick={onClick}>{children}</div>)
}
react使用jsx对html进行封装,通过来操作html和css,约定对css带“-”的属性采用驼峰的约定。css的样式规则是对整个页面生效的,在单页面中相当于是全局的,由于对css的封装非常脆弱,以及命名冲突等众多问题,出现许多 css in js 的三方库和css modules的解决方案,之所以能使css做到局部生效,看起来具有模块化,实质是通过唯一类名来实现,或通过一些打包工具的插件生成唯一hash类名。本文重点讲的 styled-components 算是css-in-js中最热门的一个库。
安装
npm install --save styled-components
vscode插件:vscode-styled-components
举例
- 对象写法和模板字符串写法(鼓励使用模板字符串写法,因为CSS语法支持伪选择器、媒体查询、嵌套等,而对象语法不支持,它们会被视为内联样式)
import styled from 'styled-components'
const Box1 = styled.div({
background: 'yellow',
height: '50px',
width: '50px',
});
const Box2 = styled.div`
background:blue;
height:50px;
width:50px;
`
- 通过继承和父级参数生成基本的主题组件
import styled from 'styled-components'
const LoopBasic = styled.div`
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
`
// 实现继承
const LoopOuter = styled(LoopBasic)`
width: 24px;
height: 24px;
background: #ffffff;
border: 1px solid ${props => props.color};
`
const LoopInner = styled(LoopBasic)`
width: 18px;
height: 18px;
background: ${props => props.color};
cursor: pointer;
`
const Index = ({color = '#FFBB00'}) => {
return (
<LoopOuter color={color}><LoopInner color={color} /></LoopOuter>
)
}
- 实现css常用的旋转动画
import styled ,{ keyframes } from "styled-components"
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const Rotate = styled.div`
display: inline-block;
animation: ${rotate} 2s linear infinite;
padding: 2rem 1rem;
font-size: 1.2rem;
`;
const Index = () => {
return (<Rotate>< 💅🏾 ></Rotate>)
}
- 样式类和一个样式化的组件类应用在一起,结果是样式组件类优先于样式类,因为默认情况下,样式组件在运行时将其样式注入到head标签的末尾。因此,它的样式胜过其他单一的类名选择器。
.test {
background: blue;
}
---------------
import styled from 'styled-components'
const Test1 = styled.div`
background: red;
width: 100px;
height: 100px;
`
const Test2 = styled.div`
width: 100px;
height: 100px;
`
const Index = () => {
return (
<>
<Test1 className={styles.test} /> {/**红色 */}
<Test2 className={styles.test} /> {/**蓝色 */}
</>
)
}
- 通过css助手实现css复用
import styled, { css } from 'styled-components'
const complexMixin = css`
color: ${props => (props.whiteColor ? 'white' : 'black')};
`
const StyledComp = styled.div`
${props => (props.complex ? complexMixin : 'color: blue;')};
`
- 通过组件的as属性实现标签的多态
import React, { FC } from 'react'
import styled from 'styled-components'
const Component = styled.div`
color: red;
`;
const Index = () => {
return (
<Component
as="button"
onClick={() => alert('It works!')}
>
Hello World!
</Component>
)
}
export default Index
- 通过ThemeProvider实现主题(react组件并不能拿到主题的参数,仅通过styled生成的组件才能拿到;可以通过withTheme高阶助手来包裹拿到顶层主题,或者使用ThemeConsumer来消费)
import React from 'react'
import styled, { ThemeProvider, withTheme } from 'styled-components'
const Box1 = styled.div`
color:${props => props.theme.color};
`
const Box2 = styled.div`
color:${props => props.theme.color};
`
const Box31 = styled.div`
color:${props => props.theme.color};
`
const Box3 = (props: any) => {
console.log(props)
return (<>
<div>{props.children}</div>
<Box31>box31</Box31>
</>)
}
const Box4 = withTheme((props: any) => {
console.log(props)
return <div>{props.children}</div>
})
const Index = () => {
return (
<ThemeProvider theme={{ color: 'red' }}>
<Box1>box1</Box1>
<Box2>box2</Box2>
<Box3>box3</Box3>
<Box4>box4</Box4>
</ThemeProvider>
)
}
export default Index
- 样式组件通过“组件选择器”模式实现上下文覆盖,形成组合模式。
const BoxWrapper = styled.div`
border: 1px solid #ccc;
height: 100px;
width: 100px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
`
const Box = styled.div`
background: yellow;
height: 50px;
width: 50px;
${BoxWrapper}:hover & {
background: red;
}
`
const Index = () => {
return (
<BoxWrapper>
<Box />
</BoxWrapper>
)
}
好处
- 少量样式写在js里面,不必单独引入css文件,jsx+react+styled贯彻React的everything in js理念
- 使用js零学习成本,也不会多一道编译步骤,速度更快
- 样式可以使用变量,组件化写法
- 使用方便,不需要配置 webpack、开箱即用
不足
- 使用时感觉过度组件化
- 自动生成的类名可读性较差,样式过多时不好定位具体元素