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阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容