您的位置:首页 > Web前端 > React

React-native文件上传

2018-08-29 16:24 866 查看
上一篇说了文件选择的使用,

/detail/2746528040.html

选了文件就要上传,这篇就记录一下文件上传

这是antd的一个UI库,不知道的同学自行去学习,选择图片和拍照有时间在补上,他们的上传方法是同一个,还包含了一点点RN和webview的交互以及组件封装调用

https://rn.mobile.ant.design/components/toast-cn/

1、调用各自文件选择方式

延迟调用文件选择是为了用户体验,以及权限获取延时问题









2、上传前的一些处理

我们不能让用户传一些乱七八糟的东西上去,所以要对文件进行筛选,我们就简陋的用文件后缀名筛选一下就行了











4、调用上传文件的方法

this.props.sendWebMessage(fileList)这是上传成功后和WebView交互,有时间会记一下RN和WebView的交互







5、这是上传方法







其中必须的的参数,参数名不能改,如果上传的文件是中文名,还要对name字段编码(后台接收需要解码,才能得到真正的文件名),不然会报类似的错误

unexpected char 0*6587 at 34 in content-disposition





引用组件的代码片段

/**
* @Date:   2018-08-08T17:25:36+08:00
* @Email:  xiao.hxj@qq.com
* @Last modified time: 2018-08-23T08:17:26+08:00
*/

import React, { Component } from 'react';
import { StyleSheet, View, Text, WebView, AsyncStorage} from 'react-native';
import { deviceWidth ,isIOS,deviceHeight } from '../../../utils/common';
import { _Download } from '../../../utils/downloadImage';
import { connect } from 'react-redux';
import {ActionSheet, Toast} from "antd-mobile-rn";
import Header from "../../../components/Common/Header";
import Modal from "../../../components/Common/Modal";
import NoDate from "../../../components/Common/NoDate";
import NoMore from "../../../components/Common/NoMore";
import LoadingMore from "../../../components/Common/LoadingMore";

const isIPhone = new RegExp('\\biPhone\\b|\\biPod\\b', 'i').test(window.navigator.userAgent);
let wrapProps;
if (isIPhone) {
wrapProps = {
onTouchStart: e => e.preventDefault(),
};
}

