只需两行代码,实现大文件分片上传功能

一、优势

1、简便。

只需要传入几个参数即可帮你实现从分片到上传的全部 功能。

2、灵活,可以用构造函数中暴露的方法和属性实现与用户交互。

       如:

        1、.schedule_updata:可以得到当前上传进度(0-100)

        2、.stop():实现停止上传(将以上传的保存到浏览器缓存里了,即使离开页面下次仍可继续在上次停止时的地方上传)

        3、.star_run():实现继续上传。

        .........

二、源码:main.js

class CutFile_updata{
    /** 
 * @param {String} upload_url -文件上传的地址
 * @param {String} file_name -文件名
 * @param {Element} file_dom -放文件的dom元素
 * @param {Number} cut_size -分片的大小MB,默认3MB
 * @param {Boolean}  cut_up_type -选择切好之后再发送,还是一边请求一边发送
 * @param {Function} fun -上传完成后执行的函数
 * **/
    constructor(upload_url,file_name,file_dom,cut_size=3,cut_up_type=false,fun){
    this.cut_up_type=cut_up_type//true为边切边请求
    this.fun=fun
    this.file_dom=file_dom
    this.file_name=file_name
    this.upload_url=upload_url
    this.chunkSize=(1024*1024)*cut_size
    this.file=file_dom.files[0]
    this.cut_file_all=new Array(Math.ceil(this.file.size/this.chunkSize))
    this.cuted_file_arr=[]
    this.updataed_file_arr=localStorage.getItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200_updered')?JSON.parse(localStorage.getItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200_updered')):[]
    this.updataed_file_arr_find=new Array(Math.ceil(this.file.size/this.chunkSize))
    this.schedule_cut=this.cuted_file_arr.length/this.cut_file_all.length//切片进度
    this.schedule_updata=this.updataed_file_arr.length/this.cut_file_all.length//发送进度
    this.stop_key=false
    this.last_index=localStorage.getItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200')?parseInt(localStorage.getItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200')) :0
    this.open=true
    }
    init(){
        this.star_run()
        }
    stop(){
        this.stop_key=true
        localStorage.setItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200',this.last_index)
        localStorage.setItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200_updered',JSON.stringify(this.updataed_file_arr))
    }
    star_run(){
        this.stop_key=false
        this.di(this.last_index)
    }
    di(star_index){
            localStorage.setItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200',this.last_index)
            localStorage.setItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200_updered',JSON.stringify(this.updataed_file_arr))
            this.cut_hander(star_index*this.chunkSize,this.chunkSize+star_index*this.chunkSize,star_index).then((up_index)=>{
    })
    }
    cut_hander(star,end,index){
        return new Promise((y,b)=>{
        const filereder=new FileReader()
        filereder.readAsArrayBuffer(this.file.slice(star,end))
        console.log(star,end)
        filereder.onload=async (e)=>{
            console.log(e.target.result)
            this.cut_file_all[index]=e.target.result
            this.cuted_file_arr.push(e.target.result)
            this.post_data({'index':index,'file_name':this.file_name,'data':JSON.stringify(
               new Int8Array(e.target.result)) },e.target.result,index)
                y(index)
           }}
           )
        }
    post_data(data_obj,arr,index){
const xml=new XMLHttpRequest()
        xml.open('POST',this.upload_url)
        xml.send(JSON.stringify(data_obj))
        xml.onreadystatechange=()=>{
            if(xml.readyState==4&&xml.status==200){
            this.updataed_file_arr.push(arr)
            this.updataed_file_arr_find[index]=arr
            this.last_index+=1
            console.log(this.last_index)
            if(this.last_index+1<Math.ceil(this.file.size/this.chunkSize)&&!this.stop_key){
                this.di(this.last_index+1)
            }
            else{
                
            }
            this.schedule_updata=((this.updataed_file_arr.length+1)/this.cut_file_all.length)*100
            if(this.schedule_updata==100){
                this.fun()
                localStorage.removeItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200')
                localStorage.removeItem(this.file_name+'my_lastindex_cut_updata_star_2024_4_200_updered')
            }
            }
            
        }

    }}

源码中有很多可以完善的地方(读取文件和编码时可能会阻塞进程,可以将cut_hander写在webworker开的线程中)

