1. 程式人生 > >ReactNative製作Component控制元件並且複用(二)

ReactNative製作Component控制元件並且複用(二)

上一篇部落格ReactNative製作Component控制元件並且複用(一)簡單介紹了一下如何定義一個可複用的控制元件,並且引用他。這篇部落格繼續上一篇,介紹怎樣在使用自定義控制元件的時候傳遞資料,設定樣式等一些問題。OK 開始吧:

上一篇部落格中我們製作了一個長得還算過得去的Button:

接著提出了這樣一個疑問:不可能我所有的按鈕都叫確認、背景顏色都是綠色、文字都是白色、都長這個體型……吧……

當然了,這個時候第一個想到的就是給他設定樣式!好,那接下來寫一個style並且設定給button:[index.android.js]

先加一個叫button的樣式,暫時就先改個背景顏色吧:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#f00',//紅色背景
  }
});

接下來給Button設定style:

    return (
      <View 
        style = { styles.container }>
       {/*通過import引入了Button控制元件後,就可以像下面這樣直接使用這個控制元件*/}
        <Button
          style = { styles.button }>
        </Button>
      </View>
    );

這樣是不是就給Button換了一下背景顏色呢?先看一下吧,double r:

我去,怎麼沒變化呀?那我設定寬高等其他屬性再試試!(你儘管試,能起作用算我輸)

那麼,這個按鈕的樣式到底要怎麼控制呢?還記得在【Button.js】中寫的樣式嗎?來回顧一下:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  TouchableOpacity,
} from 'react-native';

export default class Button extends Component {
  render() {
    return (
        <TouchableOpacity 
          style={styles.button}>
          <Text 
            style={ styles.btText }> 
            {"確認"} 
          </Text>
        </TouchableOpacity>
    );
  }
}

const styles = StyleSheet.create({
  button: {
    height: 30,
    width: 200,
    backgroundColor: '#0f0',
    borderRadius: 10,
    justifyContent: 'center',
    alignItems: 'center',
  },
  btText: {
    color: '#fff',
    fontSize: 16,
  },
});

看見了吧,按鈕的樣式是【Button.js】裡<TouchableOpacity>的style控制的,文字的樣式在在<Text>的style控制

的!

那難道每需要一個按鈕都要新建一個【XXButon.js】來滿足不同地方的需求?當然不是啦,還記得Props(屬性)

嗎?(這裡是Props的示例)ReactNative中的Props,這個得會才能往下看噢。

既然Props可以傳遞資料,那麼我當然可以在【index.andorid.js】中通過<Button>傳遞資料!再來看一遍剛剛寫

的:

<Button
          style = { styles.button }>
        </Button>

咦,這不就是相當於給<Button>的style屬性設定了一個值(樣式物件)嗎?可是這個值在哪兒接收呢?當然是

在定義這個控制元件的地方了:【Button.js】!這樣的話,就能在【Button.js】中取到這個”styles.button”,將他設定給

<TouchableOpacity>就行了。機智!馬上來一發:【Button.js】

……
    return (
        <TouchableOpacity 
          style={this.props.style}>
          <Text 
            style={ styles.btText }> 
            {"確認"} 
          </Text>
        </TouchableOpacity>
    );
……

來,double r:

哇66666背景色成功設定!等會兒……為什麼寬高和圓角不見了??what??回頭看下程式碼,噢,原來

<TouchableOpacity>設定了style={this.props.style},而這個style從呼叫這個button的地方傳來,我們剛剛只設置

了backgroundColor,所以只有背景色一個樣式……好,那返回【index.android.js】給這個按鈕修改一下樣式:


……
  button: {
    backgroundColor: '#f00',
    width: 100,
    height: 50,
    borderRadius: 10,
  }
……

額……好吧,有點小尷尬,文字沒居中……那繼續寫樣式??我的天,這樣的話,每次使用<Button>都要寫

文字居中的程式碼?!誒,有了:給Button設定一個預設的樣式,每次引用的時候我只修改我需要修改的某幾個樣式

