React Native移动开发实战
上QQ阅读APP看书,第一时间看更新

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规范进行了部分修改,并增加了一些新的规范以适应开发需求。