react-native应用开发

RN上传文档组件react-native-file-select

2019-07-14  本文已影响0人  思考的种子

1,RN上传文档组件react-native-file-selector这一篇文档是前两篇文档的前提,这里做了上传后,后面就可以执行下载、查看等后续操作。
2,我用这个组件的原因是两端通用,而且可以展示文件选择目录,唯一不足的就是我们的需求想要做上传文档的大小控制在5M以内的时候这个控件里实现不了,所以想了其他的办法实现的,后面我会讲到
3,react-native-file-selector组件Github地址
4,RN下载文档
5,RN查看文档

1,上传的文件选择处理:
(1)此处涉及的代码有上传文档大小的判断,由于没有找到合适的方法获取文件大小,所以就采取原生方法获取文件大小
(2)文件选择的文件夹内容显示的时候做了个过滤,打开的文件里就都是你需要的文档类型了,注意下IOS和安卓过滤条件是相反的

//上传文档,type=0表示上传的照片,1表示上传的文档
    _onPressDocument = () => {
        this.props.close();
        let filterFile;
        if (Platform.OS === 'ios') { //文件夹内容筛选IOS和安卓是相反的,要注意
            filterFile = ['log','LOG','HTML','html','js','JS','bat','BAT','class','CLASS','java','JAVA','PRO','pro','sql','SQL'];
        } else if (Platform.OS === 'android') {
            filterFile = ".+(.pdf|.PDF|.doc|.DOC|.DOCX|.docx|.xls|.xlsx|.XLS|.XLSX|.ppt|.PPT|.PPTX|.pptx|.txt|.TXT|.rar|.RAR|.zip|.ZIP)$";
        }
        //文档目录
        RNFileSelector.Show({
            title: '选择文件',
            closeMenu: true,
            filter: filterFile,
            onDone: (path) => {
                // android上通过'react-native-file-selector获取的path是不包含file://'协议的,
                // android上需要拼接协议为'file://'+ path,
                // 而IOS则不需要,type可以是文件的MIME类型或者'multipart/form-data'
                let Path = Platform.OS === 'ios' ? path : `file://${path}`;
                let fileParams = {mime: '', path: Path}
                let fileArr = path.split('.');
                console.log('fileArr: ', fileArr);
                if (fileArr.length > 1 && acceptFile.indexOf(fileArr[fileArr.length - 1]) !== -1) {
                    let checkFilePath = Platform.OS === 'ios'?Path:path;
                    FaceModule.getFileSize(checkFilePath).then((result)=>{ //根据文件路径获取文件大小
                        console.log("rs->",result)
                        if (!_.isEmpty(result)&& parseFloat(result) <= 5) {  //文件小于5M继续下一步
                            fileParams.mime = `.${fileArr[fileArr.length - 1]}`
                            console.log('fileParams: ', fileParams);
                            this.FileUpload(fileParams)
                        } else {
                            this._showToast(); //提示文档超过5M,重新选择
                        }
                    });
                } else {
                    Toast.info('文件类型错误,请重新选择!', 2000);
                }
            },
            onCancel: () => {
                console.log('cancelled')
            }
        })
    }

安卓生获取文件大小:这里注意传过来的path前面不要加file://,当时没注意传过来的是带file://,获取不到文件大小,后来检查发现的

/**
     *  根据路径获取文件大小(单位M,保留2位小数)
     * @param path    指定路径即可(注意传过来的路径不要带file://)
     * @param promise
     */
    @ReactMethod
    public void getFileSize(String path, Promise promise) {
        String sizeMb = "";
        try {
            Log.e("FAceM", "path: " + path);
            File mfile = new File(path); // "/storage/emulated/0/文档7M.pdf"
            Log.e("FAceM", "size: " + mfile.length());
            //FileInputStream fis = new FileInputStream(mfile);

            FileInputStream fis = new FileInputStream(mfile);

            DecimalFormat df = new DecimalFormat("#.##");

            sizeMb = df.format((double) ((double) fis.available() / 1024 / 1024));

            Log.e("FaceModule", sizeMb);
            //fis.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("FAceM", "path: " + path);
            sizeMb = null;
        }
        promise.resolve(sizeMb);
    }

