上一篇说了文件选择的使用,
https://blog.csdn.net/qq_20652771/article/details/82184005
选了文件就要上传,这篇就记录一下文件上传
这是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: [email protected]
* @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(
{this.props.navigation.goBack();Toast.hide()}}>
)
}
}
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: [email protected]
* @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 (
{
visible ? this.showActionSheet():null
}
);
}
}
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();
}