RN中布局样式的写法

作者: 孙焱焱 | 来源:发表于2018-01-23 14:50 被阅读124次

    介绍原始写法 & 及其改进写法一

    还有比较流行的 styled-components在RN中的使用 & 及其改进写法二

    1.原写法

    /**
     * 原写法
     */
    const styles1 = StyleSheet.create({
        item1:{
            width:100,
            height:200,
            backgroundColor:'#66CCFF',
        },
        item2:{
            width:100,
            height:200,
            backgroundColor:'#66CCFF',
        },
        item3:{
            width:50,
            height:100,
            top:50,
            left:25,
            backgroundColor:'#66CCFF',
        }
    });
    console.log('styles1 :',styles1);
    

    原写法的缺点在于变量不好引入,不好体现样式间的关系,没有计算表达式等……

    2.改进写法一

    看StyleSheet.create的代码,就是直接返回一个对象

    //在react native 0.44版本中
    var StyleSheet = {
      create: function(styles) {
        return styles;
      },
    

    那就可以不限于StyleSheet.create的写法,可以比较自由的返回一个对象了,下面给出一个我的简单例子:

    
    /**
     * 换一种写法,简单引入了变量表达式
     * 虽然还是没有像iOS中 view.center / autolayout之类的写法方便
     * @returns {{}}
     */
    function styles2Creator() {
        let s = {};
        let itemWidth = 100;
        let itemHeight = 200;
        //引用常量
        s.item1 = {
            width:itemWidth,
            height:itemHeight,
            backgroundColor:'#66CCFF',
        };
        //引用其他样式的值
        s.item2 = {
            width:s.item1.width,
            height:itemHeight,
            backgroundColor:`${s.item1.backgroundColor}`,
        };
        //计算表达式 
        s.item3 = {
            width: s.item2.width / 2,
            height: s.item2.height / 2,
            top:s.item2.height / 4,
            left:s.item2.width / 4,
            backgroundColor:s.item1.backgroundColor,
        };
        //样式的继承
        s.item4 = {
            ...s.item3,
            backgroundColor:'#FF00CC',
        };
        //带参数
        s.item5 = (top) => {
            return {
                ...s.item3,
                marginTop:top,
            };      
        };
        //带参数 + 缺省值
        s.item6 = (top) => {
            return {
                ...s.item3,
                marginTop:top ? top : 10,
            };          
        }
        return s;
    }
    const style2 = styles2Creator();
    //const style2 = StyleSheet.create(styles2Creator());
    console.log('style2 :',style2);
    

    运行一下可以看到 log出来的style2和style1的属性。

    3. styled-components

    号称React 中的 CSS 最佳实践,使用行内样式,支持CSS。该第三方也也可用于RN。

    react-native init了个RN工程 写了个简单的例子:

    
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    } from 'react-native';
    //需要 `npm install --save styled-components`
    import styled from "styled-components/native";
    
    
    //这里开始styled-components 式的样式:
    //styled-components的格式为: const [自定义变量名] = styled.[相应的系统组件]`css表达式`;
    
    //普通写法 (不大写开头会报错……
    const ListContainerView = styled.View`
        width:360;
        height:280;
        background-color: #F0F2F5;
        
    `;
    
    //扩展 (backgroundColor 和 background-color都可以
    const ItemContainerView = ListContainerView.extend`
        backgroundColor: #66CCFF;
        flexDirection:row;
    `;
    
    //带参数
    const LeftImageContainerView = styled.View`
        height:${props => props.primary ? 280 : 180};;
        width:180;
        background-color: #77BB00;
    `;
    
    //然后发现一个尴尬的事就是不知道怎么扩展自定义组件 比如JDImage
    //带计算表达式
    const LeftImageHeight = 280 - 10 *2;
    const LeftImage = styled.Image`
        margin-top:10;
        margin-left:10;
        width:${180 - 10 *2};
        height:${LeftImageHeight};
        background-color: #FFFFFF;
    `;
    
    //想要获取另一个组件样式LeftImage的高度 不能直接使用 ${LeftImage.height}
    //因为 LeftImage返回的是  ƒ StyledNativeComponent()方法……
    const RightContainerView = styled.View`
        width:160;
        height:${LeftImageHeight};
        background-color: #FF00CC;
    `;
    
    
    export default class MyApp extends Component {
        render() {
            return (
                <ItemContainerView >
                    <LeftImageContainerView primary>
                        {console.log('LeftImageContainerView.style:',LeftImageContainerView)}
                        <LeftImage source={{uri:'http://static.runoob.com/images/demo/demo2.jpg'}}/>
                    </LeftImageContainerView>
                    <RightContainerView></RightContainerView>
                </ItemContainerView>
            );
        }
    
    }
    
    AppRegistry.registerComponent('MyApp', () => MyApp);
    
    

    优点:

    • react推荐的行内样式 css in js;
    • 方便前端同学的写法 可以完全使用CSS的书写习惯

    缺点和原始写法的差不多,还对本身不是前端开发的人来说带来额外的学习成本…… 所以还是不推荐……

    参考链接:

    4.改进写法二

    简单来讲 styled-components 就是生成一个带样式的组件,完全可以吸收这种写法 自己改进RN中 ,而不使用styled-components这个库

    结合 写法一 和 styled-components的想法,给出一个简单例子:

    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    } from 'react-native';
    
    //写法二
    function stylesCreator() {
        let s = {};
        let width = 360.0, height = 280.0;
        s.ListContainerView = {
            width:  width,
            height: height,
            backgroundColor: '#F0F2F5',
        };
        s.ItemContainerView = {
            width:  width,
            height: height,
            backgroundColor: '#66CCFF',
            flexDirection:'row',
        };
        console.log('s.ItemContainerView :',s.ItemContainerView);
        s.LeftImageContainerView = {
            height:height,
            width:width / 2,
            backgroundColor: '#77BB00',
        };
        s.LeftImage = {
            marginTop:10,
            marginLeft:10,
            width: 180 - 10 *2,
            height: s.LeftImageContainerView.height - 10*2,
            backgroundColor: `#FFFFFF`,
        };
    
        s.RightContainerView = {
            width: width / 2,
            height: s.LeftImage.height,
            backgroundColor: '#FF00CC',
        };
        return s;
    }
    const styles = stylesCreator();
    //const styles = StyleSheet.create(stylesCreator());
    
    //然后再结合 styled-components:
    // 模拟 styled-components API
    const styled = (Component, styler) => (props) => {
        const style = typeof styler === 'function' ? styler(props) : styler;
        return <Component {...props} style={[ style, props.style ]} />
    }
    
    // styled components
    //同样可以完成组件(带样式)的继承 const RightContainerView = styled(LeftImageContainerView,styles.RightContainerView);
    
    const ListContainerView = styled(View,styles.ListContainerView);
    const ItemContainerView = styled(View,styles.ItemContainerView);
    const LeftImageContainerView = styled(View,styles.LeftImageContainerView);
    const LeftImage = styled(Image,styles.LeftImage);
    const RightContainerView = styled(View,styles.RightContainerView);
    
    export default class MyApp extends Component {
        render() {
            return (
                <ItemContainerView >
                    <LeftImageContainerView primary>
                        {console.log('LeftImageContainerView.style:',LeftImageContainerView)}
                        <LeftImage source={{uri:'http://static.runoob.com/images/demo/demo2.jpg'}}/>
                    </LeftImageContainerView>
                    <RightContainerView></RightContainerView>
                </ItemContainerView>
            );
        }
    
    }
    
    AppRegistry.registerComponent('MyApp', () => MyApp);
    

    emmm ,无需引入第三方库 感觉好多了。缺点当然是不支持原CSS写法。

    5. react native 0.45

    在0.45版本中运行改进写法一时,你可能看到style2在控制台的输出类似为:

    //const style2 = StyleSheet.create(styles2Creator());
    
      style2 : 
    {item1: 12, item2: 13, item3: 14, item4: 15, item5: 16, …}
        item1:12
        item2:13
        item3:14
        item4:15
        item5:16
        item6:17
    __proto__:Object
    

    这是怎么肥事!我的item对象怎么变成数字了!

    别急,在0.45版本后StyleSheet代码有所改变(其实我没看具体哪个小版本改的 _(:зゝ∠)_), StyleSheet.create改成:

    //react native : 0.45.1
      create<S: Styles>(obj: S): StyleSheet<S> {
        const result: StyleSheet<S> = {};
        for (var key in obj) {
          StyleSheetValidation.validateStyle(key, obj);
          result[key] = ReactNativePropRegistry.register(obj[key]);
        }
        return result;
      },
    
    //react native0.45.1 ReactNativePropRegistry.js
    var objects = {};
    var uniqueID = 1;
    var emptyObject = {};
    
    class ReactNativePropRegistry {
      static register(object: Object): number {
        var id = ++uniqueID;
        if (__DEV__) {
          Object.freeze(object);
        }
        objects[id] = object;
        return id;
      }
    //多的就不看了……内容不多各位有兴趣自己看  
    

    通过看ReactNativePropRegistry代码,StyleSheet将样式对象储存在objects中,并返回uniqueID

    比如取回原来的item,就可以这样做:

    import ReactNativePropRegistry from '../node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativePropRegistry';
    console.log("ReactNativePropRegistry.getByID(12): ",ReactNativePropRegistry.getByID(12));
    console.log("ReactNativePropRegistry.getByID(style2. item1): ",ReactNativePropRegistry.getByID(style2. item1));
    

    就可以通过 ReactNativePropRegistry.getByID就可以取得样式对象了。这可能对于之前的改进写法造成了一点小麻烦,不过还可以用~


    其他参考阅读:

    相关文章

      网友评论

      • 孙焱焱:更新StyleSheet.create在0.45版本后的变化

      本文标题:RN中布局样式的写法

      本文链接:https://www.haomeiwen.com/subject/mtusaxtx.html