由于最近项目有大文件上传,所以最近复习了下文件上传的相关知识,特别整理了一下笔记
js 实现图片预览的两种方式
- 要操作文件(图片)首先需要html支持,html中支持操作选择文件的标签如下
<input type="file" />
<!-- 下面图片预览代码的html结构 -->
<input type="file" onchange="handleFileChange1(this)" />
<input type="file" onchange="handleFileChange2(this)" />
- 第一种方式:(使用bloburl)js中的核心API是
URL.createObjectURL
// 2通过 URL.createObjectURL,它会把文件对象变成 blob 对象,然后直接被 img 标签读取
function handleFileChange2(instance) {
const file = instance.files[0];
imgUrl = globalThis.URL.createObjectURL(file);
const img = new Image();
img.alt = img.title = file.name;
img.src = imgUrl;
document.body.appendChild(img);
}
- 第二种方式:(使用dataurl)比较消耗性能 js中的核心API是
FileReader readAsDataURL
// 1通过 readAsDataURL 把图片转换为base64
function handleFileChange1(instance) {
const file = instance.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const base64URL = e.target.result;
const img = new Image();
img.alt = img.title = file.name;
img.src = base64URL;
document.body.appendChild(img);
};
}
js 实现单张图片上传的两种方式
<!-- 下面图片预览代码的html结构 -->
<input type="file" id="file1">
<input type="file" id="file2">
- 方案1:基于FORM-DATA
// 基于formData
document.getElementById('file2').onchange = async function() {
var files = this.files
if (files.length <= 0) return
var formData = new FormData()
formData.append('file', files[0])
formData.append('filename', files[0].name)
var res = await axios.post('http://127.0.0.1:8888/single1', formData)
if (res.data.code == 0) {
var img = new Image()
img.src = res.data.path
document.body.appendChild(img)
}
}
- 方案2:把选择的文件转化为BASE64,把BASE64传递给服务器
// 基于base64
function getBase64(file) {
return new Promise((resolve, reject) => {
var ready = new FileReader()
ready.readAsDataURL(file)
ready.onload = function(e) {
resolve(e.target.result)
}
})
}
document.getElementById('file1').onchange = async function() {
var files = this.files
if (files.length <= 0) return
// console.log(files)
var base64 = await getBase64(files[0])
var filename = files[0].name
// console.log(filename, base64)
var res = await axios.post('http://127.0.0.1:8888/single2', Qs.stringify({ chunk: encodeURIComponent(base64), filename }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
if (res.data.code == 0) {
var img = new Image()
img.src = res.data.path
document.body.appendChild(img)
}
}
js 实现多张图片上传
<section class="uploadBox clearfix">
<div class="card button">
<input type="file" id="uploadInp" accept="image/*" multiple>
</div>
<!-- <div class="card">
<img src="images/1.png" alt="">
<div class="progress">
<div class="line"></div>
</div>
<div class="mark"></div>
</div> -->
</section>
(function () {
//请求封装
function postRequest(url, data, config) {
config = config || {};
return axios.post(`http://127.0.0.1:8888${url}`, data, config).then(response => {
return response.data;
});
}
//文件读取
function fileReader(file) {
return new Promise(resolve => {
let reader = new FileReader;
reader.readAsDataURL(file);
reader.onload = ev => {
resolve(ev.target.result);
};
});
}
//延迟函数
function delay(interval) {
interval = interval || 500;
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, interval);
});
}
let uploadBox = document.querySelector('.uploadBox'),
button = uploadBox.querySelector('.button'),
uploadInp = uploadBox.querySelector('#uploadInp');
button.onclick = function () {
uploadInp.click();
};
uploadInp.onchange = async function () {
let self = this,
files = Array.from(self.files);
if (files.length === 0) return;
// 构建上传列表
let uploadList = [];
files.forEach((file, index) => {
uploadList[index] = {
file: file,
base64: null,
card: null
};
});
// 搞定BASE64 && 和动态创建CARD
let base64List = await Promise.all(files.map(file => fileReader(file))),
frag = document.createDocumentFragment();
base64List.forEach((base64, index) => {
let card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<img src="${base64}" alt="">
<div class="progress">
<div class="line"></div>
</div>
<div class="mark"></div>
`;
frag.appendChild(card);
//完善上传列表
uploadList[index].base64 = base64;
uploadList[index].card = card;
});
uploadBox.appendChild(frag);
await delay();
// 按照上传列表,批量上传图片 && 监听进度
uploadList.forEach(async item => {
let {
file,
base64,
card
} = item;
let data = {
chunk: encodeURIComponent(base64),
filename: file.name
},
config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
// 上传进度检测
onUploadProgress(ev) {
// ev.loaded && ev.total
let ratio = ev.loaded / ev.total * 100 + '%';
card.querySelector('.line').style.width = ratio;
}
};
let response = await postRequest('/single2', Qs.stringify(data), config);
if (response.code === 0) {
// 上传成功
await delay();
let progress = card.querySelector('.progress'),
mark = card.querySelector('.mark');
card.removeChild(progress);
card.removeChild(mark);
}
});
};
})();
文件上传服务端参考代码如下
//后端代码
/*-CREATE SERVER-*/
const express = require('express'),
app = express(),
bodyParser = require('body-parser'),
fs = require('fs'),
SparkMD5 = require('spark-md5'),
PORT = 8888;
app.listen(PORT, () => {
console.log(`THE WEB SERVICE IS CREATED SUCCESSFULLY AND IS LISTENING TO THE PORT:${PORT}`);
});
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMAIN REQUESTS!') : next();
});
app.use(bodyParser.urlencoded({
extended: false,
limit: '1024mb'
}));
/*-API-*/
const multiparty = require("multiparty"),
uploadDir = `${__dirname}/upload`;
function handleMultiparty(req, res, temp) {
return new Promise((resolve, reject) => {
// multiparty的配置
let options = {
maxFieldsSize: 200 * 1024 * 1024
};
!temp ? options.uploadDir = uploadDir : null;
let form = new multiparty.Form(options);
// multiparty解析
form.parse(req, function (err, fields, files) {
if (err) {
res.send({
code: 1,
reason: err
});
reject(err);
return;
}
resolve({
fields,
files
});
});
});
}
// 基于FORM-DATA上传数据
app.post('/single1', async (req, res) => {
let {
files
} = await handleMultiparty(req, res);
let file = files.file[0];
res.send({
code: 0,
originalFilename: file.originalFilename,
path: file.path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
});
// 上传BASE64
app.post('/single2', (req, res) => {
let {
chunk,
filename
} = req.body;
// chunk的处理:转换为buffer
chunk = decodeURIComponent(chunk);
chunk = chunk.replace(/^data:image\/\w+;base64,/, "");
chunk = Buffer.from(chunk, 'base64');
// 存储文件到服务器
let spark = new SparkMD5.ArrayBuffer(),
suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1],
path;
spark.append(chunk);
path = `${uploadDir}/${spark.end()}.${suffix}`;
fs.writeFileSync(path, chunk);
res.send({
code: 0,
originalFilename: filename,
path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
});
});
app.use(express.static('./'));
app.use((_, res) => {
res.status(404);
res.send('NOT FOUND!');
});