class Outweb extends Component {

constructor(props){
super(props);
this.state = {
visible:false,
// url: "http://..../appjump"
// url: "http://..../appjump"
url: "http://..../appjump"
}
}

async componentDidMount(){
let token = await  AsyncStorage.getItem('token')
let url = `${this.state.url}?token=${token}`
this.setState({url:url.replace(/"/g,'')})
console.log(url.replace(/"/g,''));
}
// 开始加载
onLoadStart(e){
Toast.loading('加载中...', 0)
}
// 加载成功
onLoad (){
Toast.hide()
}
// 加载失败
onError(e){
Toast.hide()
this.props.navigation.goBack()
Toast.info('应用加载失败,请稍后重试',2)
}

// 上传组件 getMessage
onMessage(e){
const message = e.nativeEvent.data
if(message === 'upload'){
Toast.loading('加载中...',0)
this.setState({visible:true})
}else {
// console.log('*************',message);
_Download(message);
}
}
// 回调
sendWebMessage(fileList){
this.refs.webview.postMessage(fileList);
}

render(){
return(
<View style={styles.page}>
<Header title={"外部页面"} goBack={() => {this.props.navigation.goBack();Toast.hide()}}></Header>
<WebView
ref={'webview'}
onLoadStart = {this.onLoadStart.bind(this)}
onLoad = {this.onLoad.bind(this)}
onError  = {this.onError .bind(this)}
onMessage = {this.onMessage.bind(this)}
automaticallyAdjustContentInsets={false}
startInLoadingState
scalesPageToFit = {true}
javaScriptEnabled = {true}
domStorageEnabled = {true}
style={styles.webView}
source={{uri: this.state.url,method: 'GET'}}
/>
<Modal sendWebMessage={this.sendWebMessage.bind(this)} visible={this.state.visible} />
</View>
)
}
}

const styles = StyleSheet.create({
page:{
flex:1,
backgroundColor:"#fff",
},
webView: {
height: isIOS ? (deviceHeight-44):(deviceHeight-64),
width: deviceWidth
},
})

export default connect(({cstmrModel, loading}) => ({
cstmrModel,
loading:loading.models.cstmrModel
}))(Outweb)

组件代码





/**
* @Date:   2018-08-21T15:52:02+08:00
* @Email:  xiao.hxj@qq.com
* @Last modified time: 2018-08-23T09:51:26+08:00
*/

import React from "react";
import { connect } from 'react-redux'
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity
} from "react-native";
import { activeOpacity ,acceptFile } from "../../utils/common";
import { ActionSheet, Toast, Modal} from "antd-mobile-rn";
import ImagePicker from 'react-native-image-crop-picker';
import RNFileSelector from 'react-native-file-selector';
import { FileUpload } from '../../utils/FileUpload'
import RNFS from 'react-native-fs'

const isIPhone = new RegExp('\\biPhone\\b|\\biPod\\b', 'i').test(window.navigator.userAgent);
let wrapProps;
if (isIPhone) {
wrapProps = {
onTouchStart: e => e.preventDefault(),
};
}

class UploadModal extends React.PureComponent {
constructor(props) {
super(props);
this.state={
visible:false
}
}

componentWillUnmount(){
ImagePicker.clean().then(() => {
console.log('clean file cache');
}).catch(e => {
console.log(e);
});
}

async fileUpload(fileAry) {
Toast.loading('上传中...',0)
try {
const res = await FileUpload(fileAry)
if (res.success) {
let fileList = JSON.stringify(res.attList)
this.props.sendWebMessage(fileList)
Toast.hide()
}else {
Toast.hide()
Toast.info(res.message,2)
}
} catch (e) {
Toast.hide()
// console.log(e);
}
}
// file上传
upLoadFile(){
let that = this;
Toast.hide()
RNFileSelector.Show( {
title: '选择文件',
closeMenu: true,
onDone: (path) => {
let params = [{
mime:'',
path:`file://${path}`
}]
let fileArr = path.split('.');
if (fileArr.length > 1 && acceptFile.indexOf(fileArr[fileArr.length-1]) !==-1) {
params.mime = `.${fileArr[fileArr.length-1]}`
// console.log('params*****',params);
that.fileUpload(params)
}else {
Toast.info('文件类型错误,请重新选择!',2);
}
},
onCancel: () => {
console.log('cancelled')
}
})
}
// image上传
upLoadImage(params){
let that = this;
Toast.hide()
if (params==='camera') {
ImagePicker.openCamera({
width: 300,
height: 400,
multiple: true,
hideBottomControls:true,
}).then(image => {
this.fileUpload(image)
}).catch((e)=>{
Toast.info('未选择文件或文件异常!',2)
});
}else {
ImagePicker.openPicker({
mediaType:'photo',
multiple: true
}).then(images => {
that.fileUpload(images)
}).catch((e)=>{
Toast.info('未选择文件或文件异常!',2)
});
}
}

showActionSheet(){
Toast.hide();
let that = this;
const BUTTONS = [
'拍摄',
'选择图片',
'选择文件',
'取消',
];
ActionSheet.showActionSheetWithOptions(
{
maskClosable:false,
options: BUTTONS,
cancelButtonIndex: 3,
},
(buttonIndex: any) => {
if (BUTTONS[buttonIndex]==='拍摄') {
Toast.loading('加载中...',0)
this.timer = setTimeout(()=>{that.upLoadImage('camera')},200)
}else if (BUTTONS[buttonIndex]==='选择图片') {
Toast.loading('加载中...',0)
that.timer = setTimeout(()=>{that.upLoadImage()},200)
}
else if (BUTTONS[buttonIndex]==='选择文件') {
Toast.loading('加载中...',0)
that.timer = setTimeout(()=>{that.upLoadFile()},200)
}
},
);
}

render() {
const { visible } =  this.props
return (
<View>
{
visible ? this.showActionSheet():null
}
</View>
);
}
}

const styles = StyleSheet.create({
content:{
flexDirection:'row',
justifyContent:'space-around',
alignItems:'center'
},
img:{
height:60,
width:60,
}
});

export default connect(({ M_My }) => ({
M_My
}))(UploadModal);

上传组件代码

import { AsyncStorage } from 'react-native';
import RequestUrl from "../services/RequestUrl";
import { Storage } from "../utils";

const baseUrl = async () => {
......
}

export const FileUpload = async(fileAry) => {
let formData = new FormData();
let token = await AsyncStorage.getItem('token');
let serverUrl = await baseUrl();
if (!fileAry.length) return {success:false,message:'未选择文件'};
//因为需要上传多个文件,所以需要遍历数组,把文件的路径数组放入formData中
for( let i = 0; i < fileAry.length; i++ ){
let path = fileAry[i].path;
let arr = path.split('/');//截取获取文件名
// 文件的类型,以及中文文件名编码
let file = { uri: path, type: 'multipart/form-data', name: escape(arr[arr.length-1]), fileType: fileAry[i].mime };   //这里的key(uri和type和name)不能改变,
formData.append("file", file);   //这里的files就是后台需要的key
//这里的files就是后台需要的key
}
// console.log(formData);
let response = await fetch(`${serverUrl}${RequestUrl.FILE_UPLOAD}`,{
method:'POST',
headers:{
// 'Accept': 'Application/json',
'Content-Type':'multipart/form-data',
'token': token,
'moduelType':8
},
body:formData,
})
// console.log('response',await response.json());
return await response.json();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  React Native ReactJS