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();
}
相關文章
相關標籤/搜索