1.文件上传
在实际前端开发中, 文件上传是一个很常见的功能,通常我们会将视频,图片等格式的文件上传到服务器以达到我们的需求.例如上传头像来达到换头像的功能等等.
1.1 起步
通常在我们实现文件上传有这么几步
- 获取当前事件对象的文件对象
- 创建FormData对象,并将带上当前的文件对象.
- 通过post请求向后台发送请求上传文件.并带上formdata.
- 搭建一个后台环境, 向后台发送请求.
- 后台通过获取前端传递过来的文件对象, 利用fs模块来进行读写,实现文件的保存
在实用原生js实现文件上传时, 我们需要用到H5的input文件域选择器来选择我们需要的文件.我们通过对其的type指定为file属性, 此时我们在页面上我们就可以看到一个选择文件button按钮元素.和一段描述文件名称的文字.
最终页面如下所示
此时当我们点击了选择文件按钮,会触发input元素的onChange事件, 此时我们给元素绑定对应的onChange事件, 以便我们获取用户选择的文件的信息.来实现文件的上传.
file.addEventListener('change',upLoad)
function upLoad(event){
// 事件对象event. 包含当前选中文件的一些简单信息
console.log(event)
}
1.2获取文件对象
通常我们会使用直接使用文件拖拽的方式来上传文件或者手动选择文件,此时我们需要做一个兼容处理,
当我们使用文件拖拽的方式上传时, 此时文件对象会存在于事件对象的dataTransfer的files上否者它会存在于事件对象的evnet的target的files属性上,此时我们的代码如如下
// 获取文件对象
function getFiles(e){
let files;
// 获取文件拖拽方式上传的文件对象
if (e.dataTransfer) {
files = e.dataTransfer.files[0];
} else if (e.target) {// 获取手动选择文件的文件对象
files = e.target.files[0];
}
return files
}
此时我们在upload函数中调用getFiles函数并传入事件对象
function upLoad(event){
let file = getFiles(event);
console.log(file)
}
此时我们点击选择文件.并随便选择一个图片. 此时我们可以在控制台打印出对应的文件对象,如下图所示
1.2 创建formData对象
通常我们会使用formData对象来实现文件上传, 使用formData对象的语法非常简单,下面是FormData的简单的用法.
let formData = new FormData();
formData.append('key1','value1');
formData.get('key1')// value1
接下来我们在upload里面创建formData对象, 并利用append方法添加对应的对应的键值对数据.
const formData = new FormData();
formData.append('file', getFiles(e));
console.log( formData.get('file'))
1.4 搭建后台环境
下面是我们需要用到的依赖
- koa 搭建基本的应用程序服务
- koa-router 建立路由启动应用程序
- koa-better-body 解析post请求的参数中的formData数据
- koa-static 解析静态资源目录
首页我们输入yarn init -y创建package.json文件. 接下来我们使用安装以下依赖
yarn add koa koa2-formidable koa-static koa-router
下面是后台逻辑的完整代码
const koa = require('koa'),
formidable = require('koa2-formidable'),
staticFiles = require('koa-static'),
router = require('koa-router')(); //引入实例化路由
const fs = require('fs');
const path = require('path');
const app = new koa();
// 路由
router.post('/head', async (ctx) => {
let file = ctx.request.files['headPhoto']
// 创建可读流
const reader = fs.createReadStream(file.path);
const extname = file.name
const filePath = path.join(__dirname, `./public/upload/${extname}`);
// 创建可写流
const upStream = fs.createWriteStream(filePath);
// 可读流 通过管道 写入可写流
reader.pipe(upStream)
ctx.body = {
headImgShortPath: '/public/' + `/upload/${extname}`,
isPass: true,
message: '上传成功'
}
})
router.get('/', async ctx => {
// 返回我们的index首页, 避免跨域
ctx.body = fs.readFileSync(__dirname + '/index.html').toString();
})
// 挂载路由
app.use(router.routes());
app.use(router.allowedMethods())
app.use(formidable())
// 指定 public目录为静态资源目录,用来存放 js css images 等
app.use(staticFiles(path.resolve(__dirname, "./public")))
app.listen(3001, function () {
console.log('koa server start listening on port 3001');
});
下面是我们项目的目录结构
此时我们的后台逻辑已经完成, 接下来我们在index.html中引入axios . 方便发送ajax请求.
接下来我们在只需要发送请求即可, 下面是前端文件上传的完整的js代码
let file = document.querySelector('.file');
file.addEventListener('change',upLoad)
async function upLoad(e){
//创建formdata对象
const formData = new FormData();
formData.append('file', getFiles(e));
const response = await axios.post('http://localhost:3001/upload',formData);
console.log(response)
}
// 获取文件对象
function getFiles(e){
let files;
if (e.dataTransfer) {
files = e.dataTransfer.files[0];
} else if (e.target) {
files = e.target.files[0];
}
return files
}
此时我们在在浏览器打开localshost:3001, 我们点击选择文件选择想要的文件进行上传, 此时我们可以在upload中看到上传的对应文件.