React-native框架(一)

一、環境的配置工作:

1.安裝Homebrew:ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2.安裝node和npm
3.安裝watchman:brew install watchman
4.安裝react native:npm install -g react-native-cli;有權限的問題,需要再命令行的開頭加上sudo( sudo npm install -g react-native-cli)。
    4.1.選擇目標路徑:cd+"目標文件夾路徑"
    4.2.初始化react-native:react-native init "項目工程的名稱"

調試命令:
    刷新操作:commond+r
    iOS開發調試上面的菜單欄:commond+d

二、react-native的代碼智能提醒

Mac下安裝
<li>將ReactNative.xml復制~/Library/Preferences/WebStorm11/templates</li>
<li>重啟 WebStrom</li>

注意事項:因為安裝的WebStrom的版本不一定一樣,所以文件的路徑WebStorm11不一致

2.1 cd+文件路徑,之后執行以下的指令:git clone https://github.com/virtoolswebplayer/ReactNative-LiveTemplate
2.2 打開終端: 輸入ls命令(查看文件的目錄)
屏幕快照 2016-09-18 下午1.22.23.png
2.3 導入文件路徑:cd ~/Library/Preferences/
2.4 找到自己安裝的WebStrom的版本:ls
屏幕快照 2016-09-18 下午1.25.44.png
2.5 導入自己安裝 WebStorm2016.2的版本路徑:cd WebStorm2016.2
2.6 查看該路徑下面的文件目錄:ls
2.7 注意這個命令之間有空格:cd ..
2.8 打開這個文件:open WebStorm2016.2
屏幕快照 2016-09-18 下午1.31.40.png
2.9 將ReactNative.xml復制options文件夾下面即可;為了保證萬無一失,在和options的文件夾下面建立一個同級的文件夾templates,里面也放一份ReactNative.xml
2.10 重啟WebStrom即可

三、react-native的常見的組件和事件

3.1 獲取屏幕的分辨率、高度、寬度
var Dimensions = requires('Dimensions');
Dimensions.get('window').width;
Dimensions.get('window').height;
Dimensions.get('window').scale;

var Dimensions = require('Dimensions');
var screenWidth = Dimensions.get('window').width;

var  Dimensions = require('Dimensions');
var {width} = Dimensions.get('window');

Cmd+R重新加載新代碼的數據
3.2 常見的一些錯誤
屏幕快照 2016-09-12 下午2.19.29.png

Raw text cannot be used outside of a <Text> tag. Not rendering string: 'keyboardType:'

解決方法1:該引入的StyleSheet沒有引入

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

解決方法2:TextInput引入屬性方式

class helloword extends Component {
render()
 {
    return (
      <View style={styles.container}>
      <TextInput style={styles.inputStyle} placeholder="TextInput" keyboardType='number-pad' clearButtonMode="while-editing"> 
//以下方式error,應該是寫道TextInput標簽里面
      {/*placeholder="TextInput"*/}  
      {/*keyboardType:{"number-pad"}*/} 
     </TextInput>
  </View>
);

}}

3.3 常用的事件
//EX5設置
var DTouchabelDemo = React.createClass({
    getInitialState(){
        return{
            //初始的狀態值
            title:'未操作' 
        }
    },
    render(){
        return(
      <View style={styles.container}>
          <TouchableOpacity activeOpacity={0.5} 
                           onPress={()=>this.activeEvent('點擊')} 
                           onPressIn={()=>this.activeEvent('按下')}  
                           onPressOut={()=>this.activeEvent('抬起')}
                           onLongPress={()=>this.activeEvent('長按')}>
            <View style={styles.textStyle}>
                  <Text>按鈕</Text>
            </View>
          </TouchableOpacity>
          <View>
              //常見的事件的狀態的標題
              <Text>{this.state.title}</Text>
          </View>
      </View>
  )
},
//當點擊按鈕
    activeEvent(event){
        this.setState({
            title:event
        })
}});
3.4 React-native組件的生命周期
React-native組件的生命周期分為三個階段:實例化階段、存在性階段和銷毀階段。Mount  Update  Unmount
1、實例化階段的函數介紹:
1)getDefaultProps()函數初始化一些默認的屬性,將固定的內容放到這個函數里面的進行賦值和初始化,在組件中可以通過this.props拿到屬性。??不可改變
2)getInitialState()函數對組件的初始狀態賦值,狀態值是可變的,通過this.state取出組件的狀態值。??使用this.state一定會調用render()方法,內部做些判斷需要不需要進行重新渲染。
3)componentWillMount()函數,相當于oc里面的viewWillAppear視圖即將出現時候調用。
4)render()函數,是一個組件里面必須要有,本質上是一個函數,并返回JSX和其他組件來組成DOM。??在render函數里面,只能通過this.props和this.state來訪問之前函數的一些數據。
5)componentDidMount()函數,是在調用render函數之后調用的函數。在組件加載成功,并被成功的渲染出來,所要執行的一些后續的一些操作(比如網絡請求和一些數據的處理)。

