一直在思考React组件如何拆分的问题,直到接触到styled-components,让我有一种如鱼得水的感受,今天我就给你们分享一下这个库如何让咱们的前端组件开发的更优雅,如何保持更合适的组件拆分粒度从而更容易维护。css
styled-components是给React量身定制的一个库,奉行React中all in js的设计理念,并将这个理念进一步发挥到极致,让CSS也可以成为一个个的JS模块。html
使用起来也至关方便,首先安装这个库前端
npm install styled-components --save
复制代码
而后在style.js中使用(注意这里不是style.css,样式文件所有是JS文件)html5
import styled from 'styled-components';
//styled.xxx表示建立xxx这个h5标签,
//后面紧接的字符串里面写的是CSS代码
export const HeaderWrapper = styled.div` z-index: 1; position: relative; height: 56px; border-bottom: 1px solid #f0f0f0; `;
复制代码
以后再React中使用它:react
import React, {Component} from 'react';
import { HeaderWrapper } from './style.js';
class App extend Component{
render() {
return (
<HeaderWrapper></HeaderWrapper>
)
}
}
export default App;
复制代码
Ok!这就是它的平常使用方式。若是有兴趣能够去github的相应仓库打开更多使用姿式:)git
可能你还会有疑惑:这么作有什么好处呢?github
尽可能下降模块之间的耦合度,利于项目的进一步维护。比起用原生的CSS,这是它首当其冲的优点。web
如:npm
export const SearchWrapper = styled.div`
position: relative;
float: left;
.zoom {
right: 5px;
&.focused {
background: #777;
color: #fff;
}
}
`;
复制代码
能够采用sass,less的嵌套语法,开发更加流畅。sass
不只仅是由于里面的模板字符串能够写JS表达式,更重要的是可以拿到组件的上下文信息(state、props)
好比,在React组件中的JSX代码中写了这样一段:
<RecommendItem imgUrl={'xxx'}/>
复制代码
在相应的style.js中就可以接受相应的参数:
export const RecommendItem = styled.div` width: 280px; height: 50px; background: url(${(props) => props.imgUrl}); background-size: contain; `;
复制代码
CSS可以拿到props中的内容,进行相应的渲染,是否是很是酷炫?
若是以上几点还不能体现它的优点,那这一点就是对于前端开发者的毒药。
如今不少人对标签语义化的概念趋之若鹜,但其实大多数开发者都仍是div+class一把撸的模式。难道是由于语义化很差吗?可以让标签更容易理解固然是件好事情,可是对于html5规范推出的标签来讲,一方面对于开发者来讲略显繁琐,仍是div、span、h1之类更加简洁和亲切,另外一方面标准毕竟是标准,它并不能表明业务,所以并不具备足够的表达力来描述纷繁的业务,甚至这种语义化有时候是无关紧要的。我以为这两点是开发者更喜欢div+class一把撸的根本缘由。
那好,照着这个思路,拿React组件开发而言,若是要想得到更好的表达力,尽量的语义化,那怎么办?可能你会暗笑:这还用说,拆组件啊!但组件真的是拆的越细越好吗?
有人曾经说过:当你组件拆的愈来愈细的时候,你会发现每个组件就是一个标签。可是这会形成一些更加严重的问题。假设咱们拆的都是UI组件,当咱们为了语义化连一个button都要封装成一个组件的时候,代码会臃肿不堪,由于会出现数量过于庞大的组件,很是不利于维护。
那,有没有一个折中的方案呢?既能提升标签语义化,又能控制JS文件的数量。 没错,这个方案就是styled-components。
以首页的导航为例, 取出逻辑后JSX是这样:
<HeaderWrapper>
<Logo/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载App</NavItem>
<NavItem className='right'>
<i className="iconfont"></i>
</NavItem>
<SearchWrapper>
<NavSearch></NavSearch>
<i className='iconfont'></i>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<i className="iconfont"></i>
来参加
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
复制代码
//style.js
import styled from 'styled-components';
export const HeaderWrapper = styled.div` z-index: 1; position: relative; height: 56px; border-bottom: 1px solid #f0f0f0; `;
export const Logo = styled.div` position: absolute; top: 0; left: 0; display: block; width: 100px; height: 56px; background: url(${logoPic}); background-size: contain; `;
export const Nav = styled.div` width: 960px; height: 100%; padding-right: 70px; box-sizing: border-box; margin: 0 auto; `;
//......
复制代码
拆分后的标签基本是在style.js里面导出的变量名,彻底自定义,这个时候CSS都成为了一个个JS模块,每个模块至关于一个标签(如:styled.div已经帮咱们建立好了标签),在模块下面彻底能够再写h5标签。这样的开发方式实际上是很是灵活的。
坑: 之前的injectGlobal已经被弃用,所以对于全局的样式文件须要使用createGlobalStyle来进行引入。
//iconfont.js
//全局样式同理
import {createGlobalStyle} from 'styled-components'
export const IconStyle = createGlobalStyle` @font-face { font-family: "iconfont"; src: url('./iconfont.eot?t=1561883078042'); /* IE9 */ src: url('./iconfont.eot?t=1561883078042#iefix') format('embedded-opentype'), /* IE6-IE8 //... } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } `
复制代码
而后在全局的根组件App.js里面:
import { IconStyle } from './statics/iconfont/iconfont'
import { GlobalStyle } from './style'
//import ...
function App() {
return (
<Provider store={store}> <div> {/* 经过标签形式引入这些样式 */} <GlobalStyle></GlobalStyle> <IconStyle></IconStyle> <Header /> <BrowserRouter> <div> <Route path='/' exact component={Home}></Route> <Route path='/detail' exact component={Detail}></Route> </div> </BrowserRouter> </div> </Provider>
);
}
export default App;
复制代码
对于styled-components缺点而言,我认为目前惟一的不足在于模板字符串里面没有CSS语法,写起来没有自动提示,对于用惯IDE提示的人来讲仍是有美中不足的。不过也并非什么太大的问题,若是有相应的插件或工具欢迎在评论区分享。
对于styled-components以及组件化一点小小的思考,记录一下,但愿能对各位有启发。