利用koa+原生js實(shí)現(xiàn)文件上傳

1.文件上傳

在實(shí)際前端開發(fā)中, 文件上傳是一個(gè)很常見的功能,通常我們會(huì)將視頻,圖片等格式的文件上傳到服務(wù)器以達(dá)到我們的需求.例如上傳頭像來達(dá)到換頭像的功能等等.

1.1 起步

通常在我們實(shí)現(xiàn)文件上傳有這么幾步

  1. 獲取當(dāng)前事件對象的文件對象
  2. 創(chuàng)建FormData對象,并將帶上當(dāng)前的文件對象.
  3. 通過post請求向后臺(tái)發(fā)送請求上傳文件.并帶上formdata.
  4. 搭建一個(gè)后臺(tái)環(huán)境, 向后臺(tái)發(fā)送請求.
  5. 后臺(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" >

最終頁面如下所示

image-20201219122902272.png

此時(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)的文件對象,如下圖所示

image-20201219142036321.png

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)境

下面是我們需要用到的依賴

  1. koa 搭建基本的應(yīng)用程序服務(wù)
  2. koa-router 建立路由啟動(dòng)應(yīng)用程序
  3. koa-better-body 解析post請求的參數(shù)中的formData數(shù)據(jù)
  4. 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)


image-20201219144750129.png

此時(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)文件.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容