三、使用示例

1、index.html(两行代码版,不用其停止、继续、上传进程功能)

<!DOCTYPE html>
<html lang="en">
<body>
    <input type="file" id="fl">
    <button onclick="w()">上传</button>
</body>
<script src="./main.js"></script>
<script>
function w(){
const c=new CutFile_updata(上传的地址,文件名,input元素,切片的大小MB,false,上传结束后运行的函数)
c.init()
}
</script>
</html>

​

​

 1、index2.html(使用其停止、继续、上传进程功能)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="file" id="fl">
    <button onclick="w()">上传</button>
    <button id="stop">停止</button>
    <button id="next">继续</button>
    <p id="num"></p>
</body>
<script src="./main.js"></script>
<script>
    function w(){
        const c=new CutFile_updata('http://127.0.0.1:8080','',document.querySelector('#fl'),1,false,()=>{console.log('上传完成')})
        c.init()
        document.querySelector('#stop').addEventListener('click',()=>{
             c.stop()
        })
        document.querySelector('#next').addEventListener('click',()=>{
              c.star_run()
        })
        setInterval(()=>{
            document.querySelector('#num').innerHTML=c.schedule_updata+'%'
        },200)
    }
       
</script>
</html>

为了便于理解所以没有加上css样式 

运行效果为

最后我们每次传到后端的数据为

{

'index':当前切片的索引,

'file_name':文件名,(我们取文件名最好要有唯一性)

'data':JSON

}

我的模拟后端代码为(node.js):(如果不知道node.js的使用可以看一下node.js的教程)

const http=require('http')
const resever=http.createServer()
resever.on('request',(user_goverme_data,gover_user_data)=>{
    gover_user_data.setHeader('Content-Type','text/html;charset=utf-8')//设置响应头中的文件类型,解决中文乱码问题
    gover_user_data.setHeader('Access-Control-Allow-Origin','*')//解决同源策略,还可以具体设置,可自行搜索
    user_goverme_data.on('data',(postData)=>{
      //console.log(JSON.parse(postData) ) 
    })
    console.log('收到了')
    gover_user_data.end()
    })
resever.listen(8080,()=>{
    console.log('服务器已启动')
})

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的 Vue 文件分片上传代码示例: ``` <template> <div> <el-upload class="upload-demo" action="/upload" :before-upload="beforeUpload" :on-progress="onProgress" :on-success="onSuccess" :on-error="onError" :headers="headers" :data="{chunkIndex: chunkIndex, chunkTotal: chunkTotal, fileName: fileName}" > <el-button size="small" type="primary">选择文件</el-button> </el-upload> </div> </template> <script> import axios from 'axios' import { Message } from 'element-ui' export default { data() { return { file: null, fileName: '', chunkSize: 2 * 1024 * 1024, // 每个分片的大小 chunkIndex: 0, // 当前上传分片索引 chunkTotal: 0, // 分片总数 progress: 0, // 上传进度 headers: { 'Content-Type': 'application/octet-stream' // 指定文件类型为二进制流 } } }, methods: { // 选择文件 beforeUpload(file) { this.file = file this.fileName = file.name this.chunkTotal = Math.ceil(file.size / this.chunkSize) }, // 上传进度 onProgress(event) { this.progress = Math.round((100 * event.loaded) / event.total) }, // 上传成功 onSuccess(response) { if (this.chunkIndex === this.chunkTotal - 1) { // 如果上传的是最后一个分片,表示文件上传成功 Message.success('文件上传成功') } else { // 否则继续上传下一个分片 this.chunkIndex++ this.uploadChunk() } }, // 上传失败 onError(error) { Message.error('文件上传失败') }, // 上传分片 uploadChunk() { const start = this.chunkIndex * this.chunkSize const end = Math.min((this.chunkIndex + 1) * this.chunkSize, this.file.size) const chunk = this.file.slice(start, end) const formData = new FormData() formData.append('file', chunk) axios.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, params: { chunkIndex: this.chunkIndex, chunkTotal: this.chunkTotal, fileName: this.fileName } }) .catch(() => { Message.error('文件上传失败') }) } } } </script> ``` 要注意的是,上述代码仅为示例,具体实现根据实际求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值