屬性,這樣不就OK了?【Button.js】:

        <TouchableOpacity 
          style={[styles.button,this.props.style]}>
          <Text 
            style={ styles.btText }> 
            {"確認"} 
          </Text>
        </TouchableOpacity>

發現沒,style還可以這樣賦值!賦一個樣式物件陣列!原來這樣寫的作用是取兩個樣式物件的合集,而寫在前面

的樣式物件(styles.button)的屬性,會被寫在後面的樣式物件(this.props.style)的同名屬性覆蓋,這樣說可能太抽象了,

拿這個例子來說:

styles.button(這段程式碼在【Button.js】中)是這樣的:


  button: {
    height: 30,
    width: 200,
    backgroundColor: '#0f0',
    borderRadius: 10,
    justifyContent: 'center',
    alignItems: 'center',
  }

this.props.style(這段程式碼在【index.android.js】中)是這樣的:


  button: {
    backgroundColor: '#f00',
    width: 100,
    height: 50,
    borderRadius: 10,
  }

這兩個樣式物件[合併]後應該是這樣的:


{
	height: 30,// styles.button特有
	width: 200,// styles.button特有
	backgroundColor: ‘#f00’,//兩個都有,但是值會取後面的!前者會被後者覆蓋!
borderRadius: 10,//這個其實也是被覆蓋,只是兩個都寫了10而已,你可以試試把其中任意一個10換成其他的,看看效果
	justifyContent: ‘center’,// styles.button特有
	alignItems: ‘center’// styles.button特有
}

當然了,如果是this.props.style中特有的屬性,肯定也是會出現在合併後的樣式中的,因為這還是類似於取並集,

但稍微有丟丟不一樣,因為會“覆蓋”。本例子中,this.props.style中的borderRadius其實可以不用寫,因為預設樣

式(styles.button)已經設定了!

說了這麼多,看下這樣寫的效果到底是怎麼樣的吧:double r



OK,近乎完美!

那接下來,設定文字內容和文字樣式的過程就不多說了,都是一樣的,直接甩上所有程式碼!:

(注意程式碼中多寫的onPress事件觸發的函式也是一樣通過這個方法傳遞的!可以自己分析並優化一下程式碼!)

【index.android.js】:


/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  View,
} from 'react-native';

// 注意了!!就是這句話把剛剛寫的Button.js引入使用!
// 匯入 Button 從 './component/Button'(Buton.js檔案的路徑) 
// ----最後Button不需要寫成Button.js
import Button from './component/Button';

export default class button extends Component {
  render() {

    return (
      <View 
        style = { styles.container }>
        <Button
          style = { styles.button }
          {/*通過textStyle屬性傳遞了文字內容*/}
          textStyle = { styles.txStyle }
          {/*通過text屬性傳遞了文字內容*/}
          text = {"引用設定"}
          {/*通過onPress屬性傳遞了一個彈窗函式*/}
          onPress = { () => {alert("你點選了按鈕");} }>
        </Button>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#f00',
    width: 100,
    height: 50,
  },
  txStyle: {
    color: '#00f',
    fontSize: 20,
  }
});

AppRegistry.registerComponent('button', () => button);

【Button.js】:
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  TouchableOpacity,
} from 'react-native';

// 這裡特別注意 export default 關鍵字,只有加上關鍵字才能在其他檔案引用本檔案
// 注意class Button 是大寫,與Button.js保持一致
export default class Button extends Component {
  render() {
    return (
        <TouchableOpacity 
          style={[styles.button,this.props.style]}
          // 將接收到的onPress(即this.props.onPress)設定給TouchableOpacity的onPress
          onPress={this.props.onPress}>
          <Text 
            // 設定文字樣式
            style={ [styles.btText,this.props.textStyle] }> 
            {/*設定文字內容*/}
            {this.props.text} 
          </Text>
        </TouchableOpacity>
    );
  }
}

const styles = StyleSheet.create({
  // button預設樣式
  button: {
    height: 30,
    width: 200,
    backgroundColor: '#0f0',
    borderRadius: 10,
    justifyContent: 'center',
    alignItems: 'center',
  },
  // 文字內容預設樣式
  btText: {
    color: '#fff',
    fontSize: 16,
  },
});

完成效果是這樣的: