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']
组件使用介绍完毕!