为了避免在实现简单的异步文件上传功能时候引入一个第三方库文件的尴尬情形(库文件可能造成多余的开销,拉低应用加载速度,尤其是在引入库文件之后仅使用其中一两个功能的情况下,性价比极低),最近了解了一下文件异步上传的实现原理,顺带看了看进度条、图片预览等功能的实现,做一点简单的整理。

文件上传
HTML结构如下,一个file input和一个button。当点击“上传”按钮的时候,将file input选中的文件上传到服务器。
<input type="file" name="file" id="file" /> <button id="upload">上传</button>
以下是“上传”按钮的点击事件处理器,点击按钮之后通过一个XMLHttpRequest对象来实现发送异步请求。上传的内容为文件,因此还需要用到FormData对象,FormData可以js里面创建表单对象,将file input的文件append到FormData对象中,最后调用XHR对象的send()方法将表单数据发送出去即可。
var file = document.querySelector('#file');
var upload = document.querySelector('#upload');
var xhr = new XMLHttpRequest();
// 点击上传
function uploadFile(event) {
var formData = new FormData();
formData.append('test-upload', file.files[0]);
xhr.onload = uploadSuccess;
xhr.open('post', '/upload', true);
xhr.send(formData);
}
// 成功上传
function uploadSuccess(event) {
if (xhr.readyState === 4) {
console.log(xhr.responseText);
}
}
上传进度
在进行文件上传的时候,xhr对象会有一个upload属性,会提供一个progress事件,在相应的事件处理器里面通过事件对象可以知道当前的上传进度,利用这个特点可以很方便地实现进度条或者进度提示。
<input type="file" name="file" id="file" /> <button id="upload">上传</button> <span id="progress">0%</span>
var progress = document.querySelector('#progress');
// 点击上传
function uploadFile(event) {
var formData = new FormData();
formData.append('test-upload', file.files[0]);
xhr.onload = uploadSuccess;
xhr.upload.onprogress = setProgress;
xhr.open('post', '/upload', true);
xhr.send(formData);
}
// 进度条
function setProgress(event) {
if (event.lengthComputable) {
var complete = Number.parseInt(event.loaded / event.total * 100);
progress.innerHTML = complete + '%';
}
}
图片预览
上传图片的时候可以利用FileReader对象来实现图片预览。FileReader可以异步读取用户电脑上的文件,将file input选中的文件传给FileReader,读取之后取得文件的URL并设置为image元素的src即可让选中的图片文件显示出来。
<input type="file" name="file" id="file" /> <button id="upload">上传</button> <span id="progress">0</span> <img id="image" src="" width="200" />
var file = document.querySelector('#file');
file.addEventListener('change', previewImage, false);
// 图片预览
function previewImage(event) {
var reader = new FileReader();
reader.onload = function (event) {
image.src = event.target.result;
};
reader.readAsDataURL(event.target.files[0]);
}
服务端处理
使用express搭建一个简单的NodeJS服务端,提供上传文件的接口。express要支持文件上传需要用到中间件,在express官网上有很多介绍。这里我使用的是multer中间件,下面是简单的使用示例。upload.single表示这个接口接受的上传文件数量为1个,'test-upload'限制了上传的表单数据的键为'test-upload'(formData.append(‘test-upload', file.files[0]);)。经过这个中间件处理之后,通过req.file可以访问到文件的相关信息,上传的文件存放在uploads文件夹中。
const upload = require('multer')({ dest: 'uploads/' });
app.post('/upload', upload.single('test-upload'), (req, res) => {
// 没有附带文件
if (!req.file) {
res.json({ ok: false });
return;
}
// 输出文件信息
console.log('====================================================');
console.log('fieldname: ' + req.file.fieldname);
console.log('originalname: ' + req.file.originalname);
console.log('encoding: ' + req.file.encoding);
console.log('mimetype: ' + req.file.mimetype);
console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
console.log('destination: ' + req.file.destination);
console.log('filename: ' + req.file.filename);
console.log('path: ' + req.file.path);
});
由输出可以看到,文件的命名使用一个哈希值表示,并且去除了后缀名,想要保持文件的原有的命名格式,需要再通过fs对文件进行改名。
app.post('/upload', upload.single('test-upload'), (req, res) => {
// 没有附带文件
if (!req.file) {
res.json({ ok: false });
return;
}
// 输出文件信息
console.log('====================================================');
console.log('fieldname: ' + req.file.fieldname);
console.log('originalname: ' + req.file.originalname);
console.log('encoding: ' + req.file.encoding);
console.log('mimetype: ' + req.file.mimetype);
console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
console.log('destination: ' + req.file.destination);
console.log('filename: ' + req.file.filename);
console.log('path: ' + req.file.path);
// 重命名文件
let oldPath = path.join(__dirname, req.file.path);
let newPath = path.join(__dirname, 'uploads/' + req.file.originalname);
fs.rename(oldPath, newPath, (err) => {
if (err) {
res.json({ ok: false });
console.log(err);
} else {
res.json({ ok: true });
}
});
});
完整代码
ajax异步文件上传、进度显示、图片预览
<input type="file" name="file" id="file" /> <button id="upload">上传</button> <span id="progress">0</span> <img id="image" src="" width="200" />
(function () {
'use strict';
var file = document.querySelector('#file');
var upload = document.querySelector('#upload');
var progress = document.querySelector('#progress');
var image = document.querySelector('#image');
var xhr = new XMLHttpRequest();
upload.addEventListener('click', uploadFile, false);
file.addEventListener('change', previewImage, false);
// 点击上传
function uploadFile(event) {
var formData = new FormData();
formData.append('test-upload', file.files[0]);
xhr.onload = uploadSuccess;
xhr.upload.onprogress = setProgress;
xhr.open('post', '/upload', true);
xhr.send(formData);
}
// 成功上传
function uploadSuccess(event) {
if (xhr.readyState === 4) {
console.log(xhr.responseText);
}
}
// 进度条
function setProgress(event) {
if (event.lengthComputable) {
var complete = Number.parseInt(event.loaded / event.total * 100);
progress.innerHTML = complete + '%';
}
}
// 图片预览
function previewImage(event) {
var reader = new FileReader();
reader.onload = function (event) {
image.src = event.target.result;
};
reader.readAsDataURL(event.target.files[0]);
}
})();
express服务器提供文件上传接口
const express = require('express');
const upload = require('multer')({ dest: 'uploads/' });
const path = require('path');
const fs = require('fs');
const port = 8080;
let app = express();
app.set('port', port);
// index.html, index.js放在static文件夹中
app.use(express.static(path.join(__dirname, 'static')));
app.get('*', (req, res) => {
res.redirect('index.html');
});
app.post('/upload', upload.single('test-upload'), (req, res) => {
// 没有附带文件
if (!req.file) {
res.json({ ok: false });
return;
}
// 输出文件信息
console.log('====================================================');
console.log('fieldname: ' + req.file.fieldname);
console.log('originalname: ' + req.file.originalname);
console.log('encoding: ' + req.file.encoding);
console.log('mimetype: ' + req.file.mimetype);
console.log('size: ' + (req.file.size / 1024).toFixed(2) + 'KB');
console.log('destination: ' + req.file.destination);
console.log('filename: ' + req.file.filename);
console.log('path: ' + req.file.path);
// 重命名文件
let oldPath = path.join(__dirname, req.file.path);
let newPath = path.join(__dirname, 'uploads/' + req.file.originalname);
fs.rename(oldPath, newPath, (err) => {
if (err) {
res.json({ ok: false });
console.log(err);
} else {
res.json({ ok: true });
}
});
});
app.listen(port, () => {
console.log("[Server] localhost:" + port);
});
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
# ajax异步上传文件
# nodejs
# express
# 异步
# node+axios实现服务端文件上传示例
# 利用node+koa+axios实现图片上传和回显功能
# 详解Vue+axios+Node+express实现文件上传(用户头像上传)
# nodejs+express实现文件上传下载管理网站
# nodejs基于express实现文件上传的方法
# 详解nodejs实现本地上传图片并预览功能(express4.0+)
# Nodejs+express+html5 实现拖拽上传
# 基于nodejs+express(4.x+)实现文件上传功能
# 使用express+multer实现node中的图片上传功能
# 使用nodejs+express实现简单的文件上传功能
# Nodejs进阶:基于express+multer的文件上传实例
# NodeJS实现图片上传代码(Express)
# node+express+axios实现单文件上传功能
# 上传
# 文件上传
# 进度条
# 表单
# 放在
# 来实现
# 服务端
# 上传文件
# 重命名
# 的是
# 是在
# 会有
# 夹中
# 上有
# 看了看
# 可以看到
# 相关信息
# 还需要
# 等功能
# 提供一个
相关文章:
如何通过虚拟主机空间快速建站?
广州商城建站系统开发成本与周期如何控制?
股票网站制作软件,网上股票怎么开户?
如何破解联通资金短缺导致的基站建设难题?
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
,巨量百应是干嘛的?
b2c电商网站制作流程,b2c水平综合的电商平台?
南京做网站制作公司,南京哈发网络有限公司,公司怎么样,做网页美工DIV+CSS待遇怎么样?
,有什么在线背英语单词效率比较高的网站?
如何使用Golang table-driven基准测试_多组数据测量函数效率
宝塔建站后网页无法访问如何解决?
,想在网上投简历,哪几个网站比较好?
电脑免费海报制作网站推荐,招聘海报哪个网站多?
魔方云NAT建站如何实现端口转发?
如何优化Golang Web性能_Golang HTTP服务器性能提升方法
如何在香港服务器上快速搭建免备案网站?
如何配置支付宝与微信支付功能?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
小建面朝正北,A点实际方位是否存在偏差?
如何通过山东自助建站平台快速注册域名?
c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】
如何快速查询网址的建站时间与历史轨迹?
建站之星安装模板失败:服务器环境不兼容?
建站主机数据库如何配置才能提升网站性能?
制作网站公司那家好,网络公司是做什么的?
如何通过cPanel快速搭建网站?
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
广州建站公司哪家好?十大优质服务商推荐
定制建站模板如何实现SEO优化与智能系统配置?18字教程
如何通过WDCP绑定主域名及创建子域名站点?
成都网站制作报价公司,成都工业用气开户费用?
seo网站制作优化,网站SEO优化步骤有哪些?
建站之星导航配置指南:自助建站与SEO优化全解析
如何用5美元大硬盘VPS安全高效搭建个人网站?
如何在万网主机上快速搭建网站?
css网站制作参考文献有哪些,易聊怎么注册?
上海网站制作网站建设公司,建筑电工证网上查询系统入口?
如何在万网自助建站中设置域名及备案?
如何制作一个表白网站视频,关于勇敢表白的小标题?
建站之星如何实现PC+手机+微信网站五合一建站?
c++ stringstream用法详解_c++字符串与数字转换利器
如何选购建站域名与空间?自助平台全解析
建站之星logo尺寸如何设置最合适?
大同网页,大同瑞慈医院官网?
企业微网站怎么做,公司网站和公众号有什么区别?
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
建站主机选哪种环境更利于SEO优化?
湖北网站制作公司有哪些,湖北清能集团官网?
代购小票制作网站有哪些,购物小票的简要说明?
Python路径拼接规范_跨平台处理说明【指导】
*请认真填写需求信息,我们会在24小时内与您取得联系。