用户头像(图片文件)上传(Vue + nodejs 前后端)

文件上传(图片上传)

前端:Vue3 + element-plus

后端:express

前端

组件库实现

封装一个 Upload 组件和一个 upload 方法。
Upload 组件

  <!-- auto-upload 选择好图片后立刻自动上传后端还是手动点击某按钮上传后端 -->
  <el-upload
    class="avatar-uploader"
    action="https://jsonplaceholder.typicode.com/posts/"
    :show-file-list="false"
    :auto-upload="false"
    :on-change="handleUpload"
  >
    <img
      v-if="props.avatar"
      :src="uploadAvatarUrl"
      class="avatar"
    />
    <el-icon
      v-else
      class="avatar-uploader-icon"
    >
      <Plus />
    </el-icon>
  </el-upload>
</template>

<script setup>
import { Plus } from '@element-plus/icons-vue'
import { computed } from 'vue'
const props = defineProps({
  avatar: String
})
const emit = defineEmits(['handle'])
// 每次选择完图片之后的回调,file是文件信息,file.raw是原生文件对象
const handleUpload = (file) => {
  emit('handle', file.raw)
}
const uploadAvatarUrl = computed(() => {
  return props.avatar.includes('blob') ? props.avatar : 'http://localhost:3000' + props.avatar
})
</script>

<style scoped lang="scss">
// 由于 scoped 属性,局部作用域,所以需要通过 ::v-deep 操作符来深层设置嵌套样式
::v-deep .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

::v-deep .el-upload:hover {
  border-color: var(--el-color-primary);
}

::v-deep .el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}

.avatar {
  width: 178px;
  height: 178px;
}
</style>

Upload 方法

import axios from "axios"
const upload = (path, userForm) => {
  // console.log('submit', userForm)
  // 上传文件需要转化为 FormData 的格式
  const params = new FormData()
  for (let item in userForm) {
    params.append(item, userForm[item])
  }
  return axios.post(path, params, {
    // FormData 文件上传的请求头
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  }).then(res=>res.data)
}
export default upload
 <UploadAvatar
    :avatar="userForm.avatar"
    @handle="handleUpload"
  ></UploadAvatar>
  
  // ...
  const userForm = reactive({
  username,
  gender,
  introduction,
  // avatar 和 file 都是代表的用户头像 avatar 用于前端用户回显,file 用户提交后端
  avatar,
  file: null
});
// 每次选择完图片之后的回调
const handleUpload = (file) => {
  userForm.avatar = URL.createObjectURL(file);
  userForm.file = file;
}
// 提交个人信息表单
const submitForm = () => {
  userFormRef.value.validate(async (valid) => {
    if (valid) {
      const res = await upload('/adminapi/user/upload', userForm)
      if (res.ActionType === 'OK') {
        store.commit('changeUserInfo', res.data)
        ElMessage.success('更新成功')
      }
    }
  });
}
// ...

原生实现

可以使用 HTML 的<input type="file">元素来实现文件上传。当用户选择了一个或多个文件后,你可以使用 JavaScript 来获取这些文件并将它们上传到服务器。

<input type="file" id="fileInput" multiple>
<button id="uploadButton">上传</button>

<script>
  const fileInput = document.querySelector('#fileInput');
  const uploadButton = document.querySelector('#uploadButton');

  uploadButton.addEventListener('click', () => {
    const files = fileInput.files;
    if (files.length === 0) {
      alert('请选择文件');
      return;
    }

    const formData = new FormData();
    for (const file of files) {
      formData.append('files[]', file);
    }

    fetch('/upload', {
      method: 'POST',
      body: formData
    })
    .then(response => response.text())
    .then(result => {
      console.log(result);
    })
    .catch(error => {
      console.error(error);
    });
  });
</script>

后端

const express = require('express');
const UserRouter = express.Router();
const UserController = require('../../controllers/admin/UserController')
// multer 中间件用于处理 form-data 数据(文件上传)
const multer = require('multer')
const upload = multer({ dest: 'public/avataruploads/' })

UserRouter.post('/adminapi/user/login', UserController.login)
UserRouter.post('/adminapi/user/upload', upload.single('file'), UserController.upload)

