• Vue3 + Nodejs 实战 ,文件上传项目--实现图片上传


    目录

    技术栈

    1. 项目搭建前期工作(不算太详细)

    前端

     后端

    2.配置基本的路由和静态页面

     3.完成图片上传的页面(imageUp)

    静态页面搭建

     上传图片的接口

     js逻辑

    4.编写上传图片的接口

    5.测试效果

     结语


    博客主页:専心_前端,javascript,mysql-CSDN博客

     系列专栏:vue3+nodejs 实战--文件上传

     前端代码仓库:jiangjunjie666/my-upload: vue3+nodejs 上传文件的项目,用于学习 (github.com)

     后端代码仓库:jiangjunjie666/my-upload-server: nodejs上传文件的后端 (github.com)

     欢迎关注

    本系列记录vue3(前端)+nodejs(后端) 实现一个文件上传项目,目前只完成了图片的上传,后续会陆续完成:单文件上传,多文件上传,大文件分片上传,拖拽上传等功能,欢迎关注。

    技术栈

    前端:Vue3 Vue-router axios element-plus...

    后端:nodejs express...

    1. 项目搭建前期工作(不算太详细)

    前端

    我使用的是vite创建的vue项目,包管理器工具为:pnpm

    pnpm create vite

    创建好项目后安装依赖就可启动项目了

    配置+安装需要用到的库

    配置文件路径别名(在vite.config.js文件中)

    安装需要用到的库

    1. pnpm i vue-router
    2. pnpm i element-plus
    3. pnpm install @element-plus/icons-vue
    4. pnpm i axios

    进行基础配置(建好对应的文件夹)

    导入Element-Plus (在main.js文件中)

    1. import { createApp } from 'vue'
    2. import './style.css'
    3. import App from './App.vue'
    4. import ElementPlus from 'element-plus'
    5. import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
    6. //引入样式
    7. import 'element-plus/dist/index.css'
    8. import router from '@/router/index.js'
    9. const app = createApp(App)
    10. import * as ElementPlusIconsVue from '@element-plus/icons-vue'
    11. for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    12. app.component(key, component)
    13. }
    14. app.use(ElementPlus, {
    15. locale: zhCn
    16. })
    17. app.use(router)
    18. app.mount('#app')

     后端

    使用express框架快速搭建出node项目

    npx express-generator

    需要用到的依赖

    1. npm i cors
    2. npm i formidanle@2.1.2

    在app.js文件中配置跨域

    1. //配置跨域
    2. var cors = require('cors')
    3. app.use(cors())

    启动项目

    npm start

    2.配置基本的路由和静态页面

    目前路由文件是这样的

    1. //vue-router
    2. // import Vue from 'vue'
    3. import { createRouter, createWebHistory } from 'vue-router'
    4. const router = createRouter({
    5. history: createWebHistory(),
    6. routes: [
    7. {
    8. path: '/',
    9. //重定向至主页
    10. redirect: '/home'
    11. },
    12. {
    13. path: '/home',
    14. component: () => import('../views/home/index.vue'),
    15. name: 'home',
    16. redirect: '/home/imageUp',
    17. meta: {
    18. title: '首页'
    19. },
    20. children: [
    21. {
    22. path: '/home/imageUp',
    23. component: () => import('../views//home/imageUp/index.vue'),
    24. name: 'imageUp',
    25. meta: {
    26. title: '图片上传'
    27. }
    28. },
    29. {
    30. path: '/home/videoUp',
    31. component: () => import('../views/home/videoUp/index.vue'),
    32. name: 'videoUp',
    33. meta: {
    34. title: '视频上传'
    35. }
    36. },
    37. {
    38. path: '/home/fileUp',
    39. component: () => import('@/views/home/fileUp/index.vue'),
    40. name: 'fileUp',
    41. meta: {
    42. title: '文件上传'
    43. }
    44. }
    45. ]
    46. }
    47. ]
    48. })
    49. export default router

    目前就这几个页面

    在App.vue中使用路由占位

    home主页中的index.vue文件

    这其中除了静态页面的搭建外,我使用了编程式路由跳转方式实现路由跳转,后续可能会添加更多功能(也可以使用其他的方式实现跳转,不唯一)。

    1. <script setup>
    2. import { ref } from 'vue'
    3. //引入路由
    4. import { useRouter } from 'vue-router'
    5. const $router = useRouter()
    6. let activeIndex = ref(1)
    7. //二级路由跳转函数
    8. const changeUp = (path, index) => {
    9. //路由跳转
    10. $router.push(path)
    11. activeIndex.value = index
    12. }
    13. script>
    14. <style lang="scss" scoped>
    15. .container {
    16. .top {
    17. width: 100vw;
    18. height: 100px;
    19. background-color: rgb(61, 221, 154);
    20. text-align: center;
    21. font-size: 30px;
    22. color: #fff;
    23. line-height: 100px;
    24. }
    25. .heart {
    26. width: 100vw;
    27. //高度减去100px
    28. height: calc(100vh - 100px);
    29. display: flex;
    30. .left {
    31. width: 350px;
    32. height: 100%;
    33. background-color: #fffcfc;
    34. border-right: 1px solid #ccc;
    35. // padding-left: 20px;
    36. ul {
    37. li {
    38. width: 100%;
    39. height: 40px;
    40. display: flex;
    41. align-items: center;
    42. padding-left: 20px;
    43. p {
    44. margin-left: 10px;
    45. font-size: 16px;
    46. line-height: 40px;
    47. }
    48. }
    49. //给li加个active
    50. .active {
    51. color: rgb(61, 221, 154);
    52. }
    53. //加hover
    54. li:hover {
    55. cursor: pointer;
    56. background-color: rgb(146, 236, 199);
    57. opacity: 0.8;
    58. color: black;
    59. }
    60. }
    61. }
    62. .layout {
    63. width: calc(100% - 350px);
    64. height: 100%;
    65. padding: 20px;
    66. }
    67. }
    68. }
    69. style>

    目前项目长这样:

     3.完成图片上传的页面(imageUp)

    静态页面搭建

    act用于控制上传图片时的不同状态:选择图片->上传中->上传成功

    上传成功的图片会展示在下方的照片墙中

    1. <template>
    2. <div class="box">
    3. <div class="add">
    4. <input type="file" ref="fileInputRef" style="display: none" @change="handleFileChange" />
    5. <el-icon size="100" color="#ccc" v-if="act == 1" @click="openFileInput"><Plus />el-icon>
    6. <div class="loading" v-if="act == 2">div>
    7. <img :src="base64Img" alt="" v-if="act == 2" />
    8. div>
    9. div>
    10. <div class="imgList">
    11. <ul>
    12. <li v-for="item in imgList"><img :src="item" alt="" />li>
    13. ul>
    14. div>
    15. template>
    16. <style lang="scss" scoped>
    17. .box {
    18. width: 350px;
    19. height: 350px;
    20. border: 2px dashed rgb(175, 171, 171);
    21. border-radius: 2em;
    22. display: flex;
    23. justify-content: center;
    24. align-items: center;
    25. .add {
    26. position: relative;
    27. .loading {
    28. width: 100px;
    29. height: 100px;
    30. position: absolute;
    31. top: 35%;
    32. left: 35%;
    33. border: 3px solid #302b2b;
    34. border-top-color: transparent;
    35. border-radius: 50%;
    36. animation: circle infinite 0.75s linear;
    37. }
    38. // 转转转动画
    39. @keyframes circle {
    40. 0% {
    41. transform: rotate(0);
    42. }
    43. 100% {
    44. transform: rotate(360deg);
    45. }
    46. }
    47. img {
    48. width: 350px;
    49. height: 350px;
    50. z-index: -1;
    51. // 增加点模糊透明度
    52. opacity: 0.5;
    53. }
    54. }
    55. .add:hover {
    56. cursor: pointer;
    57. }
    58. }
    59. .imgList {
    60. width: 60%;
    61. // background-color: pink;
    62. margin-top: 30px;
    63. ul {
    64. border: 1px solid #ccc;
    65. border-radius: 20px;
    66. display: flex;
    67. flex-wrap: wrap;
    68. padding-left: 20px;
    69. li {
    70. width: 200px;
    71. height: 200px;
    72. margin: 5px 6px;
    73. // border: 1px solid pink;
    74. img {
    75. width: 100%;
    76. border-radius: 20px;
    77. height: 100%;
    78. }
    79. }
    80. }
    81. }
    82. style>

     上传图片的接口

     js逻辑

    我想实现的是有加载中的一个效果,但是单图片上传的速度,所以我使用了定时器来看到这个上传的效果,其中还没完成上传的图片,能显示加载出来主要是我们可以用FileReader中的onload事件来读取其中的数据,并会将其转为base64的数据,然后直接给img的src赋值,其他的就很简单了,代码基本能看懂。

    到这里前端的功能基本完成了

    4.编写上传图片的接口

    先建好文件夹

    路由images.js

    1. var express = require('express')
    2. var router = express.Router()
    3. const handler = require('./image_handler')
    4. //挂载路由
    5. router.post('/imageUpload', handler.imageUp)
    6. module.exports = router

    接口函数

    这里使用的包是formidable,下载的版本是2.1.2 ,如果版本不同可能代码会有所差异

    这里限制了上传的图片类型和图片大小,并且将图片上传至了public/images文件夹中。

    1. //放置上传图片的处理函数
    2. //导入处理文件上传的包
    3. const formidable = require('formidable')
    4. const path = require('path')
    5. exports.imageUp = (req, res, next) => {
    6. const form = formidable({
    7. multiples: true,
    8. uploadDir: path.join(__dirname, '../../public/images'),
    9. keepExtensions: true
    10. })
    11. form.parse(req, (err, fields, files) => {
    12. if (err) {
    13. next(err)
    14. return
    15. }
    16. console.log(files)
    17. //切割出上传的文件的后缀名
    18. let ext = files.file.mimetype.split('/')[1]
    19. //计算出图片文件大小
    20. let size = (files.file.size / 1024 / 1024).toFixed(2)
    21. if ((ext == 'png' || ext == 'jpg' || ext == 'jpeg') && size < 2) {
    22. let url = 'http://127.0.0.1:3000/images/' + files.file.newFilename
    23. res.send({
    24. code: 200,
    25. msg: '上传成功',
    26. imgUrl: url
    27. })
    28. } else {
    29. res.send({
    30. code: 400,
    31. msg: '只能上传png、jpg、jpeg格式的图片或图片过大'
    32. })
    33. return
    34. }
    35. })
    36. }

    5.测试效果

    上传中

    上传成功

     后端文件夹中

     结语

    下一篇,文件批量上传并显示实时传输进度条:Vue3 + Nodejs 实战 ,文件上传项目--实现文件批量上传(显示实时上传进度)_専心的博客-CSDN博客

    如果没有接触过文件上传或者想尝试开发一下文件上传项目的可以交流学习一下,后续会陆续更新更多的功能,如有想法可在评论区交流或私信,感谢关注!!!

  • 相关阅读:
    Android 使用Camera2 API 和 GLSurfaceView实现相机预览
    企业申请CMMI认证选择武汉好地科技的优势
    你不一定全部知道的16种进程注入方法和注入工具(C语言版)
    记录 | docker权限原因导致service ssh start失败
    基于vue-tianditu实现瓦片数据层添加
    简单实现spring的set依赖注入
    516. 最长回文子序列
    Python编程:从初学者到高级开发者的综合指南
    JAVA计算机毕业设计家政服务公司管理信息Mybatis+系统+数据库+调试部署
    计算机三级数据库高级查询
  • 原文地址:https://blog.csdn.net/m0_64642443/article/details/133799547