@Bios
2018-12-10T08:39:19.000000Z
字数 7485
阅读 991
React-native
app
本项目基于react ntive @0.51+ node@6.8
npm install -g react-native-cli
安装SDK
先要配置jdk
直接在网上下的SDK,本打算用Android Studio但是配置了一阵各种问题,也就放弃了它。
配置环境变量
新建一个变量名:ANDROID_HOME
,变量值:D:\AndroidSDK
在Path
后再加一个D:\AndroidSDK\platform-tools
要将
D:\AndroidSDK\tools
中的adb.exe复制到D:\AndroidSDK\platform-tools
中。
配置完环境变量,打开CMD运行adb
如果成功,则配置完成。
adb connect 127.0.0.1:62001
adb devices
初始化一个项目:react-native init my_app
项目名不能有横线'-',可以有下划线'_'
等待几分钟就会生成一个项目,该项目已经下载好了各个依赖插件。
通过 react-native run-android
,此时如果正确连接了模拟器,则会在模拟器上安装一个app。
此时还不能正常运行,需要在模拟器上打开Dev Settings
-> Debug server host & port for device
。
设置端口为ip:8081
,例如192.168.10.209:8081
.
怎样查看本机IP: 在CMD中运行
ipconfig
则可以查看对应ip。
yarn add mobx mobx-react
或 npm i mobx mobx-react --save
mobx中涉及了ES7的装饰器(decorator),所以需要安装相应的插件支持。
npm i babel-plugin-transform-decorators-legacy babel-preset-react-native-stage-0 --save-dev
或
yarn add babel-plugin-transform-decorators-legacy babel-preset-react-native-stage-0 --dev
在.babelrc
文件中配置babel插件:
{
'presets': ['react-native'],
'plugins': ['transform-decorators-legacy']
}
译注:从0.44版本开始,Navigator被从react native的核心组件库中剥离到了一个名为react-native-deprecated-custom-components的单独模块中。如果你需要继续使用Navigator,则需要先npm i facebookarchive/react-native-custom-components安装,然后从这个模块中import,即import { Navigator } from ‘react-native-deprecated-custom-components’.——官网
npm i react-navigation --save
或
yarn add react-navigation
npm install react-native-vector-icons --save
或
yarn add react-native-vector-icons
安卓关联图标:在项目根目录下执行
npm i -g rnpm
rnpm link
在需要使用的地方:
import Icon from 'react-native-vector-icons/FontAwesome';
使用组件:
<Icon name="qq" size={30} color="#52C0FE"/>
遇到图标不能显示却没有报错的问题,可以删除模拟器上的app,再执行一个
react-native run-android
。
如果报错信息:
原因是因为插件的SDK的platform与项目自身的不同。
修改node_modules\react-native-vector-icons\android\build.gradle
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
}
再次执行react-native run-android
就ok了。
const delay = timeout => {
return new Promise((resolve, reject) => {
setTimeout(() => reject('请求超时!'), timeout * 1000)
})
}
/**
* http请求
* @param {[type]} options.url [请求地址]
* @param {String} options.method [请求方法]
* @param {Object} options.params [请求参数]
* @param {[type]} timeout} [超时时间]
* @return {[type]} [Promise]
*/
const httpReq = ({url,method = 'get',params = {}, timeout}) => {
const paramArr = [];
/**
* var obj = {'a':'123','b':'345'};
* console.log(Object.keys(obj)); //['a','b']
*/
if (Object.keys(params).length !== 0) {
for (const key in params) {
paramArr.push(`${key}=${params[key]}`);
}
}
const urlStr = `${url}?${paramArr.join('&')}`; // get请求url拼接
const body = paramArr.join('&'); // post请求body传参
let options = {};
options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
body: body
}
if (method.toLowerCase() === 'get'){
if (timeout === undefined) {
return fetch(urlStr)
} else {
// Promise.race当数组中有一个promise返回则返回,其余的不再执行。如果超时了就不执行了
return Promise.race([fetch(urlStr), delay(timeout)])
}
} else if (method.toLowerCase() === 'post') {
if (timeout === undefined) {
return fetch(url,options)
} else {
return Promise.race([fetch(url,options), delay(timeout)])
}
} else {
return new Promise((resolve,reject) => {
resolve('不支持该请求!');
})
}
}
export { httpReq }
将"babel-preset-react-native": "5.0.0"
----> "babel-preset-react-native": "4.0.0"
<View style={styles.productBox}>
<View >
<Text style={{color:'#444',fontSize:16}}>{item.productName}</Text>
<View style={{flexDirection: 'row',alignItems: 'center',marginTop:3}}>
<Image source={require('../assets/higher.png')}
style={{width: 33, height:20}}
resizeMode = "contain"
/>
<Text style={{marginBottom:5,color:'#fc3d14'}}>{item.productPrice}</Text>
</View>
</View>
<View >
<Icon name="angle-right" size={30} color="#8f8888"/>
</View>
</View>
const styles = StyleSheet.create({
productBox: {
width: width - 40,
marginLeft: 20,
marginTop: 20,
borderRadius: 4,
padding: 20,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between', // 针对view (未测试所有情形,建议用vie包裹)
backgroundColor:'#fff'
}
})
<View>
<Image source={require('./assets/merchantBg_group/default_MB.png')}
resizeMode = "contain"
style={{width: width,marginTop:-65}}
/>
</View>
<View style={[styles.productBox,comStyle.card]}></View>
import {
Platform
} from 'react-native';
// 不同的平台显示不同的内容
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<Text style={styles.instructions}>
{instructions} // 直接调用
</Text>
</View>
);
}
}
// model/goods.js
import { observable, action } from 'mobx';
import { httpReq } from '../api/httpReq.js';
export default class GoodsModel {
@observable goodsList = []; // 被观察者
@action // 改变数据
getGoodsList = async (id) => {
const url = 'http://dev.xyf.78dk.com/v5/firstproductlists';
const method = 'post';
const params = {
merchantId: id || 1005
}
const responseData = await httpReq({url, method, params}).then(res => res.json());
this.goodsList = [].concat(responseData.data.productList);
}
}
// views/goods.js
// 伪代码
import React, { Component } from 'react';
import {observer} from 'mobx-react';
// 加载数据模型
import GoodsModel from '../models/goods.js';
import {
StyleSheet,
Text,
View,
Image,
Dimensions,
TouchableOpacity
} from 'react-native';
const {width,height} = Dimensions.get('window');
import Icon from 'react-native-vector-icons/FontAwesome';
@observer // 观察者
export default class Goods extends Component{
// new数据实例
goodsModel = new GoodsModel();
componentDidMount(){
this.getProductList();
}
getProductList(){
// 调用实例方法
this.goodsModel.getGoodsList();
}
render() {
// 拿取数据 (解构赋值)
const { goodsList } = this.goodsModel;
// 渲染
let productItem = goodsList.length>0&&goodsList.map((item, index) => {
return (
<TouchableOpacity onPress={() => this.onPressBtn(index)} key={index}>
<View style={styles.productBox}>
<Text style={{color:'#444',fontSize:16}}>{item.productName}</Text>
<Text style={{color:'#444',fontSize:16}}>{item.productPrice}</Text>
</View>
</TouchableOpacity>
)
})
return (
<View>
<View style={{backgroundColor:"#fff"}}>
……
</View>
{productItem}
</View>
);
}
}
const styles = StyleSheet.create({
……
});
// nextStep.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
TouchableOpacity
} from 'react-native';
export default class NextStep extends Component {
constructor(props){
super(props);
}
onPressBtn(){
this.props.click(); // 触发父组件传递的方法
}
render() {
return (
<TouchableOpacity onPress={() => this.onPressBtn()}>
<View style = {styles.nextStep}>
<View style= {styles.btn}>
<Text style={styles.text}>下一步</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
……
});
// index.js
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
} from 'react-native';
import NextStep from '../components/nextStep.js';
export default class Index extends Component{
componentDidMount(){
this.getProductList();
}
// 传递到子组件的方法
click(){
alert(1);
}
render() {
return (
<View>
……
<NextStep click={() => this.click()}></NextStep>
</View>
);
}
}
const styles = StyleSheet.create({
……
});
// route/index.js
import { StackNavigator } from 'react-navigation';
// 继续增加新的页面
import Goods from '../views/goods'
import GoodsDetail from '../views/goods-detail'
const AppNavi = StackNavigator({
Goods: {
screen: Goods
},
GoodsDetail: {
screen: GoodsDetail
}
},{
initialRouteName: 'Goods' // 初始化的页面
});
export default AppNavi;
// app.js
import React, { Component } from 'react';
import AppNavi from './src/routes'
import {
View,
Text
} from 'react-native';
export default class App extends Component {
render() {
return (
<AppNavi />
);
}
}
<View style={{height: 300}}>
<ScrowView>
.......
</ScrowView>
</View>