module.exports = UserRouter;
upload: async (req, res) => {
    // console.log(req.body,req.file)
    const { username, introduction, gender } = req.body
    const token = req.headers['authorization'].split(' ')[1]
    const payload = JWT.verify(token)
    const avatar = req.file ? `/avataruploads/${req.file.filename}` : ''
    await UserService.upload({ _id: payload._id, username, introduction, gender: Number(gender), avatar })
    if (avatar) {
      res.send({
        ActionType: 'OK',
        data: {
          username,
          gender: Number(gender),
          introduction,
          avatar,
        }
      })
    } else {
      res.send({
        ActionType: 'OK',
        data: {
          username,
          gender: Number(gender),
          introduction,
        }
      })
    }
  }
upload: async ({ _id,username, introduction,gender,avatar }) => {
  if(avatar) {
    return UserModel.updateOne({
      _id
    }, {
      username,
      introduction,
      gender,
      avatar
    })
  } else {
    return UserModel.updateOne({
      _id
    }, {
      username,
      introduction,
      gender
    })
  }
}

总结

用户头像文件上传流程:

  1. 先计算原本有没有图片,有则展示原图片的 url,没有则展示 icon
  2. 点击上传组件从本地选取图片,单个图片上传可以控制选取后自动上传和之后手动上传
  3. 当统一手动上传时,选择完图片之后将选择的图片file文件转换为URL地址进行前端页面的回显,并将其原本file格式的文件赋值给form表单内容对象,不修改头像默认使用原图片的 url
  4. 将form表单内容对象转化为 FormData 的格式,并设置 FormData 请求头,作为参数传递给后端
  5. 后端 multer 中间件用于处理 form-data 数据(文件上传)
  6. 将图片文件存入后端静态资源文件
  7. 数据响应,如果没有图片的更改即不传递图片文件数据给前端(如果传递则为空,会覆盖页面原本存在的头像url),这样前端默认使用已存在的blob文件
Vue3和Node.js是一对非常强大的组合,可以用于构建现代化的Web应用程序。下面是一个简单的介绍和演示: 1. Vue3是一种流行的JavaScript框架,用于构建用户界面。它具有响应式数据绑定、组件化开发和虚拟DOM等特性,使得开发者可以更轻松地构建交互性强、高效的前端应用程序。 2. Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,可以用于构建高性能的服务器端应用程序。它具有非阻塞I/O和事件驱动的特性,使得开发者可以使用JavaScript语言来编写服务器端代码。 为了演示Vue3和Node.js的使用,你可以按照以下步骤进行操作: 1. 首先,你需要安装Node.js和Vue CLI。Node.js可以从官方网站(https://nodejs.org)下载并安装,Vue CLI可以使用以下命令进行安装: ```shell npm install -g @vue/cli ``` 2. 创建一个新的Vue项目。在命令行中运行以下命令: ```shell vue create my-vue-app ``` 根据提示选择配置选项,然后等待项目创建完成。 3. 进入项目目录并启动开发服务器。在命令行中运行以下命令: ```shell cd my-vue-app npm run serve ``` 这将启动一个本地开发服务器,并在浏览器中打开应用程序。 4. 在Vue项目中创建一个简单的组件。在src目录下创建一个名为HelloWorld.vue文件,并添加以下代码: ```vue <template> <div> <h1>Hello, Vue3!</h1> </div> </template> <script> export default { name: 'HelloWorld', } </script> <style scoped> h1 { color: red; } </style> ``` 5. 在App.vue中使用HelloWorld组件。打开src/App.vue文件,并将以下代码添加到模板中: ```vue <template> <div id="app"> <HelloWorld /> </div> </template> <script> import HelloWorld from './HelloWorld.vue' export default { name: 'App', components: { HelloWorld } } </script> ``` 6. 启动Node.js服务器。在项目根目录下创建一个名为server.js的文件,并添加以下代码: ```javascript const express = require('express') const app = express() const port = 3000 app.get('/', (req, res) => { res.send('Hello, Node.js!') }) app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`) }) ``` 7. 在Vue应用程序中调用Node.js服务器的API。在HelloWorld.vue组件的脚本部分添加以下代码: ```javascript export default { name: 'HelloWorld', data() { return { message: '' } }, mounted() { fetch('http://localhost:3000') .then(response => response.text()) .then(data => { this.message = data }) } } ``` 现在,你可以在浏览器中查看Vue应用程序,并在页面上看到"Hello, Vue3!"的标题。同时,Vue应用程序还会调用Node.js服务器的API,并将返回的数据显示在页面上。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秀秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值