版权声明:本文为博主原创文章,未经博主允许不得转载。
PS:转载请注明出处
作者: TigerChain
地址: http://www.jianshu.com/p/dd2a5b1b95c5
本文出自 TigerChain 简书 ReactNative 系列
教程简介
- 1、阅读对象
本篇教程适合新手阅读,老手直接略过
-
2、教程难度
初级
3、Demo 地址:https://github.com/tigerchain/rn-lesson/tree/master/lesson01/02、stylecomponents/styleComponent
我们都知道在 RN 中使用的的内联样式,是通过 StyleSheet 组件创建出来的样式「当然也可以使用 const style={} 来定义」
对于 web 开发者来说,特别是使用 css 样式的人来说写样式的时候总是不自觉的要加一个 - ,那么你也可以使用样式组件--styled-components ,这们来重点介绍一下 styled-components
一、 什么是 styled-components
熟悉前端的童鞋都知道,html 中引入 css 有三种方式
- 嵌入式
<head>
<style type="text/css">
h3{color:red}
span{color:blue}
</style>
<head>
- 内联式
<p style="color:#FFEECC;font-weight:bold;">内联样式</p>
- 外部引用入,有 link import 等
这里说一下 link
<link rel="stylesheet" type="text/css" href="theme.css" />
<html>
指令语句
</html>
在 RN 中使用的也是内联样式,那有没有一个既有 web 开发中 css 书写特性,也能把 React 组件化思想结合在一起「有样式的组件」组件呢?styled-components 就能满足我们的需求
styled-components 则是一个把组件和 style 联系在一起的一个组件库,为 React 和 ReactNative 提供一个干净,易于使用的界面,说白了就是在 js 上写 css ,移除了组件和样式的映射关系。是 style 的另一种思想,简单的举个例子来直观的感受一下吧,如下:定义了一个带有样式的 Button ,怎么样帅吧
const Button = styled.Button`
color:red;
font-size:16;
margin:1;
padding:0.5,1;
...
`
PS:其中 styled.Button 是一个标签模版函数,紧跟在后面的 `...` 是一个模版字符串,模版函数和模版字符串都是 ES6 的语法,如果不清楚的可以查看 ES6 相关知识
二、styled-components 的使用
这里我们以 RN 举例子来说明,React 使用套路是一样的
1、在指定目录下创建一个 RN 项目
react-native init styleComponent
2、安装 styled-components
npm install --save styled-components 或 yarn add styled-components
我们看一下 package.json 中已经成功添加了 styled-components 并且版本是 2.2.0
3、新建 app 目录,并且新建 main.js,并将 main.js 添加到时 index.android.js 和 index.ios.js 中
修改 index.android.js 和 index.ios.js 核心代码
4、在 app 目录中新建 inlineStyle.js 和 StyleComponent.js 文件
- 我们使用传统的 rn 样式方法来创建一个背景为红色,并且字为红色的按钮,如下:
# inlineStyle.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
} from 'react-native';
/**
* @author TigerChain
* 普通的内联样式的组件
* @type {Object}
*/
export default class InlineStyle extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.inlineText}>I'm the InlineStyle button</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor:'red',
height:40,
justifyContent:'center',
alignItems:'center'
},
inlineText:{
color:'yellow',
fontSize:18
}
});
- 2、定义 StyleComponent.js
# StyleComponent.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
} from 'react-native';
import styled from 'styled-components/native'
/**
* @author TigerChain
* 使用 styled-components 声明组件
* @type {Object}
*/
const StyledView = styled.View`
background-color: red;
height: 40;
justify-content:center;
align-items: center;
`
const StyleText = styled.Text`
color: yellow;
font-size: 18;
`
const StyleComponent = (props)=>(
<StyledView>
<StyleText>styled-components 声明的 Button</StyleText>
</StyledView >
)
module.exports = StyleComponent
style-components 格式
我们可以看到使用 styled-components 来编写样式组件的格式是
const CustomView = styled.XXX`
样式
`
其中 XXX 就是 RN 中的组件,比如 Text,View,Button 等
PS:使用 styled-components 要先引入这个库
import styled from 'styled-components/native'
我们来对比一下两种方式吧
把两个组件组合到 main.js 中
两种方式写的生成的一个相同的组件最后运行效果如下:
经过以上代码,我们简单的了解了一下 styled-components 是个什么鸟,并且如何使用,下面我们来说一些高级用法吧
三、styled-components 的高级用法
1、传递属性「定制组件」
- 1、我们先看一个 React 的例子吧「注意这里说的是 React 」
假如我们想要定义按钮的样式,分别为大、小,我们会这样做,新建一个 css 文件
css 文件
.button{
background:red;
border-radius: 8px;
color: yellow;
}
.large{
height:60px;
width:180px;
}
.small{
height:40px;
width:100px;
}
js 文件
class CustomButton extends React.Component {
render() {
return (
<div>
<button className="small">按钮</button>
<button className="large">按钮</button>
</div>
)
}
}
我们想在 rn 使用 styled-components 实现以上类似的功能如何办呢?传递 props 就派上用场了,废话不多说,直接上代码
- 2、使用 styled-components 完成上面的按钮组件
修改 styleComponent.js,并声明一个可指定大小的按钮组件
const CustomButton = styled.View`
background-color: ${props => props.red?'red':blue};
border-radius: 8;
margin-top: 10;
justify-content: center;
align-items: center;
height: ${props => props.small?40:60};
width:${props => props.small?100:180}
`
然后引用即可
<CustomButton small red>
<StyleText >TigerChain</StyleText>
</CustomButton>
2、对任何组件进行样式化
我们项目中有时会用三方组件,我们想必变三方组件的样式,styles-components 也是完美支持的,看核心代码
// 定义可被任意样式的组件 熟悉 props 的都知道这里的 children是啥意思,style 就不用说了
const CustomText = ({style,children}) =>(
//这里还可以是任意三方组件
<Text style={style}>
{children}
</Text>
)
// 给上面的组件添加样式
const StyledText2 = styled(CustomText)`
color: palevioletred;
font-weight: bold;
font-size: 18;
`;
使用方式
<CustomText>TigerChain</CustomText>
<StyledText2>给 TigerChain 添加样式</StyledText2>
运行查看结果:
大体一个过程如下:
3、样式继承
- 格式:
const CustomComponent = styled.Component`
样式
`
const MyComponent = CustomComponent.extend`
扩展样式或重写样式
...
`
- 在 styleComponent.js 中添加自定义样式扩展组件
//定义可继承的组件
const MyCusTomText = styled.Text`
color: red;
margin-top: 8;
`
//扩展组件
const ExtendText = MyCusTomText.extend`
font-size:25;
font-weight:bold;
`
- 使用
<MyCusTomText>自定义文本</MyCusTomText>
<ExtendText>扩展文本</ExtendText>
- 运行查看结果
4、附加 props 使用 .attrs 构造函数
在 .attrs 构造函数中,我们可以声明静态 props ,动态 props ,目的是为了避免传递不必要的属性
- 格式:
const MyView = styled.View.attrs({
...
xxx:props => props.yyy
...
})`
xxx:${props => props.xxx}
`
- 以上格式看起来比较模糊,我们通过代码来感受一下
// 使用 .atrr 来添加额外的 props
const AtrrView = styled.View.attrs({
//声明一些 props 属性
height:props => props.height || 40,
background:props => props.bgcolor || 'red',
})`
border-radius:5;
height:${props => props.height}
background-color:${props => props.background}
justify-content:center;
align-items:center;
`
使用并查看结果
<AtrrView bgcolor='orange' height='80'>
<Text>
我是 .attrs 属性
</Text>
</AtrrView>
结果如下:
过程分析
总结:
经过以上我们对 styled-componets 有了一个大体的认识和了解,styled-components 还支持动画等,具体可以去官网查看,总结 styled-componentd 有以下特点
- 是 css in js 的一种实现方式
- 移除了样式和组件的映射关系
- 使用组件看起来更清晰
- 使样式组件和逻辑组件更好的区分开,使得两种组件解耦
- 与传统单一职责相比,styled-components 就相当于富二代,与生俱来就可以写一个 style 的组件「传统的推崇 html css js 等都要分开」
这个玩意开始写的时候人很别扭「特别对于喜欢 js css html 分离的人」,但是写着写着就有一种巴黎欧莱雅的感觉---你值得拥有
三、性能对比
既然 styled-components 让组件拥有完整的功能,并且是目前前端变化的趋势,那么我们到底该不该使用 styled-components 呢?说到这里估计有人要骂笔者了「我靠,我都照着你说的的代码撸了一遍了,你居然这样说...」。我只想说年轻人,稍安勿躁
一个组件不光是好用就是我们要选择的理由,我们还要考虑性能、组件对包大小的影响,兼容性的影响等等,这里我们对比一下 styled-components 和传统的 in-line css 的性能
开始撸码
在上面 demo 的基本上添加代码,在这里我们要统计一代码的执行时间,所以安装一个依赖库 react-native-console-time-polyfill
yarn add react-native-console-time-polyfill
- 1、在 app 目录中新建 StyledComponentsPerformance.js
/* @flow weak */
import React, { Component} from 'react';
import {
View,
Text,
StyleSheet,
ListView
} from 'react-native';
import styled from 'styled-components/native'
import 'react-native-console-time-polyfill'
import data from './Data'
const ListItemView = styled.View`
padding-top: 5;
padding-bottom: 5;
border-bottom-width: 1;
border-bottom-color: red;
`;
const ListItemText = styled.Text`
color:red;
font-size: 18;
`;
const ScrollViewStyled = styled.ScrollView`
`;
const ListViewStyled = styled.ListView`
`;
/**
* 样式组件性能测试
* @type {ListView}
*/
export default class StyleComponentPerformance extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
dataSource: ds.cloneWithRows(data),
};
}
componentWillMount() {
console.log(`ListView - 渲染 ${data.length} 个组件`);
console.time('styled-components');
}
componentDidMount() {
console.timeEnd('styled-components');
}
renderRow = (row) =>(
<ListItemView><ListItemText>{row.name}</ListItemText></ListItemView>
)
renderListView() {
return (
<ListViewStyled
dataSource={this.state.dataSource}
renderRow={this.renderRow}
enableEmptySections={true}
/>
);
}
renderScrollView() {
return (
<ScrollViewStyled>
{data.map((row, index) => <ListItemView key={index}><ListItemText>{row.name}</ListItemText></ListItemView>)}
</ScrollViewStyled>
);
}
render() {
return this.renderListView();
// return this.renderScrollView();
}
}
- 2、在 app 中目录中新建 InlineStylePerformance.js
/* @flow weak */
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
ListView,
ScrollView
} from 'react-native';
import 'react-native-console-time-polyfill'
import data from './Data'
/**
* inLine style 性能测试
* @type {ListView}
*/
export default class InlineStylePerformance extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
dataSource: ds.cloneWithRows(data),
};
}
componentWillMount() {
console.log(`ListView - 渲染 ${data.length} 个组件`);
console.time('inline-style');
}
componentDidMount() {
console.timeEnd('inline-style');
}
renderRow = (row) =>(
<View style={styles.ListItemView}><Text style={styles.textStyle}>{row.name}</Text></View>
)
renderListView() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
enableEmptySections={true}
/>
);
}
renderScrollView() {
return (
<ScrollView>
{data.map((row, index) => (
<View style={styles.ListItemView} key={index}><Text style={styles.textStyle}>{row.name}</Text></View>
))}
</ScrollView>
);
}
render() {
return this.renderListView();
// return this.renderScrollView();
}
}
const styles = StyleSheet.create({
ListItemView: {
paddingTop: 5,
paddingBottom: 5,
borderBottomWidth: 1,
borderBottomColor: 'red',
},
textStyle:{
fontSize:18,
color:'red',
}
});
- 3、新建 Data.js
const data = []
for(let i=0;i<2000;i++){
data.push({name:`测试 === ${i}`})
}
export default data
- 4、测试,在 main.js 引入即可
在这里我们在模拟器或是真机上开启远程 debug 调试,然后打开 chrome 调试就可以看到 console 打出的 log 了
打开 chrome 调试工具
经过五次对比,得出以下结果
结论
- 由于我们是开启远程调试工具,所以和网络也有关系,得出的结论不一定是最准确的
- 但是也说明了一些问题 styled-components 目前的版本来说「2.2.0」性还是比 in-line 样式的性能稍有点差,
- styled-components 完全可以使用在项目中,并且相信以后的版本会逐渐缩小和 in-line 样式的性能的微小差距
到此为止,我们就介绍完了 styled-components 的用法和性能比较,快上手试试吧
最近开了公号,以后文章内容第一时间会发在公号中,希望大家关注,扫描以下二维码即可关注
据说每一个勤奋努力想成为非常牛 B 的人都会点个喜欢或转发的