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

一、优势

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
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值