3.4 样式
前面说过,React Native和Web应用程序除了逻辑代码不同之外,样式部分是可以共享的。Github上有一个React Style项目(https://github.com/JS-next/react-style),该项目提供React Native和Web样式的共用解决方案。在React Native的样式开发中,React Native不实现CSS,而是依赖于JavaScript来为应用程序设置样式。
3.4.1 申明与操作样式
在使用React开发web应用的过程中,为了让程序的结构更加清晰,通常需要将逻辑代码和样式表分离出来,而样式通常使用CSS、SASS编写。而在React Native的开发过程中,React Native采用了完全不同的方式,它将样式带入了到JavaScript的世界,使用JavaScript对单个元素的样式进行操作即可。毋庸置疑,这种方式摒弃了CSS的样式规范,增加了代码的可读性。
为了更好地理解React Native样式的设计思想,我们需要了解传统的CSS样式规范的痛点。传统的样式表最大的问题在于维护比较困难,代码结构混乱。在传统的CSS样式规范中,CSS代码通常都在全局作用域里,如果不注意,一个组件的样式很容易影响到其他组件。如Twitter公司很流行的Bootstrap库同时引入了600多个全局变量。由于CSS并非显示的HTML元素,如果有些样式被抛弃不用,想要消除这些无用的样式就会变得非常困难。
React Native则采用了与传统的样式表截然不用的方式,它将样式引入到JavaScript中,从而保证了组件的模块化和独立化,这也是React Native开发的优势之一。
语法
样式表由选择符和声明组成,声明又由属性和值组成。简单来说,声明就是英文大括号“{}”,属性和值之间用英文冒号“:”分隔,多条申明用英文分号“; ”分隔。例如:
Style{ font-size:12px; color:red; }
3.4.2 样式分类
样式表按作用域分为:行内样式、内嵌样式、外部样式。
行内样式
从语法上来讲,行内样式是编写组件样式中最简单的方式,但代码不利于查看和维护。行内样式的写法就是将CSS代码直接写在标签中,直接设置元素的style属性。如果有多条CSS样式,也可以写在一起,中间用分号隔开。例如:
<View style={ { width: 300, height: 600, backgroundColor: 'red', } }>
内嵌样式
内嵌样式又称为对象样式,是对行内样式的一种升级写法,把CSS代码写在该文件,而不是将样式直接写在标签中。例如:
var bold={
fontWeight:'bold'
};
...
render(){
return{
<Text style={bold}>
内嵌样式
</Text>
}
}
外部样式
外部样式又称为外联样式,是指将CSS代码写在一个单独的外部文件中,然后在使用的地方导入样式文件。例如style.js:
import React from 'react'; import { StyleSheet } from 'react-native'; var style= StyleSheet.create( { fontSize: { fontSize: 20 } }); module.exports = style;
在使用样式的时候,先导入样式文件,然后再使用。例如:
import style from './styles' … <Text style={style.fontSize}> 外联样式 </Text>
3.4.3 样式使用
StyleSheet.create
在React Native官方的示例代码中,很多地方都使用StyleSheet.create来实例化样式对象。使用StyleSheet.create来创建样式有很多的优势。StyleSheet通过将样式文件转换为一个引用内部表的纯数字,来确保值是不可变和不透明的。通过将StyleSheet放在样式文件的最后,也确保了样式文件为只被创建一次,而不是每一个渲染周期都被创建。
换言之,StyleSheet.create是提供保护的语法糖,它提供了通过propTypes校验属性的能力。在样式的使用过程中,除了上面介绍的几种使用方式之外,开发者还可以对样式进行复用和拼接操作。
style属性接受对象数组:例如,使用StyleSheet.create创建一个样式数组的代码如下:
var styles = StyleSheet.create({ button: { backgroundColor: '#ffffff', borderRadius: 8 }, text: { fontSize: 20 } });
然后,通过简单的样式拼接操作即可创建一个拥有组合样式的组件。
var combination=React.createClass{
render(){
return(
<Text style={[styles.button, styles.text]}>
{拼接组件}
</Text>
);
}
});
React Native的属性不仅可以接受对象数组,还可以在对象数组的基础上接受内联样式,不过这样写出来的代码有点杂乱无章,阅读性差。例如:
var combination=React.createClass{
render(){
return(
<Text style={[styles.button, styles.text, {color:'#000000'}]}>
{内联样式拼接组件}
</Text>
);
}
});
值得注意的是,在使用数组对象样式时,如果有两个对象的样式属性相同,React Native会默认选择最后一个,并且对于空值如:(false、null和undefind)会被忽略。
除了上面的特性之外,React Native还支持条件性样式,只需要在Style中添加额外的条件语句即可。例如:
<View style={this.state.touching&&styles.highlight}/>
对比一下Web样式的做法,我们采用@extend关键字,或者在CSS中对类进行嵌套和重写。虽然使用拼接样式可以到达预期的效果,但是它是一种受限的写法,我们更多的是使用样式的导出和继承。不过拼接样式也有它的优点:它保持了逻辑的简洁性,让我们更容易查看组件的相关属性。
3.4.4 样式传递
为了能够在调用组件的时候对其子组件样式进行自定义,可以通过将样式作为参数进行传递。使用View.propTypes.style或Text.propTypes.style来确保传递的参数确实是style类型。
var List = React.createClass({ propTypes: { style: View.propTypes.style, elementStyle: View.propTypes.style, }, render: function(){ return( <View style={this.props.style}> {elements.map((element)=> <View style={[styles.element, this.props.elementStyle]} /> )} </View> ); } }); // ... in another file ... <List style={styles.list} elementStyle={styles.listElement} />
总体来说,和传统概念的CSS样式相比,React Native对传统的CSS规范进行了部分修改,并增加了一些新的规范以适应开发需求。