Vue 92 ,Element 15 ,Vue + el-upload 实现图片上传与管理

发布于:2024-12-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

前言
一. 文章背景
二. 项目结构
三. 核心代码解析
1. 页面结构
2. 属性介绍
3. 必要参数
4. 函数逻辑
四. 相关样式布局
五. 关键功能解释
六. 注意事项
七. 本文总结

前言

在这篇博客中,我们将深入探讨如何使用 Vue 和 el-upload 构建一个图片上传与管理功能。我们将创建一个上传图片、预览图片、下载图片和删除图片的完整功能,并通过一系列的 Vue 组件和方法来实现这些功能。在此过程中,我们还将处理文件上传的限制与管理,并实现界面的过渡动画效果。

一. 文章背景

本文旨在为用户提供一个图片上传识别的前端界面,允许用户上传图片,并进行智能识别。为提升用户体验,我们实现了图片的上传、预览、下载和删除功能,并根据不同操作展示不同的 UI 界面效果。


二. 项目结构

我们将页面结构分为以下几个部分:

  1. 页面标题:显示“智能 识别”。
  2. 左侧内容区域:主要包含图片上传区域,当没有准备上传的图片时,显示默认图片。
  3. 右侧内容区域:用于显示智能识别的结果(如待填充区域)。
  4. 图片预览:提供预览上传的图片功能。
  5. 文件上传与管理:通过 Element UI 的上传组件来处理文件上传,支持文件删除、预览和下载。


三. 核心代码解析

1. 页面结构
<template>
    <div class="homeIndex_test">
        <!-- 页面标题 -->
        <header class="homeIndex_test_header">XX识别</header>

        <!-- 主内容区域 -->
        <div class="test_Con">
            <!-- 左侧内容区域,带有过渡动画 -->
            <transition name="slide_left">
                <article class="testCon_left">
                    <!-- 图片展示区域,当没有准备上传图片时显示默认图片 -->
                    <div class="default_imgBox" v-if="!isUploadReady">
                        <div class="img_box">
                            <img src="@/assets/test1/photo1.png" alt="" />
                        </div>
                    </div>

                    <!-- 上传组件 -->
                    <el-upload class="upload_box" :action="uploadImg_url" :headers="headers" :auto-upload="true" name="files"
              multiple :limit="limitNum" list-type="picture-card" v-model:file-list="fileList"
              :on-change="handleChange">

                        <div class="aperate_btnBox">
                            <!-- 上传按钮 -->
                            <el-button class="upload_btn" slot="trigger" size="small" type="primary"
                                :disabled="this.upBtnDisable">
                                上传图片
                                <i class="el-icon-upload el-icon--right"></i>
                            </el-button>
                            <!-- 开始识别按钮,当图片上传准备好时显示 -->
                            <el-button v-if="isUploadReady" class="begin_btn" size="small" type="primary"
                                @click.stop="choseBeginSb">
                                开始识别
                                <i class="el-icon-refresh-left"></i>
                            </el-button>
                        </div>

                        <!-- 上传文件的操作项 -->
                        <div slot="file" slot-scope="{ file }">
                            <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
                            <span class="el-upload-list__item-actions">
                                <!-- 预览图片操作 -->
                                <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
                                    <i class="el-icon-zoom-in"></i>
                                </span>
                                <!-- 下载图片操作 -->
                                <span class="el-upload-list__item-download" @click="handleDownload(file)">
                                    <i class="el-icon-download"></i>
                                </span>
                                <!-- 删除图片操作 -->
                                <span class="el-upload-list__item-delete" @click="handleRemove(file)">
                                    <i class="el-icon-delete"></i>
                                </span>
                            </span>
                        </div>

                    </el-upload>

                    <!-- 图片预览对话框 -->
                    <el-dialog :visible.sync="dialogVisible">
                        <img width="100%" :src="dialogImageUrl" alt="" />
                    </el-dialog>

                </article>
            </transition>

            <!-- 右侧内容区域,带有过渡动画 -->
            <transition name="slide_right">
                <section v-if="showRightSection" class="testCon_right">
                    <!-- 识别结果区域 -->
                </section>
            </transition>
        </div>
    </div>
