- 创建指定RN版本的工程
react-native init MyApp --version 0.44.3。注意版本号必须精确到两个小数点。
- 倒计时 (系统自带的)
//定时器: 隔2s切换到Main
setTimeout( ()=>{
//页面的切换
this.props.navigator.replace({
component:Main, //具体路由的版块
});
} ,2000);
- 按钮 Switch的状态切换
//!this.state.isOn 取反,切换状态
// 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(){
//指示器数组
var indicatorArr = [], style;
//遍历创建组件
for (var i=0;i<2;i++){
//设置圆点样式
style = (i === this.state.activePage) ? {color:'orange'} : {color:'gray'}
indicatorArr.push(
// 一个数组里面有多个样式
<Text key={i} style={[style,{fontSize:30}]}>•</Text>
);
}
return indicatorArr;
}
- 用ListView实现九宫格布局
通常情况下,我们对ListView的操作是纵向的,如果是横向的,则需要设置ListView的contentContainerStyle属性,添加flexDirection:‘row’让多个ListView在同一行显示,而且通过flexWrap:'wrap'进行换行。
contentViewStyle:{
//设置主轴的方向
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:{
//设置主轴的方向
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
}
});
效果
-
替换字符串的内容
下面的图片url中,包含有/w.h/字符,需要前端传递给后台具体的尺寸,然后返回对应尺寸的图片
"imageurl": "http://p0.meituan.net/w.h/groupop/b8fb2def2c0063c9acabed6cbf1c65449452.png"
js中的做法
//处理图像的尺寸
dealWithImgUrl(url){
//url.search('w.h') 如果找到,则返回正数;没有找到,则返回 -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字符串格式的数据,需要转换成Json格式
一般用作fetch
数据请求中
post(url, data) {
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
//将传递过来的参数对象序列化
body: JSON.stringify(data)
})
.then(response=>response.json())
.then(result=> {
this.setState({
//转换成了json字符串格式,在实际开发中不用转,直接可以用
//该界面主要用作通过<Text>标签把请求结果显示出来
result: JSON.stringify(result)
})
})
.catch(error=> {
this.setState({
result: JSON.stringify(error)
})
})
}
-
设置阴影
elevation number(限Android)使用Android原生的 elevation API来设置视图的高度(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 {
//转成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;
})
-
获取数组中元素的索引
let index = this.dataArray.indexOf(item);
-
DeviceEventEmitter 事件儿发射器]
添加通知
componentDidMount(){
this.listener=DeviceEventEmitter.addListener('showToast',(text)=>{
this.toast.show(text,DURATION.LENGTH_LONG);
});
}
移除通知
componentWillUnmount(){
this.listener&&this.listener.remove();
}
发送通知 (在需要发送通知的地方发送通知)
DeviceEventEmitter.emit('showToast','显示缓存数据');
-
TextInput 注意
默认给TextInput设置要显示的内容,如果设置value='xxx',会导致输入框无法输入!
<TextInput
style={styles.input}
value={URL}
onChangeText={text=>this.text=text}
/>
应设置defaultValue='xxx',这样就可以正常输入了
<TextInput
style={styles.input}
defaultValue={URL}
onChangeText={text=>this.text=text}
/>
-
react-native-htmlview的使用
//用p标签包括以下,也可以换用别的标签
let description = '<p>'+this.props.data.description+'</p>';
<HTMLView
value={description}
stylesheet={{ //设置标签的样式
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);
//可以往里面存东西,但是不会触发更细状态机
this.changeValues = [];
//会触发更新状态机
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的写法,导致程序崩溃,先检查方法函数是否采用的ES5,再改成ES6.
-
按钮状态的切换
设置this.state
this.state={
//默认未选中
isFavorite:false,
//默认图片
favoriteIcon:require('../../res/images/ic_unstar_transparent.png'),
}
创建按钮
let favoriteButton = <TouchableOpacity
onPress={()=>this.onPressFavorite()}
>
<Image
style={{width:22,height:22,tintColor:'#2196F3'}}
source={this.state.favoriteIcon}
/>
</TouchableOpacity>
按钮点击,状态切换
onPressFavorite(){
this.setState({
//this.state.isFavorite状态取反
isFavorite:!this.state.isFavorite,
//显示图片切换
favoriteIcon:!this.state.isFavorite ? require('../../res/images/ic_star.png'):require('../../res/images/ic_unstar_transparent.png'),
});
}
-
当props发生变化时执行,初始化render时不执行
当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用
//当数据状态不能及时刷新时,调用此方法
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() 转成字符串
-
事件的点击等操作方法前加
on
//onPress={()=>this.onRightButtonClick()},onRightButtonClick前面加on
<TouchableOpacity
onPress={()=>this.onRightButtonClick()}
>我是按钮</TouchableOpacity>
方法实现
onRightButtonClick(){
alert('我被点击了');
}
-
multiGet ====> AsyncStorage 通过多个
key
获取数据
//参数 keys:数组
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);
}
});
-
通知的使用
监听页面
//添加通知
componentDidMount() {
this.listener = DeviceEventEmitter.addListener('favoriteChanged_popular', () => {
this.isFavoriteChanged=true;
});
this.loadData();
}
//记得移除通知
componentWillUnmount(){
if (this.listener) {
this.listener.remove();
}
}
在需要发送通知的地方发送通知
DeviceEventEmitter.emit('favoriteChanged_popular');
-
定义一些常量
/**
* 定一些常量
* 更多菜单
* */
//导出标识
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'
这样使用
//直接调用
MORE_MENU.About
//如下面示例
<TouchableHighlight
onPress={()=>this.onClick(MORE_MENU.About)}
>我是按钮</TouchableHighlight>
-
定义全局的样式类
代码如下:
/**
* 全局样式
* @flow
*/
import {
Dimensions
}from 'react-native'
const {height, width} = Dimensions.get('window');
//导出全局样式
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,
};
使用的地方,先导入
import GlobalStyles from '../../../res/styles/GlobalStyles'
调用方法:
<View style={GlobalStyles.line}></View>
-
公共类里面定义表示,用于区分不同的组件调用
-
Linking 打开浏览器、邮箱或者其它的应用
如果想在打开链接前先检查是否安装了对应的应用,则调用以下方法:
//以发送邮箱为例
//打开邮箱,由于模拟器上没有安装邮箱,故无法打开
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()函数
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
let arr = [...map.keys()]; // [1, 2, 3]
具体使用如下
-
async和await用法
要理解async和await的用法,首先要了解Task相关知识,这里不做说明,因为这不是本文的重点。
如果你已经对Task很了解,那么如何使用async和await,在此主要总结了以下三点:
1.只有在async方法里面才能使用await操作符;
2.await操作符是针对Task对象的;
3.当方法A调用方法B,方法B方法体内又通过await调用方法C时,如果方法C内部有异步操作,则方法B会等待异步操作执行完,才往下执行;但方法A可以继续往下执行,不用再等待B方法执行完。
使用如下:(省去了链式调用的繁琐)
async updateFavorite(repositories){
if (repositories) this.repositories = repositories;
//等于空 直接return
if (!this.repositories) return;
if (!this.favoriteKeys){
this.favoriteKeys = await this.favoriteDao.getFavoriteKeys();
}
}
-
设置this.state要注意
constructor(props) {
super(props);
this.state={
//默认值要为数组[],或者对象{},千万不能是null,(null会报错)
dataSource:[],
}
}
-
StackNavigator 导航跳转
const { navigate } = this.props.navigation;
//点击调转
onPress={() => navigate('Detail', {
//传值
id: item.id,
//回调
callback: (data) => {
this.setState({
childState: data
})
}
})}
Detail页面显示
static navigationOptions = {
title: '详情页',
};
没有回调 => 返回
onPress={()=>this.props.navigation.goBack()}
带有参数=>返回
const {state,goBack} = this.props.navigation;
<Text onPress={()=>{
state.params.callback('假装是回传的内容');
goBack();
}}
>返回</Text>
-
AsyncStorage存储 只能存 "死的"字符串 (json字符串)
async componentDidMount() {
const { state: { params: { id } } } = this.props.navigation;
let textData, jsonData;
//await 该函数执行完 才能往下接着执行
//如果使用await componentDidMount()方法前要加 async
textData = await AsyncStorage.getItem(id);
if (textData) {
// alert('数据来自本地');
} else {
const rawData = await fetch(`${api}/${id}`);
textData = await rawData.text();
// alert('数据来自服务器');
}
// 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);
}
-
复制到剪切板
Clipboard.setString('xxx');
-
打开邮箱
Linking.openURL('mailto://1047912930@qq.com');
-
给textInput设置paddingLeft:5,输入框的光标就会往右移动5px的距离
textInput: {
flex: 1,
paddingLeft: 5,//输入框的光标就会往右移动
},
-
让键盘隐藏(输入框失去焦点)
处理方式(一):
先定义该变量 dismissKeyboard
const {width, height} = Dimensions.get('window'); // 获取屏幕尺寸
const dismissKeyboard = require('dismissKeyboard'); // 获取键盘回收方法
// 第三方
import {PullList} from 'react-native-pull';
调用
// 返回
pop() {
// 回收键盘
dismissKeyboard();
this.props.navigator.pop();
}
处理方式(二):
先给输入框Input设置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
调用方法
<Toast ref={toast=>this.toast = toast}/>
-
指示器ActivityIndicator的使用
//当加载数据时显示指示器,加载完成后关闭指示器
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'//设置指示器的大小,是枚举值
animating={this.state.isLoading}
/>:null;
let resultView=<View style={{flex:1}}>
{indicatorView}
{listView}
</View>
//样式
centering:{
alignItems:'center',
justifyContent:'center',
flex:1, //一定要指定flex
},
-
取消网络请求
就像在网上买东西一样,卖家已经发货是无法取消订单的,但是我们可以在快递来的时候,选择拒收快递!
封装取消网络请求类
export default function makeCancelable(promise) {
//定义标志位
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)
})
});
//向调用者返回一个字典
return {
promise:wrappedPromise,
//返回cancel方法,并将 hasCanceled_ 置为true
cancel(){
hasCanceled_=true;
}
}
}
在使用的类里面导入
import makeCancelable from '../util/Cancleable'
请求数据时调用
loadData(){
this.cancelable=makeCancelable(fetch(this.genFetchUrl(this.inputKeky)));
this.cancelable.promise
.then(response=>response.json())
.then(responseData=>{
...
}).catch(e=>{
...
})
取消搜索
//在取消搜索的地方调用
this.cancelable.cancel();
-
取消网络请求的应用
当获取网络请求的页面,当数据还未获取到时,用户选择返回上一级界面,这时,网络请求的页面还在请求数据,当获取到数据时,再上一级界面底部会显示警告,这时就需要在组件Will被卸载的方法中 "调用取消网络请求" .
componentWillUnmount(){
//this.cancelable 判断this.cancelable是否为空
this.cancelable&&this.cancelable.cancel();
}
-
React-Native 支持GCD的
-
在终端中切换到
当前文件
的某个目录
下
比如切换到iOS文件下执行一些操作
cd iOS /
-
属性的声明 propTypes
具体参考贾鹏辉自定义 NavigationBar 内容
static propTypes = {
name: PropTypes.string,
ID: PropTypes.string.isRequired, //这个是必须的,不传值会报警告
}
-
webView加载服务器返回的html标签
<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});