一、node
1.在node环境中安装multer(node.js中间件)包,用于处理 multipart/form-data
类型的表单数据
npm install --save multer
2.userRouter
var express = require('express');
const multer = require('multer')
const upload = multer({ dest: 'public/avataruploads/' })
const UserController = require('../../controllers/admin/UserController');
var router = express.Router();
// 上传图片接口
router.post('/adminapi/upload', upload.single('file'), UserController.upload);
module.exports = router;
public/avataruploads/ :上传后存放的路径地址
upload.single('file') :中的file是前端传过来的file文件的键
3.UserController.upload
const UserController = {
// 上传图片
upload: async (req, res, next) => {
console.log(req.file, 'req.file');
res.send({code:200,msg:'上传成功',data:{url:'/avataruploads/' + req.file.filename}})
}
}
module.exports = UserController;
二、Vue
1.upload组件
<template>
<div>
<!-- :auto-upload="false" -->
<el-upload
class="avatar-uploader"
:action="baseURL + url"
:headers="{ Authorization: useStore.token }"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:on-error="handleAvatarError"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</div>
</template>
<script setup lang="ts">
import { ElMessage, type UploadProps } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { baseURL, httpUrl } from '@/utils/request'
import { useUserStore } from '@/stores'
import { useRouter } from 'vue-router'
const router = useRouter()
const useStore = useUserStore()
const props = defineProps({
file: {
type: String,
default: ''
},
url: {
type: String,
default: '/adminapi/upload'
}
})
const emit = defineEmits(['uploadSuccess'])
const imageUrl = ref('')
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
console.log(response, uploadFile)
if (response.code === 200) {
imageUrl.value = response.data.url
emit('uploadSuccess', response.data.url)
} else {
ElMessage.error(response.msg)
}
// imageUrl.value = URL.createObjectURL(uploadFile.raw!)
}
const handleAvatarError: UploadProps['onError'] = (err: Error, uploadFile) => {
if (err.status === 401) {
ElMessage.error('登录已过期,请重新登录')
useStore.delUser()
return router.replace('/login')
}
console.dir(err, uploadFile)
}
watch(imageUrl, (newUrl) => {
if (newUrl && !newUrl.includes('http')) {
imageUrl.value = httpUrl + newUrl
}
})
watch(
() => props.file,
(newFile) => {
imageUrl.value = newFile
},
{ immediate: true }
)
</script>
<style scoped>
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
利用watch监听了数据的变化 拿到地址并不是带域名的(防止部署服务器时,图片丢失问题)所以更改后把配置后的域名给带上
2. 使用upload组件
<template>
<Upload :file="ruleForm.avatar" @uploadSuccess="uploadSuccessHandler"></Upload>
</template>
<script lang="ts" setup>
const ruleForm = reactive<RuleForm>({
avatar: ''
})
const uploadSuccessHandler = (url: string) => {
console.log(url)
ruleForm.avatar = url
}
</script>