一、优势
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('服务器已启动')
})