3.5 獲取真實的dom結點
<View ref="oneView"></View>
this.refs.oneView拿到view組件的dom結點屬性

四、組件的實戰

4.1 ScrollView組件學習
//EX6
class lianxi extends Component {
  render() {
    return ( 
       <ScrollView horizontal={true}        pagingEnabled={true}>
            {this.renderChildView()}
       </ScrollView>
   );
}
 renderChildView(){
    var allchild = [];
    var colors = ['red','yellow','blue','green','purple'];
    for(var i = 0;i < 5;i++){
        allchild.push(
          <View key={i} style={{backgroundColor:colors[i],width:414,height:200}}>
            <Text>{i}</Text>
          </View>
      );
  }
  return allchild;
}} 
4.2 輪播圖實現
導入定時器大的類庫:
1)cd+項目的路徑
2)npm i react-timer-mixin --save

輪播圖的效果圖:

輪播圖.gif

輪播圖完整代碼實現:index.ios.js

import React, { Component } from 'react';
import {  
    AppRegistry,
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    ScrollView,
    Image,
    AlertIOS
} from 'react-native';

//注冊計時器
var TimerMixin = require('react-timer-mixin');
//引入json數據
var imageData = require('./ImageData.json');
//計算屏幕的尺寸
var  Dimensions = require('Dimensions');
var {width} = Dimensions.get('window');

