vue3.0+TS+egg 前後端實現圖片上傳功能
阿新 • • 發佈:2021-01-02
技術標籤:vue
上效果圖
upload.vue
(樣式是boostrap,不必要太在意樣式,可以自己寫)
<template>
<div class="file-upload">
<div class="file-upload-container" @click.prevent="triggerUpload">
<slot v-if="fileStatus === 'loading'" name="loading" >
<button class="btn btn-primary" disabled>正在上傳...</button>
</slot>
<slot v-else-if="fileStatus === 'success'" name="uploaded">
<button class="btn btn-primary">上傳成功</button>
</slot>
< slot v-else name="default">
<button class="btn btn-primary">點選上傳</button>
</slot>
</div>
<input
type="file"
class="file-input d-none"
ref="fileInput"
@change="handleFileChange"
>
</div>
</template>
<script lang="ts">
import axios from 'axios';
import { defineComponent, ref } from "vue";
type UploadStatus = 'ready' | 'loading' | 'success' | 'error'
export default defineComponent({
props: {
action: {
type: String,
required: true
}
},
setup(props) {
const fileInput = ref<null | HTMLInputElement>(null)
const fileStatus = ref<UploadStatus>('ready')
const triggerUpload = () => {
if (fileInput.value) {
fileInput.value.click()
}
}
const handleFileChange = (e: Event) => {
const currentTarget = e.target as HTMLInputElement
if (currentTarget.files) {
fileStatus.value = 'loading'
const files = Array.from(currentTarget.files)
const formData = new FormData()
formData.append('file', files[0])
axios.post(props.action, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
console.log(res)
fileStatus.value = 'success'
}).catch(() => {
fileStatus.value = 'error'
}).finally(() => {
if (fileInput.value) {
fileInput.value.value = ''
}
})
}
}
return {
fileInput,
triggerUpload,
handleFileChange
}
}
})
</script>
使用元件的時候,傳入相對應的後端介面,即可
<Upload :action="'/api/upload'"></Upload>
egg
public 下,新建一個 comfiles 資料夾
router.js
router.post('/upload', controller.upload.uploadFiles);
app/controller/upload.js
'use strict';
const Controller = require('egg').Controller;
class UploadController extends Controller {
async uploadFiles() {
const { ctx } = this;
const data = await ctx.service.upload.index();
if (data) {
ctx.body = data;
} else {
ctx.body = {
message: '上傳失敗',
};
}
}
}
module.exports = UploadController;
app/service/upload.js
'use strict';
const Service = require('egg').Service;
const fs = require('fs');
const path = require('path');
const sendToWormhole = require('stream-wormhole');
class UploadService extends Service {
async index() {
const ctx = this.ctx;
const stream = await ctx.getFileStream();
const fileName = stream.filename;
const target = path.join(this.config.baseDir, `app/public/comfiles/${stream.filename}`);
const result = await new Promise((resolve, reject) => {
const remoteFileStream = fs.createWriteStream(target);
stream.pipe(remoteFileStream);
let errFlag;
remoteFileStream.on('error', err => {
errFlag = true;
sendToWormhole(stream);
remoteFileStream.destroy();
reject(err);
});
remoteFileStream.on('finish', async () => {
if (errFlag) return;
resolve({ fileName, name: stream.fields.name });
});
});
return result;
}
}
module.exports = UploadService;
參考文章:https://www.cnblogs.com/qq735675958/p/9315694.html