在html中输出对象中的指定属性值,html五种新增加的属性是

首页 > 技术 > 作者:YD1662023-04-17 02:05:40

说明

问题1

测试中发现复制多个文件无效,只有最后一个文件上传,在掘金的编辑器里也同样存在,在坐有知道原因的可以留言说下。

问题2

mac系统可以支持从磁盘复制文件后上传,windows 系统测试未通过,剪贴板的数据未拿到。

HTML

<div class="editor-box" id="editor-box" contenteditable="true" > 可以直接粘贴图片到这里直接上传 </div> 复制代码

JS

//光标处插入 dom 节点 function insertNodeToEditor(editor,ele) { //插入dom 节点 var range;//记录光标位置对象 var node = window.getSelection().anchorNode; // 这里判断是做是否有光标判断,因为弹出框默认是没有的 if (node != null) { range = window.getSelection().getRangeAt(0);// 获取光标起始位置 range.insertNode(ele);// 在光标位置插入该对象 } else { editor.append(ele); } } var box = document.getElementById('editor-box'); //绑定paste事件 box.addEventListener('paste',function (event) { var data = (event.clipboardData || window.clipboardData); var items = data.items; var fileList = [];//存储文件数据 if (items && items.length) { // 检索剪切板items for (var i = 0; i < items.length; i ) { console.log(items[i].getAsFile()); fileList.push(items[i].getAsFile()); } } window.willUploadFileList = fileList; event.preventDefault();//阻止默认行为 submitUpload(); }); function submitUpload() { var fileList = window.willUploadFileList||[]; var fd = new FormData(); //构造FormData对象 for(var i =0;i<fileList.length;i ){ fd.append('f1', fileList[i]);//支持多文件上传 } var xhr = new XMLHttpRequest(); //创建对象 xhr.open('POST', 'http://localhost:8100/', true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var obj = JSON.parse(xhr.responseText); //返回值 console.log(obj); if(obj.fileUrl.length){ var img = document.createElement('img'); img.src= obj.fileUrl[0]; img.style.width='100px'; insertNodeToEditor(box,img); // alert('上传成功'); } } } xhr.send(fd);//发送 } 复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/tree/master/src/upfiles-demo

大文件上传-分片

在 ie 时代由于无法使用xhr上传二进制数据,上传大文件需要借助浏览器插件来完成。 现在来看实现大文件上传简直soeasy。

如果太大的文件,比如一个视频1g 2g那么大,直接采用上面的栗子中的方法上传可能会出链接现超时的情况,而且也会超过服务端允许上传文件的大小限制,所以解决这个问题我们可以将文件进行分片上传,每次只上传很小的一部分 比如2M。

DEMO

在html中输出对象中的指定属性值,html五种新增加的属性是(13)

在html中输出对象中的指定属性值,html五种新增加的属性是(14)

说明

相信大家都对Blob 对象有所了解,它表示原始数据,也就是二进制数据,同时提供了对数据截取的方法slice,而 File 继承了Blob的功能,所以可以直接使用此方法对数据进行分段截图。

HTML

代码略,只需要一个 input file 标签。

JS

