1.文件上傳
在實際前端開發中, 文件上傳是一個很常見的功能,通常我們會將視頻,圖片等格式的文件上傳到服務器以達到我們的需求.例如上傳頭像來達到換頭像的功能等等.
1.1 起步
通常在我們實現文件上傳有這么幾步
- 獲取當前事件對象的文件對象
- 創建FormData對象,并將帶上當前的文件對象.
- 通過post請求向后臺發送請求上傳文件.并帶上formdata.
- 搭建一個后臺環境, 向后臺發送請求.
- 后臺通過獲取前端傳遞過來的文件對象, 利用fs模塊來進行讀寫,實現文件的保存
在實用原生js實現文件上傳時, 我們需要用到H5的input文件域選擇器來選擇我們需要的文件.我們通過對其的type指定為file屬性, 此時我們在頁面上我們就可以看到一個選擇文件button按鈕元素.和一段描述文件名稱的文字.
<input type="file" class="file" >
最終頁面如下所示
此時當我們點擊了選擇文件按鈕,會觸發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請求.
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>
接下來我們在只需要發送請求即可, 下面是前端文件上傳的完整的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中看到上傳的對應文件.