2,上传文档的接口请求

//formData上传,type=0表示上传的照片,1表示上传的文档
    FileUpload(fileParams) {
        get_item(APP_DATA).then((data1) => {
            // if (!_.isEmpty(data)) {
            if (!_.isEmpty(fileParams)) {
                //因为需要上传多个文件,所以需要遍历数组,把文件的路径数组放入formData中
                // for (let i = 0; i < fileAry.length; i++) {
                let path = fileParams.path;
                let arr = path.split('/');//截取获取文件名为数组

                // 文件的类型,以及中文文件名编码
                //这里的key(uri和type和name)不能改变
                let params = {
                    uri: path, name: arr[arr.length - 1], //取文件夹下的文件名  name: arr[arr.length - 1],
                    fileType: fileParams.mime
                };
                let access_token = data1.ACCESS_TOKEN
                let uid = data1.UID
                ModalIndicator.show('上传中...')
                _postFile('application/v3/campus/topic/upload', params, uid, access_token,
                    data => {
                        ModalIndicator.hide()
                        console.log('file data: ', data)
                        if (data.code == 0) {
                            //给H5的参数
                            let source = {
                                type: "1",
                                file_name: arr[arr.length - 1],
                                mime: fileParams.mime,
                                file_id: data.data.file_id
                            }
                            this.props.selPhoto(source)
                            console.log('file source: ', source)
                        }
                    }, err => {
                        ModalIndicator.hide()
                        console.log('data err:', err)
                    })
            } else {
                ModalIndicator.hide()
                Toast.info('未选择文件', 200)
                return
            }
            // }
        });
    }

3,接口请求处理,这里当时写完后选择的文件名为中文就报错,英文就没事,所以结合后端解决了这个问题

/**
 *  schoolForum 上传文档
 * @param uri  路径
 * @param name 文件名
 * @param fileType 文件类型
 * @param url 接口地址
 * @param access_token token
 * @param successCallback 接口返回
 * @param failCallback  接口失败返回
 * @private
 */
export function _postFile(url, params, uid, access_token, successCallback, failCallback) {
    let formData = new FormData()
    let file = {  
// 文件的类型,以及中文文件名编码 
//(encodeURIComponent、charset=utf-8、Content-Transfer-Encoding)等解决选择的文件的文件名为中文的时候报错问题
//要配合后端解析来用,后端童鞋懂的
        uri: params.uri,
        type: 'multipart/form-data;charset=utf-8',
        name: encodeURIComponent(params.name),
        fileType: params.fileType
    } //这里的key(uri和type和name)不能改变

    // 调用文件上传的方法 formData.append(key,value)
    // file是字段名,根据后端接受参数的名字来定,
    // android上通过'react-native-file-selector获取的path是不包含file://'协议的,
    // android上需要拼接协议为'file://'+ path,
    // 而IOS则不需要,type可以是文件的MIME类型或者'multipart/form-data'
    formData.append('file', file); //这里的files就是后台需要的key
    console.log("file",file)
    let postUrl = BASE_URL + url + "?file_type=224005"
    let fetchOptions = {  //解决选择的文件的文件名为中文的时候报错
        method: 'POST',
        headers: {
            'uid': uid,
            'access_token': access_token,
            'Content-Type': 'multipart/form-data;charset=utf-8', 
            'Content-Transfer-Encoding':'utf-8', 
        },
        body: formData
    }
    fetch(postUrl, fetchOptions)
        .then((response) => response.json())
        .then((responseJSON) => {
            if (responseJSON.msg && responseJSON.msg == 'ok') {
                successCallback(responseJSON)
            } else {
                if (failCallback) {
                    failCallback(responseJSON)
                }
            }
        }).catch(function (err) {
        if (failCallback) {
            failCallback(err)
        }
    });
}

4,头部导入组件使用,上传文件过滤

import RNFileSelector from 'react-native-file-selector'

const acceptFile = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rar', 'zip','PDF', 'DOC', 'DOCX', 'XLS', 'XLSX', 'PPT', 'PPTX', 'TXT', 'RAR' ,'ZIP']

组件使用介绍完毕!

上一篇 下一篇

猜你喜欢

热点阅读