RN中布局样式的写法

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

还有比较流行的 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就可以取得样式对象了。这可能对于之前的改进写法造成了一点小麻烦,不过还可以用~


其他参考阅读:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容