HTML
代码略
复制代码
JS
模拟分段保存,本地保存到localStorage
//获得本地缓存的数据
function getUploadedFromStorage(){
return JSON.parse( localStorage.getItem(saveChunkKey) || "{}");
}
//写入缓存
function setUploadedToStorage(index) {
var obj = getUploadedFromStorage();
obj[index]=true;
localStorage.setItem(saveChunkKey, JSON.stringify(obj) );
}
//分段对比
var uploadedInfo = getUploadedFromStorage();//获得已上传的分段信息
for(var i=0;i< chunkCount;i ){
console.log('index',i, uploadedInfo[i]?'已上传过':'未上传');
if(uploadedInfo[i]){//对比分段
sendChunkCount=i 1;//记录已上传的索引
continue;//如果已上传则跳过
}
var fd = new FormData(); //构造FormData对象
fd.append('token', token);
fd.append('f1', chunks[i]);
fd.append('index', i);
(function (index) {
xhrSend(fd, function () {
sendChunkCount = 1;
//将成功信息保存到本地
setUploadedToStorage(index);
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);
}
});
})(i);
}
复制代码
方法2
为什么还有方法2呢,正常情况下方法1没问题,但是需要将分片信息保存在客户端,保存在客户端是最不保险的,说不定出现各种神奇的幺蛾子。
所以这里有一个更完善的实现,只提供思路,代码就不写了,也是基于上面的实现,只是服务端需要增加一个接口。
基于上面一个栗子进行改进,服务端已保存了部分片段,客户端上传前需要从服务端获取已上传的分片信息(上面是保存在了本地浏览器),本地对比每个分片的 hash 值,跳过已上传的部分,只传未上传的分片。
方法1是从本地获取分片信息,这里只需要将此方法的能力改为从服务端获取分片信息就行了。
-getUploadedFromStorage
getUploadedFromServer(fileHash)
复制代码
另外服务端增加一个获取分片的接口供客户端调用,思路最重要,代码就不贴了。
node 端上传图片不只会从客户端上传文件到服务器,服务器也会上传文件到其他服务器。
- 读取文件buffer fs
- 构建 form-data form-data
- 上传文件 node-fetch
NODE
/**
* filepath = 相对根目录的路径即可
*/
async function getFileBufer(filePath) => {
return new Promise((resolve) => {
fs.readFile(filePath, function (err, data) {
var bufer = null;
if (!err) {
resolve({
err: err,
data: data
});
}
});
});
}
/**
* 上传文件
*/
let fetch = require('node-fetch');
let formData = require('form-data');
module.exports = async (options) => {
let {
imgPath
} = options;
let data = await getFileBufer(imgPath);
if (data.err) {
return null;
}
let form = new formData();
form.append('xxx', xxx);
form.append('pic', data.data);
return fetch('http://xx.com/upload', {
body: form,
method: 'POST',
headers: form.getHeaders()//要活的 form-data的头,否则无法上传
}).then(res => {
return res.json();
}).then(data => {
return data;
})
}
复制代码
其他在浏览器端对文件的类型、大小、尺寸进行判断
- file.type判断类型
- file.size判断大小
- 通过动态创建 img 标签,图片加载后获得尺寸,naturalWidth naturalHeightor width height
JS
var file = document.getElementById('f1').files[0];
//判断类型
if(f.type!=='image/jpeg' && f.type !== 'image/jpg' ){
alert('只能上传 jpg 图片');
flag=false;
break;
}
//判断大小
if(file.size>100*1024){
alert('不能大于100kb');
}
//判断图片尺寸
var img =new Image();
img.onload=function(){
console.log('图片原始大小 width*height', this.width, this.height);
if(this.naturalWidth){
console.log('图片原始大小 naturalWidth*naturalHeight', this.naturalWidth, this.naturalHeight);
}else{
console.log('oImg.width*height', this.width, this.height);
}
}
复制代码
input file 外观更改
由于input file 的外观比较传统,很多地方都需要进行美化。
- 定义好一个外观,然后将 file input 定位到该元素上,让他的透明度为0。
- 使用 label 标签
<label for="file">Choose file to upload</label>
<input type="file" id="file" name="file" multiple>
复制代码
- 隐藏 input file 标签,然后调用 input 元素的 click 方法
PS
file 标签隐藏后在 ie 下无法获得文件内容,建议还是方法1 兼容性强。
源码在这里以上代码均已上传 github
https://github.com/Bigerfe/fe-learn-code/