Nuxt3 npm run build后,上传文件后与如何显示问题,可以留意几个点
~/pages/upload.vue
注意 ‘onChangeFile’ 和 ‘FormData’
<template> <div> <h1 class="text-3xl mb-3">Profile</h1> <UForm ref="form" :state="state" @submit.prevent="save()"> <UAlert v-if="sucMessage" size="md" icon="i-heroicons-check-circle" title="" color="green" variant="subtle" class="mb-1" :description="sucMessage" /> <div v-else-if="errorMessage"> <UAlert size="md" icon="i-heroicons-exclamation-triangle" title="" v-for="(msg, key) in errorMessage" :key="key" color="red" variant="subtle" class="mb-1" :description="$t(msg)" /> </div> <UFormGroup :label="Photo" name="photo" class="mb-2"> <UInput type="file" v-model="state.photo" multiple @change="onChangeFile" /> </UFormGroup> <div class="mb-3"> <UButton :disabled="isSubmitting" size="md" type="submit" color="primary" variant="solid" class="mr-1">Submit</UButton> </div> </UForm> </div> </template> <script setup> const { t } = useI18n(); const isSubmitting = ref(false); const form = ref(); const errorMessage = ref([]); const sucMessage = ref(''); const state = ref({ photo: undefined, }); state.value.photo = ''; const formData = new FormData(); const onChangeFile = (event) => { for (let i = 0; i < event.target.files.length; i++) { formData.append('photo', event.target.files[i], event.target.files[i].name); } } async function save(){ isSubmitting.value = true; try { sucMessage.value = ''; errorMessage.value = {}; let response = ''; try { const res = await useFetch((`/api/upload`, { method: 'POST', body: formData }); response = res.data; } catch (error) { console.error('An error occurred while making the request:', error); } if (response && response.value.code === 200) { state.value.photo = ''; formData.delete('photo'); isSubmitting.value= false; sucMessage.value = t("update.success"); } else { form.value.setErrors(response.value.errors.map((err) => { if(err.field){ return { path: err.field, message: t(err.message) }; } })); isSubmitting.value= false; } } catch (error) { errorMessage.value.errors = t("update.error"); isSubmitting.value = false; } } </script>
~/server/api/upload.post.js
这是上传图片api, 注意‘uploadDir’:uploads 路径保持一致
import path from "path"; import fs from "fs"; import { fileURLToPath } from 'url'; import { writeFile } from "fs/promises"; export default defineEventHandler(async (event) => { try { const errors = []; const files = await readMultipartFormData(event); if (files.length === 0) { errors.push({field: 'photo', message: "account.avatar.error.required"}); return { code: 400, msg: "failed", errors, } } const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let uploadDir = path.join(__dirname, "../public/uploads"); if (process.env.NODE_ENV === 'development') { uploadDir = path.join(__dirname, "../../public/uploads"); } if (!fs.existsSync(uploadDir)){ fs.mkdirSync(uploadDir); } for(const file of files) { const filename = path.basename(file.filename); const newFilename = String(Date.now()) + String(Math.round(Math.random() * 100000)); const newPath = `${path.join(uploadDir, newFilename)}-${filename}`; // console.log("newPath:", newPath); await writeFile(newPath, file.data); } return { code: 200, msg: "success", } } catch (error) { console.log("error:", error); } });
~/server/routes/files/[name].get.js
解读图片或文件,注意 ‘uploadDir’: uploads 路径需和上传api 保持一致
解读地址是:localhost:3000/files/filename.png 就可以看到的
import fs from "fs"; import path from "path"; import { fileURLToPath } from 'url'; export default defineEventHandler(async (event) => { const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let uploadDir = path.join(__dirname, "../public/uploads"); if (process.env.NODE_ENV === 'development') { uploadDir = path.join(__dirname, "../../public/uploads"); } if (!fs.existsSync(uploadDir)){ fs.mkdirSync(uploadDir); } // console.log("uploadDir:", uploadDir); const filePath = path.join(uploadDir, event.context.params.name); return sendStream(event, fs.createReadStream(filePath)); });
本作品采用《CC 协议》,转载必须注明作者和本文链接