一、環境的配置工作:
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