</template>
2. 属性介绍
  :action="uploadImg_url"          <!-- 必填:上传的服务器地址 -->
  :headers="headers"               <!-- 可选:设置上传请求头部信息 -->
  :auto-upload="true"              <!-- 必填:选择文件后是否自动上传 -->
  name="files"                     <!-- 必填:上传接口接收文件参数的名字 -->

  multiple                        <!-- 可选:允许一次选择多个文件 -->
  :limit="limitNum"                <!-- 可选:限制最大上传文件数量 -->
  list-type="picture-card"        <!-- 可选:文件列表展示类型,此处为图片卡片模式 -->
  v-model:file-list="fileList"    <!-- 必填:双向绑定文件列表到数据属性,跟踪已选文件 -->
  :on-change="handleChange"        <!-- 可选:当文件状态改变时触发的方法 -->
3. 必要参数
    // 组件参数
    // 上传图片的目标URL
    uploadImg_url: process.env.VUE_APP_BASE_API + "/test/uploads",
    // 自定义上传请求的头部信息,通常用于传递认证令牌等。
    headers: {
      Authorization: 'Bearer your-token-here'
    },
    // 双向绑定的文件列表,用于存储用户选择的文件信息。
    fileList: [],
    // 文件上传的最大数量限制。
    limitNum: 3 // 示例:限制最多上传3个文件


    // 其它参数
    dialogImageUrl: '',        // 对话框中显示的图片 URL
    dialogVisible: false,      // 控制图片预览对话框的显示状态
    upBtnDisable: false,      // 控制上传按钮是否禁用
    isUploadReady: false,     // 控制“开始识别”按钮的显示状态
    showRightSection: false,  // 控制右侧部分的显示状态
4. 函数逻辑

    // 开始识别操作
    choseBeginSb() {
      this.showRightSection = true;  // 显示右侧识别结果区域
    },

    // 上传文件变化处理函数,选择图片后触发
    handleChange(file, fileList) {
      this.fileList = fileList;
      this.isUploadReady = fileList.length > 0;

      // 限制上传文件的数量为3张
      if (fileList.length >= 3) {
        this.upBtnDisable = true;
        this.$message({
          message: '您已达到最大上传数量, 3张图片, 请删除后重新上传',
          type: 'warning',
          offset: 400,
          showClose: true,  // 是否显示关闭按钮
        });
      } else {
        this.upBtnDisable = false;
      }
    },

    // 图片预览函数
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },

    // 下载图片函数
    handleDownload(file) {
      const link = document.createElement('a');
      link.href = file.url;
      link.download = file.name;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    },

    // 删除图片函数
    handleRemove(file) {
      const index = this.fileList.findIndex(f => f.uid === file.uid);
      if (index !== -1) {
        this.fileList.splice(index, 1);
      }
      this.isUploadReady = this.fileList.length > 0;
      if (this.fileList.length < 3) {
        this.upBtnDisable = false;
      }
    },


四. 相关样式布局

// CSS
::v-deep .testCon_right {
  background-image:
    linear-gradient(90deg,
      rgba(255, 255, 255, 0.5),
      rgba(192, 192, 192, 0.479),
      rgba(255, 255, 255, 0.5));
  background-size: 40px 100%;
  background-repeat: no-repeat;
  background-position: left -40px top 0;
  animation: shine .8s ease infinite;
}
// 定义动画
@keyframes shine {
  to {
    background-position: right -40px top 0;
  }
}