//分片逻辑 像操作字符串一样 var start=0,end=0; while (true) { end =chunkSize; var blob = file.slice(start,end); start =chunkSize; if(!blob.size){//截取的数据为空 则结束 //拆分结束 break; } chunks.push(blob);//保存分段数据 } <script> function submitUpload() { var chunkSize=2*1024*1024;//分片大小 2M var file = document.getElementById('f1').files[0]; var chunks=[], //保存分片数据 token = ( new Date()),//时间戳 name =file.name,chunkCount=0,sendChunkCount=0; //拆分文件 像操作字符串一样 if(file.size>chunkSize){ //拆分文件 var start=0,end=0; while (true) { end =chunkSize; var blob = file.slice(start,end); start =chunkSize; if(!blob.size){//截取的数据为空 则结束 //拆分结束 break; } chunks.push(blob);//保存分段数据 } }else{ chunks.push(file.slice(0)); } chunkCount=chunks.length;//分片的个数 //没有做并发限制,较大文件导致并发过多,tcp 链接被占光 ,需要做下并发控制,比如只有4个在请求在发送 for(var i=0;i< chunkCount;i ){ var fd = new FormData(); //构造FormData对象 fd.append('token', token); fd.append('f1', chunks[i]); fd.append('index', i); xhrSend(fd,function () { sendChunkCount =1; if(sendChunkCount===chunkCount){//上传完成,发送合并请求 console.log('上传完成,发送合并请求'); var formD = new FormData(); formD.append('type','merge'); formD.append('token',token); formD.append('chunkCount',chunkCount); formD.append('filename',name); xhrSend(formD); } }); } } function xhrSend(fd,cb) { var xhr = new XMLHttpRequest(); //创建对象 xhr.open('POST', 'http://localhost:8100/', true); xhr.onreadystatechange = function () { console.log('state change', xhr.readyState); if (xhr.readyState == 4) { console.log(xhr.responseText); cb && cb(); } } xhr.send(fd);//发送 } //绑定提交事件 document.getElementById('btn-submit').addEventListener('click',submitUpload); </script> 复制代码

NODE

服务端需要做一些改动,保存分片文件、合并分段文件、删除分段文件。

PS

合并文件这里使用 stream pipe 实现,这样更节省内存,边读边写入,占用内存更小,效率更高,代码见fnMergeFile方法。

//二次处理文件,修改名称 app.use((ctx) => { var body = ctx.request.body; var files = ctx.request.files ? ctx.request.files.f1:[];//得到上传文件的数组 var result=[]; var fileToken = ctx.request.body.token;// 文件标识 var fileIndex=ctx.request.body.index;//文件顺序 if(files && !Array.isArray(files)){//单文件上传容错 files=[files]; } files && files.forEach(item=>{ var path = item.path; var fname = item.name;//原文件名称 var nextPath = path.slice(0, path.lastIndexOf('/') 1) fileIndex '-' fileToken; if (item.size > 0 && path) { //得到扩展名 var extArr = fname.split('.'); var ext = extArr[extArr.length - 1]; //var nextPath = path '.' ext; //重命名文件 fs.renameSync(path, nextPath); result.push(uploadHost nextPath.slice(nextPath.lastIndexOf('/') 1)); } }); if(body.type==='merge'){//合并分片文件 var filename = body.filename, chunkCount = body.chunkCount, folder = path.resolve(__dirname, '../static/uploads') '/'; var writeStream = fs.createWriteStream(`${folder}${filename}`); var cindex=0; //合并文件 function fnMergeFile(){ var fname = `${folder}${cindex}-${fileToken}`; var readStream = fs.createReadStream(fname); readStream.pipe(writeStream, { end: false }); readStream.on("end", function () { fs.unlink(fname, function (err) { if (err) { throw err; } }); if (cindex 1 < chunkCount){ cindex = 1; fnMergeFile(); } }); } fnMergeFile(); ctx.body='merge ok 200'; } }); 复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/tree/master/src/upfiles-demo

大文件上传-断点续传

在上面我们实现了大文件的分片上传,解决了大文件上传超时和服务器的限制。

但是仍然不够完美,大文件上传并不是短时间内就上传完成,如果期间断网,页面刷新了仍然需要重头上传,这种时间的浪费怎么能忍?

所以我们实现断点续传,已上传的部分跳过,只传未上传的部分。

方法1

在上面我们实现了文件分片上传和最终的合并,现在要做的就是如何检测这些分片,不再重新上传即可。 这里我们可以在本地进行保存已上传成功的分片,重新上传的时候使用spark-md5来生成文件 hash,区分此文件是否已上传。

PS

生成 hash 过程肯定也会耗费资源,但是和重新上传相比可以忽略不计了。

DEMO

在html中输出对象中的指定属性值,html五种新增加的属性是(15)

在html中输出对象中的指定属性值,html五种新增加的属性是(16)

上一页12345下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.