1. Demo介紹
使用前后端分離開發(fā)的模式實(shí)現(xiàn)文件上傳裤纹,前端使用Vue框架委刘,后端使用node的express框架,并且顯示上傳進(jìn)度條和文件上傳速度。效果如下圖
2. 核心代碼
2.1 前端代碼
對(duì)于從小就不愛寫作文的我,寫太多文字不現(xiàn)實(shí), 不如直接貼代碼實(shí)惠,樣式自己加吧,寫的略啰嗦, 湊合看吧
<template>
<div>
<Upload type="drag" :before-upload="handleUpload" action="后端服務(wù)地址/upload">
<Button class="sele_file_b"><i class="sele_file_icon_b"></i>選擇文件</Button>
</Upload>
<div class="file_detail_b" v-if="formValidate.file !== null">
<Table class="fileTab" :data="flieList" :columns="fileColumns" stripe disabled-hover>
<template slot-scope="{ row }" slot="action">
<div class="study-btn">
<span @click="deleteFile(row)"
><i class="delete_file_icon_b"></i
></span>
</div>
</template>
</Table>
<div class="file_btn_con_b">
<div v-if="uploadStatus">
<div class="progress_con_b">
<Progress :percent="progressBar" stroke-color="#22be4e"></Progress>
</div>
<div class="upload_speed_b">
<span class="speed_b">{{ speed }}</span>
<span>{{ this.flieList[0].size }}</span>
</div>
</div>
<Button class="file_btn_b" type="text" @click="upload" :loading="loadingStatus" >{{ loadingStatus ? "停止上傳" : "開始上傳" }}</Button>
</div>
</div>
</div>
</template>
<script>
// import { uploadFile } from '@/api/mirror'
import axios from "axios";
export default {
data() {
return {
speed: "",
formValidate: {
mirror_name: "",
sys_type: 0,
rule_type: "",
file: null,
},
loadingStatus: false,
uploadStatus: false,
flieList: [{ name: "", upload_status: "等待上傳", size: 0 }],
fileColumns: [
{ title: "文件名", key: "name", width: 150, tooltip: true },
{
title: "上傳狀態(tài)",
key: "upload_status",
render: (h, params) => {
if (params.row.upload_status !== "等待上傳") {
return h("div", [
h(
"span",
{
style: {
color: "#22be4e",
},
},
params.row.upload_status
),
]);
} else {
return h("div", [h("span", params.row.upload_status)]);
}
},
},
{ title: "文件大小", key: "size" },
{ title: "操作", width: 80, slot: "action", key: "handle" },
],
progressBar: 0,
};
},
methods: {
handleUpload(file) {
this.formValidate.file = file;
this.flieList[0].name = file.name;
if (file.size / 1024 < 1024) {
this.flieList[0].size = (file.size / 1024).toFixed(2) + "KB";
} else if (file.size / 1024 / 1024 < 1024) {
this.flieList[0].size = (file.size / 1024 / 1024).toFixed(2) + "M";
} else {
this.flieList[0].size =
(file.size / 1024 / 1024 / 1024).toFixed(2) + "G";
}
return false;
},
upload() {
this.loadingStatus = true;
this.uploadStatus = true;
const formData = new FormData();
formData.append("file", this.formValidate.file);
let t0 = new Date(); // 文件開始上傳時(shí)間
axios.post("后端服務(wù)地址/upload", formData, {
onUploadProgress: (progressEvent) => {
var percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
this.progressBar = percentCompleted; // 這有點(diǎn)多余 -_-
this.flieList[0].upload_status = this.progressBar + "%";
let t1 = new Date(); // 已上傳文件大小時(shí)間
// 計(jì)算出當(dāng)前上傳為多少kb/s
let s = Math.round(
progressEvent.loaded / 1024 / ((t1 - t0) / 1000)
);
if (s > 1024) {
this.speed = (s / 1024).toFixed(2) + "M/s";
} else {
this.speed = s + "kb/s";
}
}}
).then((res) => {
this.speed = "";
this.loadingStatus = false;
});
},
deleteFile() {
}
}
};
</script>
onUploadProgress: axios的文件進(jìn)度條事件, 通過此事件可獲取文件上傳進(jìn)度,以及相關(guān)文件信息
progressEvent.loaded: 返回文件已上傳大小
progressEvent.total: 返回上傳文件的總大小
利用上述返回值可計(jì)算出文件上傳的進(jìn)度(百分比, 代碼中有體現(xiàn))
計(jì)算上傳文件速率(我感覺對(duì))
let speed = Math.round( progressEvent.loaded / 1024 / ((t1 - t0) / 1000))
speed = Math.round(文件已上傳大小 / 1024 / ((已上傳文件大小所用時(shí)間 - 文件開始上傳時(shí)間) / 1000))
2.2 后端代碼
創(chuàng)建index.js文件, 代碼如下;
const express = require('express') // 引入express 框架
const app = express()
let multer = require('multer')
let fs = require('fs');
let path = require('path');
let Mock = require('mockjs'); //引入mock模塊
const cors = require('cors')
app.use(cors())
const bodyParser = require('body-parser')
// json 請(qǐng)求
app.use(bodyParser.json())
// 表單請(qǐng)求
app.use(bodyParser.urlencoded({ extended: false }))
app.listen(3000, () => {
console.log('Server running ...');
})
let upload = multer({
storage: multer.diskStorage({
//設(shè)置文件存儲(chǔ)位置
destination: function(req, file, cb) {
let date = new Date();
let year = date.getFullYear();
let month = (date.getMonth() + 1).toString().padStart(2, '0');
let day = date.getDate();
let dir = "./uploads/" + year + month + day;
//判斷目錄是否存在锡移,沒有則創(chuàng)建
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
recursive: true
});
}
//dir就是上傳文件存放的目錄
cb(null, dir);
},
//設(shè)置文件名稱
filename: function(req, file, cb) {
let fileName = file.fieldname + '-' + Date.now() + path.extname(file.originalname);
//fileName就是上傳文件的文件名
cb(null, fileName);
}
})
});
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
res.json({
file: req.file
})
})
package.json 文件配置如下;
"scripts": {
"start": "hotnode index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
Multer 是一個(gè) node.js 中間件呕童,用于處理 multipart/form-data
類型的表單數(shù)據(jù),它主要用于上傳文件淆珊。它是寫在 busboy 之上非常高效夺饲。
GitHub: https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md
首次啟動(dòng)服務(wù) npm start; 啟用了熱更新, 修改文件保存后服務(wù)自動(dòng)重啟