react ajax 上传文件,react 文件上传组件的简单封装

背景:一个老的项目需要增加上传excel文件的功能。

需求:实现一个类似于antd组件库中Upload组件的组件

Upload Directory

,

基本思路:

1.使用HTML5 的 input type="file"来进行文件的导入

2.文件流的传输跟我们常见的字符串传输不一样,简单的ajax肯定不行。因此选用了 XMLHttpRequest Level 2 新增的FormDate对象,它除了常规的表单提交之外,还可以进行二进制文件的上传。

3.input 默认样式的修改。在input 设置type=“file” 后会默认为下图的样式

bde519a41426ce8cf2b72366538a7ed4.png

我试着修改了value也不行,然后好像也没发现有什么属性可以解决。那么我放弃直接去修改input元素本身了,可以把input元素给隐藏起来,然后使用我自定义botton来展现。

4.设计组件。我要实现的就像上面的antd中的Upload组件那样,能够把button包住,点击botton然后触发一系列的打开文件夹、上传等动作。我先把组件命名为DjUploader,那么我的组件也应该这么用

...

5.编写组件。组件内部需要实现的主要部分:

隐藏原生的input

通过组件的子组件的onClick来触发input的click,来打开文件夹

导入文件之后,也就是input 的onChange事件,使用FormDate来处理导入的文件

ajax发post请求带上FormDate

隐藏原生的input:就是弄一下css,使用visibility: hidden或opacity: 0都行,别display:none就行了。

通过组件的方法来触发的input的click:那就先使用React.createRef()引用input的实例,再手动input click()就行了。关键在于通过其子组件的onClick来触发input click(),平时我们说子组件向父组件通信,父组件将自己的方法传递给子组件就行了,但这是载子组件显式存在的情况下。

现在需要是实现this.props.children这种形式下的子组件事件触发父组件方法

render(){

return<>{this.props.children}>

}

这种情况下是没办法通过像在写jsx是通过onClick属性来绑定事件的,这个时候肯定要通过别的方式了。

这个方式就是React.cloneElement()。

相比之下,我相信大家伙会更熟悉React.createElement(),不过平时项目里都写jsx,应该没人真用React.createElement来创建react元素吧(手动狗头)。

不妨复习一下React.createElement(),它接收三个参数,形如:

React.createElement(

type,

[props],

[...children]

)

type: 原生dom 的tagName,例如div、span、a等等或者React 的组件

[props]:所有属性

[…children]:所有的子组件

React.cloneElement():顾名思义,克隆,它就是克隆出一个react元素出来

React.cloneElement(

element,

[props],

[...children]

)

element:要克隆的目标,它就是一个react元素

[props]:新添加的属性,会合并到克隆来的属性数组中

[…children]:新添加的子组件,注意,添加的子组件不是合并,而是替换

回到上面我们解决this.props.children的形式子组件事件触发父组件方法,那么就可以使用React.cloneElement(child,{onClick:xxx}),先克隆一下组件实例化时传入的子组件,然后给其添加onClick属性。

FormDate处理导入的文件:

input上的.files获取文件对象,FormDate.append(‘key’,files)。

FormDate的append方法添加键值对,值就是文件对象了

ajax:data:formData

附加:input 也可以设置文件类型啊多个文件上传啊等,这里不做赘述了

最后贴下组件的代码

import * as React from "react";

import * as ReactDOM from "react-dom";

import "./djUploader.scss";

interface Props {

action: string;

accept: string;

}

export class DjUploader extends React.Component {

private ref: any;

constructor(props) {

super(props);

this.ref = React.createRef();

}

render() {

return (

type="file"

id="uploadFile"

className="dj-upload"

accept={this.props.accept}

ref={this.ref}

onChange={this.upload}

/>

{/* 要给子组件绑定事件,要先克隆一下子组件,再将事件传入克隆的组件的属性对象中 */}

{React.Children.map(this.props.children, (child: any) => {

return React.cloneElement(child, { onClick: this.chooseFile });

})}

);

}

chooseFile = () => {

this.ref.current.click();

};

upload = () => {

//使用formDate对象提交

let formDate = new FormData();

formDate.append(this.ref.current.files[0].name, this.ref.current.files[0]);

debugger;

$.ajax(this.props.action, {

method: "POST",

data: formDate,

async: true,

cache: false,

contentType: false,

processData: false,

success: (res) => {

alert("上传成功");

},

error: (res) => {

// console.log("上传失败", res);

alert("格式错误");

},

});

};

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值