.el-upload-list__item-thumbnail {
  position: relative;
  /* 确保操作图标定位相对于图片 */
}
.el-upload-list__item-actions {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* 图标居中 */
  z-index: 10;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.el-upload-list__item-thumbnail:hover .el-upload-list__item-actions {
  opacity: 1;
  /* 鼠标悬停时显示操作图标 */
}
.el-upload-list__item-preview,
.el-upload-list__item-download,
.el-upload-list__item-delete {
  margin: 0 5px;
  cursor: pointer;
}
.el-upload-list__item-preview i,
.el-upload-list__item-download i,
.el-upload-list__item-delete i {
  font-size: 16px;
  /* 设置图标大小 */
}
.el-upload-list__item-delete i {
  color: #f56c6c;
  /* 删除图标颜色 */
}
.el-upload-list__item-preview i {
  color: #409eff;
  /* 放大图标颜色 */
}

.el-upload-list__item-download i {
  color: #67c23a;
  /* 下载图标颜色 */
}
// 隐藏上传按钮的边框
::v-deep .el-upload--picture-card {
  border: none;
  width: 100%;
  height: 100px;
  .aperate_btnBox {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
  }
  button {
    height: 40px;
  }
  i {
    // height: auto;
    font-size: 20px;
  }
}
// 上传图片的布局
::v-deep .el-upload-list {
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;

  &>li {
    width: 220px;
    height: 220px;
  }
}

// 主页面布局
.homeIndex_test {
  width: 100%;
  height: calc(100vh - 84px);
  // border: 1px solid red;

  .homeIndex_test_header {
    width: 100%;
    height: 60px;
    font-size: 22px;
    font-weight: bolder;
    // font-family: "楷体";
    display: flex;
    justify-content: center;
    align-items: center;
    border-bottom: 1px solid #46a6ff;
  }

  .test_Con {
    width: 100%;
    height: calc(100% - 60px);
    box-sizing: border-box;
    padding: 15px;
    // border: 1px solid red;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    overflow: auto;

    .testCon_left {
      width: 49%;
      height: 100%;
      // box-shadow: 0px 0px 6px red;
      border-radius: 6px;

      .default_imgBox {
        display: flex;
        justify-content: center;
        align-items: center;

        .img_box {
          width: 150px;
          height: 150px;
          border-radius: 50%;
          background-color: #409eff;
          display: flex;
          justify-content: center;
          align-items: center;

          img {
            width: 100px;
            height: 100px;
          }
        }
      }


      .upload_box {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        align-items: center;


        .upload_btn {
          .el-icon-upload:before {
            color: white;
            font-size: 16px;
          }

        }

        .begin_btn {
          .el-icon-refresh-left:before {
            color: white;
            font-size: 16px;
          }

        }
      }
    }

    .testCon_right {
      width: 49%;
      height: 100%;
      // border: 1px solid red;
      border-radius: 6px;
      position: relative;

      .parse_test {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
        font-size: 22px;
        display: flex;
        justify-content: center;
        align-items: center;
        font-family: "楷体";
      }

      .parse_btn {
        position: absolute;
        right: 2%;
        bottom: 2%;
      }

    }

  }

}


五. 关键功能解释

  1. 文件上传: 使用 Element UI 提供的 el-upload 组件处理图片的上传。v-model:file-list="fileList" 用于双向绑定文件列表,当文件上传时,我们通过 handleChange 方法进行处理,检查上传的文件数量限制(最多上传三张图片)。

  2. 上传按钮禁用: 当上传的图片数量超过 3 张时,上传按钮被禁用,并通过 this.upBtnDisable = true; 显示警告信息。用户需要删除一些图片才能继续上传。

  3. 图片预览: 用户可以点击上传列表中的预览按钮查看图片详情,图片将通过 el-dialog 显示在弹窗中。

  4. 图片下载和删除: 用户可以点击删除按钮移除文件,删除时会更新文件列表,并且控制上传按钮是否禁用。

  5. 过渡动画: 使用 Vue 的 transition 标签为左右两个区域的切换添加动画效果,使页面更具交互性。


六. 注意事项

  • 文件上传数量限制:在实际应用中,我们可能需要根据实际需求调整上传文件的数量限制,例如支持多文件上传或限制文件大小。
  • 性能优化:由于我们使用的是图片上传功能,因此需要处理大文件的上传,建议进行文件压缩或在服务器端进行文件大小校验。
  • UI 交互:确保用户在上传图片时能够清晰地了解上传状态和错误信息,可以在合适的地方添加进度条或提示框。


七. 本文总结

本文介绍了如何使用 Vue 和 Element UI 实现一个图片上传与管理功能。通过本教程,您应该能够掌握如何使用 el-upload 组件实现文件上传、删除、预览、下载等基本功能,并且结合 Vue 的过渡动画增强用户体验。


八. 更多操作

早期关于上传的博客,请看

Vue 58
文件上传icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_65793170/article/details/132627341?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223af974ce6f04f9315291ea871855f43b%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=3af974ce6f04f9315291ea871855f43b&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-3-132627341-null-null.nonecase&utm_term=%E4%B8%8A%E4%BC%A0&spm=1018.2226.3001.4450Vue 59

图片上传icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_65793170/article/details/133745982?ops_request_misc=%257B%2522request%255Fid%2522%253A%25223af974ce6f04f9315291ea871855f43b%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=3af974ce6f04f9315291ea871855f43b&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-133745982-null-null.nonecase&utm_term=%E4%B8%8A%E4%BC%A0&spm=1018.2226.3001.4450