var TimerDemo =React.createClass({
  //注冊計時器
    mixins: [TimerMixin],
  //初始化函數,不可改變的值
    getDefaultProps(){
        return{
            duration:1000
        }
    },
  //初始化函數,可以改變的值
    getInitialState(){
        return{
            currenPage:0
        }
    },

    render(){
        return(
            <View style={styles.container}>
                <ScrollView ref="scrollView" 
                         horizontal={true}
                         showsHorizontalScrollIndicator={false}
                        pagingEnabled={true} 
                       //onMomentumScrollEnd={this.onAnimationEnd},不用加()代表會自動把ScrollView這個參數傳過去
                    //當一幀結束的時候調用
                    onMomentumScrollEnd={(e)=>this.onAnimationEnd(e)}
                    //當開始拖拽的時候調用
                    onScrollBeginDrag = {this.onScrollBeginDrag}
                    //當開始拖拽的時候調用
                    onScrollEndDrag = {this.onScrollEndDrag}
                  >
                    {this.lbt()} 
                 </ScrollView>
            {/*指示器*/}
            <View style={styles.indicatePageStyle}>
                {/*返回指示器的圓點*/} 
               {this.indicateFunction()}
            </View>
        </View>
    )},

 //輪播圖圖片的設置函數
    lbt(){
        //image的數組
        var allImage = [];
        //數據數組
        var  imgsArr = imageData.data;
        for (var i = 0; i < imgsArr.length;i++){
            var model = imgsArr[i];
            allImage.push( 
               <Image key={i} source={{uri:model.img}} style={{width: width, height: 200}}/>
            ) 
       } 
     return allImage;
    },

//圓點指示符返回函數
    indicateFunction(){
        var indicateArr = [];
        var style;
        for (var i = 0; i < imageData.data.length;i++){
           //三目運算符,注意不能放到這個數組的內部----自己犯的錯誤
            style = (i==this.state.currenPage) ? {color:'red'} : {color:'#ffffff'};
            indicateArr.push(
                // 一定要加;
                <Text key={i} style={[{fontSize:25}, style]}>?</Text>
            )
        } 
       return indicateArr;
    },

//當每一幀滾動結束的時候調用函數
    onAnimationEnd(e){
        //水平方向的偏移量
         var offSet = e.nativeEvent.contentOffset.x;
        //計算當前的頁數
        var currenPage = Math.floor(offSet / width);
        console.log(currenPage);
      //更新當前的狀態機,重繪UI
        this.setState({
           currenPage:currenPage
        });
    },

//頁面加載完成之后調用的方法
    componentDidMount(){
        //開啟定時器
        this.startTimer();
    },

//加載完頁面調用的方法函數
    startTimer(){
        //1.拿到scrollview
        var scrollview = this.refs.scrollView;
        var imageCount = imageData.data.length;
        //2.添加定時器
        this.timer = this.setInterval(function(){
        var activePage = 0;
        //越界處理:注意自己犯的錯誤this.state.currenPage寫成this.state.currentPage,current單詞寫錯
        if((this.state.currenPage+1) >= imageCount){
            activePage = 0;
            // AlertIOS.alert('越界處理');
        }else {
            activePage = this.state.currenPage+1;
        }
        //更新狀態機
        this.setState({
             currenPage:activePage
        });
        //讓圖片滾動起來
        var offsetPicture = activePage* width;
        scrollview.scrollResponderScrollTo({x:offsetPicture,y:0,animated:true});
        },this.props.duration)
    },

//開始拖拽時調用
    onScrollBeginDrag(){
         this.clearInterval(this.timer);
      }, 
//結束拖拽時調用
    onScrollEndDrag()    {
        this.startTimer();
    }

});


//樣式設置
const styles = StyleSheet.create({
container:{
    marginTop:30
},
indicatePageStyle:{
    width:width,
    height:25,
    backgroundColor:'rgba(0,0,0,0.3)',
    position:'absolute',
    bottom:0,
    // 確定主軸的方向
    flexDirection:'row', 
   //側軸居中顯示,alignItems不是alignItem
    alignItems:'center'
    },
});

  AppRegistry.registerComponent('lianxi', () => TimerDemo);

遇到的問題:
1.這邊是從json文件中拿到的數據,將image的圖片的信息放到xcode的工程里面,將json文件放到webstorm工程里面;
2.低級錯誤?
    1-1問題:Can't find variable: Image; 
    處理方法:因為Image的組件沒有引入到工程里面;
 3.錯誤
   因為判斷條件的字母拼寫錯誤,導致這個條件一直不走,??.(this.state.currenPage寫成this.state.currentPage,current單詞寫錯)
4.3 ListView基本方式實戰

1.ListView相當于oc里面的tableView,添加了點擊事件, 效果圖如下:

listview.gif

2.代碼展示

//導入json數據
var Wine = require('./Wine.json');
//獲取屏幕的尺寸
var Dimensions = require('Dimensions');
var {width} = Dimensions.get('window');
var GListViewDemo = React.createClass({
    // 設置初始值
    getInitialState(){ 
       // 1.1 設置數據源
        var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        // 1.2 設置返回數據
        return{ 
     // cloneWithRows 放置數組   
           dataSource: ds.cloneWithRows(Wine) 
     }},

    // 設置render函數
    render(){
       return( 
           <ListView
              // 數據源
                dataSource={this.state.dataSource}  
                renderRow={this.renderRow} 
           />
         );
      },

    //逐條解析數據函數
    renderRow(rowData,sectionID,rowID,highlightRow){
        //逐條解析數據:注意的是這個模型的數據必須發要返回出來
        return(
            <TouchableOpacity activeOpacity={0.3} onPress={() => {AlertIOS.alert('第'+rowID+'行')}}>
               <View style={styles.modelStyle}> 
                 {/*左邊的圖片*/}
                  <Image style={styles.imgStyle} source={{uri:rowData.image}}/> 
                 {/*右邊的文字*/}
                  <View style={styles.rightTextStyle}>
                      <Text style={styles.topTextStyle}>{rowData.name}</Text>                
                      <Text style={styles.bottomTextStyle}>${rowData.money} </Text>
                  </View>
              </View>
            </TouchableOpacity>
      )}
});

