1.文件上傳
在實(shí)際前端開發(fā)中, 文件上傳是一個(gè)很常見的功能,通常我們會(huì)將視頻,圖片等格式的文件上傳到服務(wù)器以達(dá)到我們的需求.例如上傳頭像來達(dá)到換頭像的功能等等.
1.1 起步
通常在我們實(shí)現(xiàn)文件上傳有這么幾步
- 獲取當(dāng)前事件對象的文件對象
- 創(chuàng)建FormData對象,并將帶上當(dāng)前的文件對象.
- 通過post請求向后臺(tái)發(fā)送請求上傳文件.并帶上formdata.
- 搭建一個(gè)后臺(tái)環(huán)境, 向后臺(tái)發(fā)送請求.
- 后臺(tái)通過獲取前端傳遞過來的文件對象, 利用fs模塊來進(jìn)行讀寫,實(shí)現(xiàn)文件的保存
在實(shí)用原生js實(shí)現(xiàn)文件上傳時(shí), 我們需要用到H5的input文件域選擇器來選擇我們需要的文件.我們通過對其的type指定為file屬性, 此時(shí)我們在頁面上我們就可以看到一個(gè)選擇文件button按鈕元素.和一段描述文件名稱的文字.
<input type="file" class="file" >
最終頁面如下所示

此時(shí)當(dāng)我們點(diǎn)擊了選擇文件按鈕,會(huì)觸發(fā)input元素的onChange事件, 此時(shí)我們給元素綁定對應(yīng)的onChange事件, 以便我們獲取用戶選擇的文件的信息.來實(shí)現(xiàn)文件的上傳.
file.addEventListener('change',upLoad)
function upLoad(event){
// 事件對象event. 包含當(dāng)前選中文件的一些簡單信息
console.log(event)
}
1.2獲取文件對象
通常我們會(huì)使用直接使用文件拖拽的方式來上傳文件或者手動(dòng)選擇文件,此時(shí)我們需要做一個(gè)兼容處理,
當(dāng)我們使用文件拖拽的方式上傳時(shí), 此時(shí)文件對象會(huì)存在于事件對象的dataTransfer的files上否者它會(huì)存在于事件對象的evnet的target的files屬性上,此時(shí)我們的代碼如如下
// 獲取文件對象
function getFiles(e){
let files;
// 獲取文件拖拽方式上傳的文件對象
if (e.dataTransfer) {
files = e.dataTransfer.files[0];
} else if (e.target) {// 獲取手動(dòng)選擇文件的文件對象
files = e.target.files[0];
}
return files
}
此時(shí)我們在upload函數(shù)中調(diào)用getFiles函數(shù)并傳入事件對象
function upLoad(event){
let file = getFiles(event);
console.log(file)
}
此時(shí)我們點(diǎn)擊選擇文件.并隨便選擇一個(gè)圖片. 此時(shí)我們可以在控制臺(tái)打印出對應(yīng)的文件對象,如下圖所示

1.2 創(chuàng)建formData對象
通常我們會(huì)使用formData對象來實(shí)現(xiàn)文件上傳, 使用formData對象的語法非常簡單,下面是FormData的簡單的用法.
let formData = new FormData();
formData.append('key1','value1');
formData.get('key1')// value1
接下來我們在upload里面創(chuàng)建formData對象, 并利用append方法添加對應(yīng)的對應(yīng)的鍵值對數(shù)據(jù).
const formData = new FormData();
formData.append('file', getFiles(e));
console.log( formData.get('file'))
1.4 搭建后臺(tái)環(huán)境
下面是我們需要用到的依賴
- koa 搭建基本的應(yīng)用程序服務(wù)
- koa-router 建立路由啟動(dòng)應(yīng)用程序
- koa-better-body 解析post請求的參數(shù)中的formData數(shù)據(jù)
- koa-static 解析靜態(tài)資源目錄
首頁我們輸入yarn init -y創(chuàng)建package.json文件. 接下來我們使用安裝以下依賴
yarn add koa koa2-formidable koa-static koa-router
下面是后臺(tái)邏輯的完整代碼
const koa = require('koa'),
formidable = require('koa2-formidable'),
staticFiles = require('koa-static'),
router = require('koa-router')(); //引入實(shí)例化路由
const fs = require('fs');
const path = require('path');
const app = new koa();
// 路由
router.post('/head', async (ctx) => {
let file = ctx.request.files['headPhoto']
// 創(chuàng)建可讀流
const reader = fs.createReadStream(file.path);
const extname = file.name
const filePath = path.join(__dirname, `./public/upload/${extname}`);
// 創(chuàng)建可寫流
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目錄為靜態(tài)資源目錄,用來存放 js css images 等
app.use(staticFiles(path.resolve(__dirname, "./public")))
app.listen(3001, function () {
console.log('koa server start listening on port 3001');
});
下面是我們項(xiàng)目的目錄結(jié)構(gòu)

此時(shí)我們的后臺(tái)邏輯已經(jīng)完成, 接下來我們在index.html中引入axios . 方便發(fā)送ajax請求.
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>
接下來我們在只需要發(fā)送請求即可, 下面是前端文件上傳的完整的js代碼
let file = document.querySelector('.file');
file.addEventListener('change',upLoad)
async function upLoad(e){
//創(chuàng)建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
}
此時(shí)我們在在瀏覽器打開localshost:3001, 我們點(diǎn)擊選擇文件選擇想要的文件進(jìn)行上傳, 此時(shí)我們可以在upload中看到上傳的對應(yīng)文件.