我为什么要使用styled-components
最近一直在学习和使用react开发自己的博客系统,可能是之前一直都在用vue的缘故,在学习过程中脑子里面一直都潜移默化的和vue比较,其中让我最难受的就是react中css的书写。
因为在vue中每个组件都有单独写style的地方,并且都相互不影响,这样更符合组件化和减少多人开发中的样式冲突。但到react中我也尝试把样式和逻辑代码放到一起,这样可避免多人开发合并代码后带来的冲突,出bug了也好定位到个人,但是在js文件里面写css真的很难受,有些地方必须要加引号,比如:
const style = {
'color': 'red',
'fontSize': '79px'
};
const clickWorld = () => alert('hell0');
ReactDOM.render(
<h2 style={style} onclick={clickWorld}>
Hello, world!
</h2>,
document.getElementById('example')
);
这样导致书写很慢,出问题后在js文件里面找css的问题也不一目了然,如果每个组件都写一个css文件然后单独引入的话会使项目变得很冗杂。总之之前的css书写不舒服,维护也不方便。但是直到我遇到styled-components后浑身就舒畅了。
什么是styled-components
styled-components是针对react的一套css in js框架,什么意思呢?就是让你在js中写css,并且和在css文件中一样书写流畅,而且用的是js语法,没啥学习成本。如果你喜欢Vue中书写css的方式,那么这个插件你肯定相见恨晚。夸了这么多它的好是不是有点抽象,下面来举个栗子吧。
-
class类名唯一
当你使用它之后,打开控制台你就会发现这样的情况
天啊,我的类名咋成乱码了?不要慌,这是styled-components自己处理的,为了保证你定义的每个组件样式唯一,妈妈再也不用担心我为组件起名了,而且开发过程中起名在你不经意间就会重复,这样带来的后果肯定大部分人都体会过。
-
以样式为结构
可以以样式为结构,比如我先定义一个背景为红色,宽高为200px的div,div里面span字体大小为13px,颜色为蓝色。这时你把组件放进去,这个组件里面的div就是红色、宽高200px,里面的span的字体也就是蓝色、13px。
const styleContainer = styled.div` height:200px; width:200px; background-color:red; span{ font-size:13px; color:blue; } ` const container = () =>( <styleContainer> <div> <span>油炸日子</span> </div> </styleContainer> )这样写起来样式是不是很好维护,哪个组价出问题了,直接找样式结构就可以啦。
styled-components的使用
-
安装
npm install --save styled-componentsyarn add styled-components如果你的编辑器是vscode的话建议你下载
vscode-styled-components这个插件,它让智能提示失而复得。 -
入门
import React from 'react'; import styled from 'styled-components' const UzrzContainer = styled.div` background-color:red; span{ color:blue } ` const Layout = () => ( <UzrzContainer> <div> <span>油炸日子</span> </div> </UzrzContainer> ) export default Layout; -
传递props
- 样式组件可以透传包裹的组件的props
import React from 'react'; import styled from 'styled-components' const UzrzContainer = styled.input` ` const Layout = () => ( <UzrzContainer type="password" placeholder="油炸日子"> </UzrzContainer> ) export default Layout;type和placeholder属性是input标签的属性,但是样式组件可以把属性透传到包裹的input上
- 可以通过react组件传递porps来动态改变样式
const UzrzContainer = styled.div` background-color:red; span{ color:blue; font-size:${props => props.size}; } ` const Layout = () => ( <UzrzContainer size="20px"> <div> <span>油炸日子</span> </div> </UzrzContainer> )- 可以通过传递的props做样式判断
const UzrzContainer = styled.div` background-color:red; span{ color:blue; font-size:${props => props.size ? props.size : '14px'}; } ` const Layout = () => ( <UzrzContainer size> <div> <span>油炸日子</span> </div> </UzrzContainer> ) -
extend 继承
有些时候我们需要设计一套组件,比如设计一套按钮,这一套按钮只是背景颜色不变,其他的样式都一样,那么这时就是extend大放异彩的时候了。
cosnt UzrzPrimaryButton = styled.button` background-color:blue; width:200px; height:50px; border-radius:10px; ` // 这里只需要让UzrzWarningButton继承UzrzPrimaryButton的样式,然后设置自己的background-color,然后UzrzPrimaryButton的背景颜色就会被UzrzWarningButton替换掉。 const UzrzWarningButton = styled(UzrzPrimaryButton)` background-color:yellow ` -
样式化组件
import React from 'react'; import styled from 'styled-components' const UzrzContainer = (props) => (<div> <span className={props.className}>{props.children}</span> </div> ) const CopyContainer = styled(UzrzContainer)` background-color:red; span{ color:blue; font-weight:bold; } ` const Layout = () => ( <div> <UzrzContainer >油炸日子</UzrzContainer > <CopyContainer>油炸日子</CopyContainer> </div> ) export default Layout;**注意:**这里的className一定要加上,否则样式并没有生效。
这里相当于CopyContainer复制了UzrzContainer这个组件,然后装饰了下。
假如你想复制这个组件并且放到另外一个容器里面,你还可以
component selector样式化组件,这样是不是少写了很多class,命名有些时候蛮痛苦的,但是styled-components解决的挺干净的。import React from 'react'; import styled from 'styled-components' const UzrzContainer = (props) => (<div> <span className={props.className}>{props.children}</span> </div> ) const CopyContainerInner = styled(UzrzContainer)`` const CopyContainerOut = styled.div` padding:20px; ${CopyContainerInner}{ background-color:red; color:#fff; } ` const Layout = () => ( <div> <CopyContainerOut > <CopyContainerInner>油炸日子</CopyContainerInner> </CopyContainerOut > </div> ) export default Layout; -
withComponent
有些时候我在样式写好了后,可能想想更改组件的标签类型,这时候可以用下withComponent
import React from 'react'; import styled from 'styled-components' const UzrzContainer = styled.div` background-color:red; color:blue; ` const CopyContainer = UzrzContainer.withComponent('span') const Layout = () => ( <div> <UzrzContainer >油炸日子</UzrzContainer > <CopyContainer>油炸日子</CopyContainer> </div> ) export default Layout;当我们审查元素时就会发现UzrzContainer渲染的元素是div,CopyContainer渲染出来的是 span。
-
refs
这里使用的4.0.0及以上的版本,如果你使用的是4.0.0以下的版本,那么获取dom就要使用innerRef,这里只是介绍refs,innerRef请移步官网styled-components
4.0.0版本更新后在styled组件中获取dom和在react组件获取dom的操作是一样的,也是无缝连接。
import React, { Component } from 'react'; import styled from 'styled-components' const UzrzContainer = styled.input` background-color:red; color:blue; width:200px; height:50px; ` class Layout extends Component { constructor(props) { super(props); this.state = {} this.input = React.createRef() } render() { return (<UzrzContainer ref={this.input} onMouseEnter={() => { console.log(this.input) }}> </UzrzContainer >); } } export default Layout; -
isStyledComponent
有些时候我们需要判断一个组件是不是StyledComponent,我们才好运用只有StyledComponent才具有的特性,比如样式化组件
import React from 'react'; import styled, { isStyledComponent } from 'styled-components'; import OuterComponents from './outer' let UzrzComponent = isStyledComponent(OuterComponents) ? OuterComponents : styled(OuterComponents)``; const UzrzContainer = styled.div` color: blue; ${UzrzComponent} { color: red; } ` const Layout = () = ( <UzrzContainer> <UzrzComponent /> </UzrzContainer> ) -
attr
给样式组件添加默认属性
import React from 'react'; import styled from 'styled-components' const UzrzContainer = styled.div.attrs({ // 给盒子添加css属性,赋予初始值 margin: props => props.out || '0', padding: props => props.inner || '0' })` margin:${props => props.margin}; padding:${props => props.margin}; ` const Layout = () => ( <UzrzContainer out="20px" inner="30px"> 油炸日子 </UzrzContainer> ) export default Layout; -
动画
官网上面解释的意思大概是:带有@keyframes的CSS animations,一般来说会产生复用。
styled-components暴露了一个keyframes的API,我们使用它产生一个可以复用的变量。这样,我们在书写css样式的时候使用JavaScript的功能,为CSS附能,并且避免了名称冲突。import React from 'react'; import styled, { keyframes } from 'styled-components' const scaleTwo = keyframes` from{ transform:scale(1) } to{ transform:scale(2) } ` const Uzrz = styled.div` animation: ${scaleTwo} 2s linear infinite; background-color:red; ` const Layout = () => ( <Uzrz >油炸日子</Uzrz> ) export default Layout; -
全局样式
Styles-components也提供了全局样式的函数
createGlobalStyleimport { createGlobalStyle } from 'styled-components' const GlobalStyle = createGlobalStyle` body{ margin:0; padding:0; width:100vw; height:100vh; } ` export default GlobalStyle -
主题
styled-components还提供了一个ThemeProvider容器组件,这样你可以用来设置默认主题和更好地切换主题。下面我们来完成一个切换主题的功能
import React from 'react'; import styled, { ThemeProvider } from 'styled-components' const defaultTheme = { backgroundColor: "white", color: '#000' } const darkTheme = { backgroundColor: "black", color: '#fff' } const Uzrz = styled.div` background-color:${props => props.theme.backgroundColor}; color:${props => props.theme.color}; button{ background-color:${props => props.theme.backgroundColor}; color: ${ props => props.theme.color}; } ` class Layout extends React.Component { constructor(props) { super(props); this.state = { selectTheme: defaultTheme //给组件一个默认的初始主题 } this.changeTheme = this.changeTheme.bind(this) } changeTheme() { // 点击切换主题按钮,把没有选中的主题赋值给selectTheme this.state.selectTheme === defaultTheme ? this.setState({ selectTheme: darkTheme }) : this.setState({ selectTheme: defaultTheme }) } render() { return ( <ThemeProvider theme={this.state.selectTheme}> <Uzrz> <button onClick={this.changeTheme}>切换主题</button> </Uzrz> </ThemeProvider> ); } } export default Layout;这样写主题是不是很方便呢。
-
最后
Styled-components也可以用在react native上,并且对SSR服务端渲染还有很好地支持等等一些很不错的功能,但是小编暂时还没有用到,等以后使用后会慢慢补充的。谢谢小伙伴们花时间和我一起学习~