//樣式的設置
const styles = StyleSheet.create({
  modelStyle:{
    marginTop:10,
    width:width,
    height:100,
    // 下劃線
    borderBottomWidth:1.5,
    borderBottomColor:'#e8e8e8',
    // 確定主軸的方向
    flexDirection:'row'
  }, 
 imgStyle:{
    marginTop:20,
    width: 60,
    height:60
  }, 
 rightTextStyle:{
    marginLeft:20,
    // 主軸的對齊方式
    justifyContent:'center'
  },
  topTextStyle:{
    width:0.7*width
  },
  bottomTextStyle:{
    fontSize:15,
    marginTop:30
  }
});

遇到的問題:1)render函數里面的return(),而不是return{}
          2)renderRow函數必須要把cell的模型的控件返回出來
          3)下劃線的設置:borderBottomWidth和borderBottomColor
4.4 ListView九宮格實戰

效果圖:

屏幕快照 2016-09-24 下午4.21.54.png

代碼:

// 導入json數據
var share = require('./shareData.json');
//獲取屏幕的尺寸
var Dimensions = require('Dimensions');
var {width} = Dimensions.get('window');
var  count = 3;
var cellWidth = 100;
var marginX = (width-count*cellWidth) / (count+1);
var GListViewDemo = React.createClass({
    // 設置初始值
    getInitialState(){
        // 1.1 設置數據源
        var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        // 1.2 設置返回數據
        return{
            dataSource: ds.cloneWithRows(share.data)  // cloneWithRows 放置數組
        }
    },

    // 設置render函數:利用jsx語法對頁面進行渲染
    render(){
        return(
            <ListView            
                 dataSource={this.state.dataSource}  // 數據源
                 renderRow={this.renderRow}
                 contentContainerStyle={styles.listViewStyle}
                  //??要加上這行代碼,才會自動換行布局      
                 removeClippedSubviews={false}
             >
            </ListView>
        );
    },

    //cell模型UI布局:逐條解析數據:注意的是這個模型的數據必須發要返回出來
    renderRow(rowData){ 
        return(
           <TouchableOpacity activeOpacity={0.5} onPress={() => {AlertIOS.alert('hh')}}>
              <View style={styles.cellBackStyle}>
                  <Image source={{uri: rowData.icon}} style={{width:80,                height:80}} />
                  <Text>{rowData.title}</Text>
              </View>
          </TouchableOpacity>
       )}
});

    //樣式設置
    const styles = StyleSheet.create({ 
       listViewStyle:{ 
           //設置橫向布局
            flexDirection:'row',
            //設置換行顯示
            flexWrap:'wrap', 
         height:100
        },
        cellBackStyle:{ 
           width:cellWidth,
            height:cellWidth,
            marginLeft:marginX, 
           marginTop:30, 
           alignItems:'center'//居中顯示
        }
    });

遇到的問題:

圖1
圖2
圖3
1.圖1問題是因為沒有設置換行屬性:flexWrap:'wrap'
2.圖2問題:設置了整體的布局方向和換行屬性之后還是不行;解決:removeClippedSubviews={false},當超出畫面以外的子視圖,這個屬性默認是true隱藏,即子視圖不會出現到父視圖上面(不會出現)。
3.圖3問題:一行的cell占了超過自身的高度,設置一下listview高度即可(??設置的是listViewStyle的樣式中設置height屬性)。
4.5 ListView分組實戰

效果圖:

圖1
圖2

代碼:

