一、环境的配置工作:
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命令(查看文件的目录)
2.3 导入文件路径:cd ~/Library/Preferences/
2.4 找到自己安装的WebStrom的版本:ls
2.5 导入自己安装 WebStorm2016.2的版本路径:cd WebStorm2016.2
2.6 查看该路径下面的文件目录:ls
2.7 注意这个命令之间有空格:cd ..
2.8 打开这个文件:open WebStorm2016.2
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 常见的一些错误
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
轮播图的效果图:
轮播图完整代码实现: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,添加了点击事件, 效果图如下:
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九宫格实战
效果图:
代码:
// 导入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.图1问题是因为没有设置换行属性:flexWrap:'wrap'
2.图2问题:设置了整体的布局方向和换行属性之后还是不行;解决:removeClippedSubviews={false},当超出画面以外的子视图,这个属性默认是true隐藏,即子视图不会出现到父视图上面(不会出现)。
3.图3问题:一行的cell占了超过自身的高度,设置一下listview高度即可(⚠️设置的是listViewStyle的样式中设置height属性)。
4.5 ListView分组实战
效果图:
代码:
// 导入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