- 創(chuàng)建指定RN版本的工程
react-native init MyApp --version 0.44.3。注意版本號必須精確到兩個小數(shù)點。
- 倒計時 (系統(tǒng)自帶的)
//定時器: 隔2s切換到Main
setTimeout( ()=>{
//頁面的切換
this.props.navigator.replace({
component:Main, //具體路由的版塊
});
} ,2000);
- 按鈕 Switch的狀態(tài)切換
//!this.state.isOn 取反,切換狀態(tài)
// onValueChange={()=>{this.setState({isOn:!this.state.isOn})}}
<Switch value={this.state.isOn === true} onValueChange={()=>{this.setState({isOn:!this.state.isOn})}} style={{marginRight:8}}/>
- ScrollView的吸頂效果
<ScrollView
style={styles.scrollViewStyle}
contentInset={{top:-200}}
contentOffset = {{y:200}}
>
</ScrollView>
- 遍歷時,控件一定要加
key={i}
//頁碼指示器
renderIndicator(){
//指示器數(shù)組
var indicatorArr = [], style;
//遍歷創(chuàng)建組件
for (var i=0;i<2;i++){
//設(shè)置圓點樣式
style = (i === this.state.activePage) ? {color:'orange'} : {color:'gray'}
indicatorArr.push(
// 一個數(shù)組里面有多個樣式
<Text key={i} style={[style,{fontSize:30}]}>?</Text>
);
}
return indicatorArr;
}
- 用ListView實現(xiàn)九宮格布局
通常情況下,我們對ListView的操作是縱向的据途,如果是橫向的姐仅,則需要設(shè)置ListView的contentContainerStyle屬性巡社,添加flexDirection:‘row’讓多個ListView在同一行顯示山橄,而且通過flexWrap:'wrap'進行換行怀各。
contentViewStyle:{
//設(shè)置主軸的方向
flexDirection:'row',
//多個cell在同一行顯示
flexWrap:'wrap',
//寬度
width:Dimensions.get('window'),
},
全局變量
var {width} = Dimensions.get('window');
//全局的變量
var cols = 5;
var cellW = Platform.OS == 'ios' ? 70 : 50;
var cellH = 70;
var vMargin = (width-cellW*cols) / (cols + 1);
渲染
render(){
return(
<ListView
dataSource = {this.state.dataSource}
renderRow = {this._renderRow}
contentContainerStyle = {styles.contentViewStyle}
scrollEnabled = {false}
/>
);
},
樣式
const styles = StyleSheet.create({
contentViewStyle:{
//設(shè)置主軸的方向
flexDirection:'row',
//多個cell在同一行顯示
flexWrap:'wrap',
//寬度
width:width,
},
cellStyle:{
width:cellW,
height:cellH,
justifyContent:'center',
alignItems:'center',
marginTop:10,
marginLeft:vMargin,
},
titleStyle:{
color:'gray',
fontSize:Platform.OS == 'ios' ? 14: 10
}
});
效果
-
替換字符串的內(nèi)容
下面的圖片url中,包含有/w.h/字符,需要前端傳遞給后臺具體的尺寸,然后返回對應(yīng)尺寸的圖片
"imageurl": "http://p0.meituan.net/w.h/groupop/b8fb2def2c0063c9acabed6cbf1c65449452.png"
js中的做法
//處理圖像的尺寸
dealWithImgUrl(url){
//url.search('w.h') 如果找到,則返回正數(shù);沒有找到,則返回 -1;
if (url.search('w.h') == -1){
//沒有找到, 正常返回
return url;
}else {
//把'w.h'替換成具體的尺寸
return url.replace('w.h',64.43);
}
}
-
對象序列化: JSON.stringify(result)
var result = {'name':'張三','age':'25'}
//對象序列化
JSON.stringify(result)
-
解析一個JSON字符串 : JSON.parse()
resolve(JSON.parse(result));
一般用作AsyncStorage等獲取的是json字符串格式的數(shù)據(jù),需要轉(zhuǎn)換成Json格式
一般用作fetch
數(shù)據(jù)請求中
post(url, data) {
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
//將傳遞過來的參數(shù)對象序列化
body: JSON.stringify(data)
})
.then(response=>response.json())
.then(result=> {
this.setState({
//轉(zhuǎn)換成了json字符串格式,在實際開發(fā)中不用轉(zhuǎn),直接可以用
//該界面主要用作通過<Text>標(biāo)簽把請求結(jié)果顯示出來
result: JSON.stringify(result)
})
})
.catch(error=> {
this.setState({
result: JSON.stringify(error)
})
})
}
-
設(shè)置陰影
elevation number(限Android)使用Android原生的 elevation API來設(shè)置視圖的高度(elevation)频伤。這樣可以為視圖添加一個投影恳谎,并且會影響視圖層疊的順序。此屬性僅支持Android5.0及以上版本憋肖。
//陰影安卓和iOS有別:
//IOS
shadowColor:'red',
shadowOffset:{width:1,height:1},
shadowOpacity:0.4,
shadowRadius:1,
//安卓
elevation:2,
-
try catch 拋出異常
fetch(){
return new Promise((resolve,reject)=>{
AsyncStorage.getItem(this.flag,(error,result)=>{
if (error){
reject(error);
}else {
if (result){
//解析有可能會出錯,拋出異常
try {
//轉(zhuǎn)成JSON格式
resolve(JSON.parse(result));
} catch (e){
//出錯
reject(e);
}
}
}
})
})
}
-
使用map遍歷
this.state.languages.map((result,i,array)=>{
let lan = array[i];
return lan.checked ? <PopularTab tabLabel={lan.name}>{lan.name}</PopularTab> : null;
})
-
獲取數(shù)組中元素的索引
let index = this.dataArray.indexOf(item);
-
DeviceEventEmitter 事件兒發(fā)射器]
添加通知
componentDidMount(){
this.listener=DeviceEventEmitter.addListener('showToast',(text)=>{
this.toast.show(text,DURATION.LENGTH_LONG);
});
}
移除通知
componentWillUnmount(){
this.listener&&this.listener.remove();
}
發(fā)送通知 (在需要發(fā)送通知的地方發(fā)送通知)
DeviceEventEmitter.emit('showToast','顯示緩存數(shù)據(jù)');
-
TextInput 注意
默認給TextInput設(shè)置要顯示的內(nèi)容,如果設(shè)置value='xxx',會導(dǎo)致輸入框無法輸入!
<TextInput
style={styles.input}
value={URL}
onChangeText={text=>this.text=text}
/>
應(yīng)設(shè)置defaultValue='xxx',這樣就可以正常輸入了
<TextInput
style={styles.input}
defaultValue={URL}
onChangeText={text=>this.text=text}
/>
-
react-native-htmlview的使用
//用p標(biāo)簽包括以下,也可以換用別的標(biāo)簽
let description = '<p>'+this.props.data.description+'</p>';
<HTMLView
value={description}
stylesheet={{ //設(shè)置標(biāo)簽的樣式
p:styles.description,
a:styles.description,
}}
onLinkPress={(url) => {}}
/>
const styles = StyleSheet.create({
description:{
fontSize:14,
marginBottom:2,
color:'#757575',
},
})
-
ES6和ES5的不一樣
export default class CustomKeyPage extends Component {
constructor(props) {
super(props);
//可以往里面存東西,但是不會觸發(fā)更細狀態(tài)機
this.changeValues = [];
//會觸發(fā)更新狀態(tài)機
this.state={
dataArray:[],
}
}
}
-
報錯: React.Children.only expected to receive a single React element child.
則需要用View把這些組件包裹起來
<View style={{flexDirection:'row'}}>
<Image source={require('./images/ic_sort.png')}/>
<Text>{this.props.data.name}</Text>
</View>
-
undefined is not an object (evaluating 'this.props.navigator.push')
報這樣的錯誤,需要檢查下各個界面的延展屬性有木有傳!!!
-
this.setState is not a function. (In 'this.setState({ isVisible: false})', 'this.setState' is undefined)
有時候第三方插件采用的ES5的寫法,導(dǎo)致程序崩潰,先檢查方法函數(shù)是否采用的ES5,再改成ES6.
-
按鈕狀態(tài)的切換
設(shè)置this.state
this.state={
//默認未選中
isFavorite:false,
//默認圖片
favoriteIcon:require('../../res/images/ic_unstar_transparent.png'),
}
創(chuàng)建按鈕
let favoriteButton = <TouchableOpacity
onPress={()=>this.onPressFavorite()}
>
<Image
style={{width:22,height:22,tintColor:'#2196F3'}}
source={this.state.favoriteIcon}
/>
</TouchableOpacity>
按鈕點擊,狀態(tài)切換
onPressFavorite(){
this.setState({
//this.state.isFavorite狀態(tài)取反
isFavorite:!this.state.isFavorite,
//顯示圖片切換
favoriteIcon:!this.state.isFavorite ? require('../../res/images/ic_star.png'):require('../../res/images/ic_unstar_transparent.png'),
});
}
-
當(dāng)props發(fā)生變化時執(zhí)行因痛,初始化render時不執(zhí)行
當(dāng)props發(fā)生變化時執(zhí)行,初始化render時不執(zhí)行岸更,在這個回調(diào)函數(shù)里面鸵膏,你可以根據(jù)屬性的變化,通過調(diào)用this.setState()來更新你的組件狀態(tài)怎炊,舊的屬性還是可以通過this.props來獲取,這里調(diào)用更新狀態(tài)是安全的谭企,并不會觸發(fā)額外的render調(diào)用
//當(dāng)數(shù)據(jù)狀態(tài)不能及時刷新時,調(diào)用此方法
componentWillReceiveProps(nextProps){
this.setFavoriteState(nextProps.projectModel.isFavorite);
}
setFavoriteState(isFavorite){
this.setState({
isFavorite:isFavorite,
favoriteIcon:isFavorite ? require('../../res/images/ic_star.png'):require('../../res/images/ic_unstar_transparent.png'),
});
}
-
item.id.toString() 轉(zhuǎn)成字符串
-
事件的點擊等操作方法前加
on
//onPress={()=>this.onRightButtonClick()},onRightButtonClick前面加on
<TouchableOpacity
onPress={()=>this.onRightButtonClick()}
>我是按鈕</TouchableOpacity>
方法實現(xiàn)
onRightButtonClick(){
alert('我被點擊了');
}
-
multiGet ====> AsyncStorage 通過多個
key
獲取數(shù)據(jù)
//參數(shù) keys:數(shù)組
AsyncStorage.multiGet(keys,(err,stores)=>{
try {
stores.map((result,i,store)=>{
let value = store[i][1];
if (value) items.push(value);
})
resolve(items);
}catch (e){
reject(e);
}
});
-
通知的使用
監(jiān)聽頁面
//添加通知
componentDidMount() {
this.listener = DeviceEventEmitter.addListener('favoriteChanged_popular', () => {
this.isFavoriteChanged=true;
});
this.loadData();
}
//記得移除通知
componentWillUnmount(){
if (this.listener) {
this.listener.remove();
}
}
在需要發(fā)送通知的地方發(fā)送通知
DeviceEventEmitter.emit('favoriteChanged_popular');
-
定義一些常量
/**
* 定一些常量
* 更多菜單
* */
//導(dǎo)出標(biāo)識
export const MORE_MENU={
Custom_Language:'Custom Language',
Sort_Language:'Sort Language',
Custom_Key:'Custom Key',
Sort_key:'Sort Key',
Remove_Key:'Remove Key',
About_Author:'About Author',
About:'About',
}
在使用的地方這樣引入
import {MORE_MENU} from '../../common/MoreMenu'
這樣使用
//直接調(diào)用
MORE_MENU.About
//如下面示例
<TouchableHighlight
onPress={()=>this.onClick(MORE_MENU.About)}
>我是按鈕</TouchableHighlight>
-
定義全局的樣式類
代碼如下:
/**
* 全局樣式
* @flow
*/
import {
Dimensions
}from 'react-native'
const {height, width} = Dimensions.get('window');
//導(dǎo)出全局樣式
module.exports ={
line: {
height: 0.4,
opacity:0.5,
backgroundColor: 'darkgray',
},
root_container:{
flex: 1,
backgroundColor: '#f3f3f4',
},
backgroundColor: '#f3f3f4',
nav_bar_height_ios:44,
nav_bar_height_android:50,
window_height:height,
};
使用的地方,先導(dǎo)入
import GlobalStyles from '../../../res/styles/GlobalStyles'
調(diào)用方法:
<View style={GlobalStyles.line}></View>
-
公共類里面定義表示,用于區(qū)分不同的組件調(diào)用
-
Linking 打開瀏覽器、郵箱或者其它的應(yīng)用
如果想在打開鏈接前先檢查是否安裝了對應(yīng)的應(yīng)用评肆,則調(diào)用以下方法:
//以發(fā)送郵箱為例
//打開郵箱,由于模擬器上沒有安裝郵箱,故無法打開
var url='mailto://1047912930@qq.com';
Linking.canOpenURL(url).then(supported => {
if (!supported) {
console.log('Can\'t handle url: ' + url);
} else {
return Linking.openURL(url);
}
}).catch(err => console.error('An error occurred', err));
-
Map()函數(shù)
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]
具體使用如下
-
async和await用法
要理解async和await的用法债查,首先要了解Task相關(guān)知識,這里不做說明瓜挽,因為這不是本文的重點盹廷。
如果你已經(jīng)對Task很了解,那么如何使用async和await久橙,在此主要總結(jié)了以下三點:
1.只有在async方法里面才能使用await操作符俄占;
2.await操作符是針對Task對象的管怠;
3.當(dāng)方法A調(diào)用方法B,方法B方法體內(nèi)又通過await調(diào)用方法C時,如果方法C內(nèi)部有異步操作缸榄,則方法B會等待異步操作執(zhí)行完渤弛,才往下執(zhí)行;但方法A可以繼續(xù)往下執(zhí)行碰凶,不用再等待B方法執(zhí)行完。
使用如下:(省去了鏈?zhǔn)秸{(diào)用的繁瑣)
async updateFavorite(repositories){
if (repositories) this.repositories = repositories;
//等于空 直接return
if (!this.repositories) return;
if (!this.favoriteKeys){
this.favoriteKeys = await this.favoriteDao.getFavoriteKeys();
}
}
-
設(shè)置this.state要注意
constructor(props) {
super(props);
this.state={
//默認值要為數(shù)組[],或者對象{},千萬不能是null,(null會報錯)
dataSource:[],
}
}
-
StackNavigator 導(dǎo)航跳轉(zhuǎn)
const { navigate } = this.props.navigation;
//點擊調(diào)轉(zhuǎn)
onPress={() => navigate('Detail', {
//傳值
id: item.id,
//回調(diào)
callback: (data) => {
this.setState({
childState: data
})
}
})}
Detail頁面顯示
static navigationOptions = {
title: '詳情頁',
};
沒有回調(diào) => 返回
onPress={()=>this.props.navigation.goBack()}
帶有參數(shù)=>返回
const {state,goBack} = this.props.navigation;
<Text onPress={()=>{
state.params.callback('假裝是回傳的內(nèi)容');
goBack();
}}
>返回</Text>
-
AsyncStorage存儲 只能存 "死的"字符串 (json字符串)
async componentDidMount() {
const { state: { params: { id } } } = this.props.navigation;
let textData, jsonData;
//await 該函數(shù)執(zhí)行完 才能往下接著執(zhí)行
//如果使用await componentDidMount()方法前要加 async
textData = await AsyncStorage.getItem(id);
if (textData) {
// alert('數(shù)據(jù)來自本地');
} else {
const rawData = await fetch(`${api}/${id}`);
textData = await rawData.text();
// alert('數(shù)據(jù)來自服務(wù)器');
}
// title, summary
// "images": {
// "small": "http://img3.doubanio.com/view/movie_poster_cover/ipst/public/p494268647.webp",
// "large": "http://img3.doubanio.com/view/movie_poster_cover/lpst/public/p494268647.webp",
// "medium": "http://img3.doubanio.com/view/movie_poster_cover/spst/public/p494268647.webp"
// }
// 反序列化: "死的"字符串 => "活的"對象
jsonData = JSON.parse(textData);
jsonData.image = jsonData.images.large.replace('webp', 'jpg');
// 序列化: "活的"對象 => "死的"字符串
// const textData = JSON.stringify(jsonData);
AsyncStorage.setItem(id, textData);
this.setState({
data: jsonData,
ready: true,
});
this.fetchVideo(jsonData.mobile_url);
}
-
復(fù)制到剪切板
Clipboard.setString('xxx');
-
打開郵箱
Linking.openURL('mailto://1047912930@qq.com');
-
給textInput設(shè)置paddingLeft:5,輸入框的光標(biāo)就會往右移動5px的距離
textInput: {
flex: 1,
paddingLeft: 5,//輸入框的光標(biāo)就會往右移動
},
-
讓鍵盤隱藏(輸入框失去焦點)
處理方式(一):
先定義該變量 dismissKeyboard
const {width, height} = Dimensions.get('window'); // 獲取屏幕尺寸
const dismissKeyboard = require('dismissKeyboard'); // 獲取鍵盤回收方法
// 第三方
import {PullList} from 'react-native-pull';
調(diào)用
// 返回
pop() {
// 回收鍵盤
dismissKeyboard();
this.props.navigator.pop();
}
處理方式(二):
先給輸入框Input設(shè)置ref
<TextInput
ref="input"
onChangeText={text=>this.inputKeky=text} //將text賦值給this.inputKeky
style={styles.textInput}
> </TextInput>
讓輸入框失去焦點
<TouchableOpacity
onPress={()=> {
this.refs.input.blur(); //讓輸入框失去焦點
this.onRightButtonClick();
} }
>搜索 </TouchableOpacity>
-
另一種綁定ref方法
用的時候可以直接使用this.toast
調(diào)用方法
<Toast ref={toast=>this.toast = toast}/>
-
指示器ActivityIndicator的使用
//當(dāng)加載數(shù)據(jù)時顯示指示器,加載完成后關(guān)閉指示器
let listView=!this.state.isLoading?<ListView
dataSource={this.state.dataSource}
renderRow={(e)=>this.renderRow(e)}
/>:null;
let indicatorView=this.state.isLoading?
<ActivityIndicator
style={styles.centering}
size='large'//設(shè)置指示器的大小,是枚舉值
animating={this.state.isLoading}
/>:null;
let resultView=<View style={{flex:1}}>
{indicatorView}
{listView}
</View>
//樣式
centering:{
alignItems:'center',
justifyContent:'center',
flex:1, //一定要指定flex
},
-
取消網(wǎng)絡(luò)請求
就像在網(wǎng)上買東西一樣,賣家已經(jīng)發(fā)貨是無法取消訂單的,但是我們可以在快遞來的時候,選擇拒收快遞!
封裝取消網(wǎng)絡(luò)請求類
export default function makeCancelable(promise) {
//定義標(biāo)志位
let hasCanceled_=false;
const wrappedPromise=new Promise((resolve,reject)=>{
promise.then((val)=>{
hasCanceled_?reject({isCanceled:true}):resolve(val)
});
promise.catch((error)=>{
hasCanceled_?reject({isCanceled:true}):resolve(error)
})
});
//向調(diào)用者返回一個字典
return {
promise:wrappedPromise,
//返回cancel方法,并將 hasCanceled_ 置為true
cancel(){
hasCanceled_=true;
}
}
}
在使用的類里面導(dǎo)入
import makeCancelable from '../util/Cancleable'
請求數(shù)據(jù)時調(diào)用
loadData(){
this.cancelable=makeCancelable(fetch(this.genFetchUrl(this.inputKeky)));
this.cancelable.promise
.then(response=>response.json())
.then(responseData=>{
...
}).catch(e=>{
...
})
取消搜索
//在取消搜索的地方調(diào)用
this.cancelable.cancel();
-
取消網(wǎng)絡(luò)請求的應(yīng)用
當(dāng)獲取網(wǎng)絡(luò)請求的頁面,當(dāng)數(shù)據(jù)還未獲取到時,用戶選擇返回上一級界面,這時,網(wǎng)絡(luò)請求的頁面還在請求數(shù)據(jù),當(dāng)獲取到數(shù)據(jù)時,再上一級界面底部會顯示警告,這時就需要在組件Will被卸載的方法中 "調(diào)用取消網(wǎng)絡(luò)請求" .
componentWillUnmount(){
//this.cancelable 判斷this.cancelable是否為空
this.cancelable&&this.cancelable.cancel();
}
-
React-Native 支持GCD的
-
在終端中切換到
當(dāng)前文件
的某個目錄
下
比如切換到iOS文件下執(zhí)行一些操作
cd iOS /
-
屬性的聲明 propTypes
具體參考賈鵬輝自定義 NavigationBar 內(nèi)容
static propTypes = {
name: PropTypes.string,
ID: PropTypes.string.isRequired, //這個是必須的,不傳值會報警告
}
-
webView加載服務(wù)器返回的html標(biāo)簽
<WebView
```
source={{html: this.state.html, baseUrl: ''}}
```
/>
-
去除 Android 中輸入框的下劃線
那么 Android 中的 TextInput 的下劃線是不是丑爆了鹿驼?這邊我們也來處理下它欲低,直接使用 underlineColorAndroid 這個屬性,讓他為透明即可畜晰。
underlineColorAndroid={'transparent'}
-
獲取Realm的路徑
先獲取到Documents
的路徑
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSLog(@"====Realm的存儲路徑:%@",docDir);
在Documents的路徑下有一個default.realm
的文件,該文件就是Realm的文件存儲位置,可用Realm Borwser
雙擊打開
-
FlatList滾動到某一行
this.listView.scrollToIndex({viewPosition: 0, index: 0});