// 導入json數據
var cars = require('./Car.json');
var ListViewDemo3 = React.createClass({

    //初始化函數
 getInitialState(){
    var getSectionData = (dataBlob,sectionID) =>{ 
       return dataBlob[sectionID]; 
     };
    var getRowData = (dataBlob,sectionID,rowID) =>{
        return dataBlob[sectionID+':'+rowID];
    };
    return{ 
       dataSource:new ListView.DataSource({
            getSectionData:getSectionData, 
            getRowData:getRowData, 
           rowHasChanged:(r1,r2) => r1 !== r2,
            sectionHeaderHasChanged:(s1,s2)  => s1 !== s2
        })
    }},


    //頁面加載完之后調用的方法
    componentDidMount(){
        this.jsonDataFunction();
    },

    //數據加載處理函數
    jsonDataFunction(){
        //json的所有數據
        var jsonArray = cars.data;
        //定義變量存放區標號,行標號,區標題,所有的汽車的品牌信息
        var sectionIDs = [], 
            rowIDs = [],
            dataBlob = {},
            carsArray = [];
        for(var i = 0; i < jsonArray.length;i ++){
              //區號
              sectionIDs.push(i);
              //區標題
              dataBlob[i] = jsonArray[i].title;
              //所有的汽車的品牌信息
              carsArray = jsonArray[i].cars;
              //相當于聲明一個二維數組,??這句 
              rowIDs[i] = [];
             for(var j = 0; j < carsArray.length; j++){
                  rowIDs[i].push(j);
                //把每一行的汽車信息放入到數組中
                dataBlob[i + ':' + j] = carsArray[j];
            }
          }

    //更新狀態機:??更新狀態的函數為setState,而不是state 
       this.setState({
             dataSource:this.state.dataSource.cloneWithRowsAndSections(dataBlob,sectionIDs,rowIDs)
        });
  },

//數據UI的喧染
 render(){
    return( 
       <View style={styles.pageStyle}>
            {/*頭部的標題樣式*/}
            <View style={styles.titlePageStyle}>
                <Text style={styles.textPageStyle}>cjw之分組listView學習</Text>
            </View>
            {/*listView數據*/}
            <ListView
                //dataSource:this.state.dataSource這一種寫的方式會導致語法報錯
                dataSource={this.state.dataSource}
                renderRow={this.renderRow}
                renderSectionHeader={this.renderSectionHeader}
            />
        </View>
    );
},


//每一行數據解析布局
 renderRow(rowData){
    return( 
       <TouchableOpacity activeOpacity={0.5} onPress={()=>AlertIOS.alert('r')}>
            <View style={styles.rowListViewPageStyle}>
                <Image source={{uri:rowData.icon}} style={styles.rowImageStyle}/>
                <Text style={styles.rowTextStyle}>{rowData.name}</Text>
            </View>
        </TouchableOpacity>
  )},

//區標題的數據布局
renderSectionHeader(sectionData,sectionID){
    return(
        <TouchableOpacity activeOpacity={0.5} onPress={()=>AlertIOS.alert('h')}>
            <View style={styles.headerViewStyle}>
                <Text style={styles.headerTextStyle}>{sectionData}</Text>
            </View>
        </TouchableOpacity>
    );
}


//樣式布局設置
const styles = StyleSheet.create({
    pageStyle:{
        flex:1
    },
    titlePageStyle:{
        height:60,
        alignItems:'center',
        padding:20
    },
    textPageStyle:{
      fontSize:18
    },
    rowListViewPageStyle:{
        flexDirection:'row'
    },
    rowImageStyle:{
        width:60,
        height:60
    },
    rowTextStyle:{
        padding:20
    },
    headerViewStyle:{
        height:40,
        backgroundColor:'orange',
        justifyContent:'center'
    },
    headerTextStyle:{
        fontSize:18
    }
});

知識點補充和遇到的問題

1)知識點補充
//設置主軸的方向
flexDirection:'row'
//側軸方向居中
 alignItems:'center'
 //主軸方向居中
justifyContent:'center'
2)遇到的問題
    2-1//dataSource:this.state.dataSource這一種寫的方式會導致語法報錯
    //正確的寫法:
    dataSource={this.state.dataSource}

    2-2布局完成之后設置的listView的視圖,并不能滾動起來
    解決方法:最外面的view視圖里面設置一個布滿全屏的屬性flex:1
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容