基于Node的React图片上传组件实现实例代码

红旗不倒,誓把JavaScript进行到底!今天介绍我的开源项目 Royal 里的图片上传组件的前后端实现原理(React + Node),花了一些时间,希望对你有所帮助。

基于Node的React图片上传组件实现实例代码

前端实现

遵循React 组件化的思想,我把图片上传做成了一个独立的组件(没有其他依赖),直接import即可。

import React, { Component } from 'react' import Upload from '../../components/FormControls/Upload/' //...... render() { return ( <div><Upload uri={'http://jafeney.com:9999/upload'} /></div> ) }

uri 参数是必须传的,是图片上传的后端接口地址,接口怎么写下面会讲到。

渲染页面

组件render部分需要体现三个功能:

图片选取(dialog窗口)

可拖拽功能(拖拽容器)

可预览(预览列表)

上传按钮 (button)

上传完成图片地址和链接 (信息列表)

主render函数

render() { return ( <form action={this.state.uri} method="post" encType="multipart/form-data"> <div className="ry-upload-box"> <div className="upload-main"> <div className="upload-choose"> <input onChange={(v)=>this.handleChange(v)} type="file" size={this.state.size} accept="image/*" multiple={this.state.multiple} /> <span ref="dragBox" onDragOver={(e)=>this.handleDragHover(e)} onDragLeave={(e)=>this.handleDragHover(e)} onDrop={(e)=>this.handleDrop(e)} className="upload-drag-area"> 或者将图片拖到此处 </span> </div> <div className={this.state.files.length? "upload-preview":"upload-preview ry-hidden"}> { this._renderPreview(); // 渲染图片预览列表 } </div> </div> <div className={this.state.files.length? "upload-submit":"upload-submit ry-hidden"}> <button type="button" onClick={()=>this.handleUpload()}> 确认上传图片 </button> </div> <div className="upload-info"> { this._renderUploadInfos(); // 渲染图片上传信息 } </div> </div> </form> ) }

渲染图片预览列表

_renderPreview() { if (this.state.files) { return this.state.files.map((item, idx) => { return ( <div className="upload-append-list"> <p> <strong>{item.name}</strong> <a href="javascript:void(0)" className="upload-delete" title="删除" index={idx}></a> <br/> <img src=https://www.jb51.net/{item.thumb} className="upload-image" /> </p> <span className={this.state.progress[idx]? "upload-progress": "upload-progress ry-hidden"}> {this.state.progress[idx]} </span> </div> ) }) } else { return null } }

渲染图片上传信息列表

_renderUploadInfos() { if (this.state.uploadHistory) { return this.state.uploadHistory.map((item, idx) => { return ( <p> <span>上传成功,图片地址是:</span> <input type="text" value=https://www.jb51.net/{item.relPath}/> <a href=https://www.jb51.net/{item.relPath} target="_blank">查看</a> </p> ); }) } else { return null; } }

文件上传

前端要实现图片上传的原理就是通过构建FormData对象,把文件对象append()到该对象,然后挂载在XMLHttpRequest对象上 send() 到服务端。

获取文件对象

获取文件对象需要借助 input 输入框的 change 事件来获取 句柄参数 e

onChange={(e)=>this.handleChange(e)}

然后做以下处理:

e.preventDefault() let target = event.target let files = target.files let count = this.state.multiple ? files.length : 1 for (let i = 0; i < count; i++) { files[i].thumb = URL.createObjectURL(files[i]) } // 转换为真正的数组 files = Array.prototype.slice.call(files, 0) // 过滤非图片类型的文件 files = files.filter(function (file) { return /image/i.test(file.type) })

这时 files 就是 我们需要的文件对象组成的数组,把它 concat 到原有的 files里。

this.setState({files: this.state.files.concat(files)})

如此,接下来的操作 就可以 通过 this.state.files 取到当前已选中的 图片文件。

利用Promise处理异步上传

文件上传对于浏览器来说是异步的,为了处理 接下来的多图上传,这里引入了 Promise来处理异步操作:

upload(file, idx) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest() if (xhr.upload) { // 上传中 xhr.upload.addEventListener("progress", (e) => { // 处理上传进度 this.handleProgress(file, e.loaded, e.total, idx); }, false) // 文件上传成功或是失败 xhr.onreadystatechange = (e) => { if (xhr.readyState === 4) { if (xhr.status === 200) { // 上传成功操作 this.handleSuccess(file, xhr.responseText) // 把该文件从上传队列中删除 this.handleDeleteFile(file) resolve(xhr.responseText); } else { // 上传出错处理 this.handleFailure(file, xhr.responseText) reject(xhr.responseText); } } } // 开始上传 xhr.open("POST", this.state.uri, true) let form = new FormData() form.append("filedata", file) xhr.send(form) }) }

上传进度计算

利用XMLHttpRequest对象发异步请求的好处是可以 计算请求处理的进度,这是fetch所不具备的。

我们可以为 xhr.upload 对象的 progress 事件添加事件监听:

xhr.upload.addEventListener("progress", (e) => { // 处理上传进度 this.handleProgress(file, e.loaded, e.total, i); }, false)

说明:idx参数是纪录多图上传队列的索引

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wysxfy.html