React-native文件上传

上一篇说了文件选择的使用,java

https://my.oschina.net/HhhXxxJjj/blog/1936008react

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

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

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

一、调用各自文件选择方式react-native

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

二、上传前的一些处理antd

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

 

四、调用上传文件的方法dom

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

 

五、这是上传方法

其中必须的的参数,参数名不能改,若是上传的文件是中文名,还要对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();
}
相关文章
相关标签/搜索