vue3+ts - element-plus封装上传文件图片组件

这篇具有很好参考价值的文章主要介绍了vue3+ts - element-plus封装上传文件图片组件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  近期做到的项目中有涉及到上传图片上传文件的需求,因为是pc管理后台,用到了element-plus框架,所以我也一起使用element-plus中的上传图片上传图片功能,并对它进行封装成一个组件,方便在多个地方使用。

一、效果图

1、上传文件、视频

elementplus上传图片,vue,vue.js,前端,typescript

2、上传图片

elementplus上传图片,vue,vue.js,前端,typescript

二、代码分析及全部代码

  在这里上传图片和文件是分成了两个组件进行封装的,因为项目需求要求不一致,所以分开了,大家使用时有需要的话可以将它们合并到一起。文章来源地址https://www.toymoban.com/news/detail-523676.html

1、上传文件相关代码
<template>
  <div class="upload_wrap">
    <el-upload
      v-if="!props.isDisableUpload"
      class="upload"
      ref="uploadRef"
      :file-list="waitFileList"
      :multiple="props.isMultiple"
      :limit="props.limitNum"
      :accept="props.acceptType"
      :auto-upload="false"
      :show-file-list="false"
      :disabled="props.isDisableUpload"
      :on-change="handleChange"
    >
      <div class="el-upload__text">
        <img src="@/assets/images/icon_upload.png" />
        <span>上传文件</span>
      </div>
    </el-upload>
    <div class="template_list">
      <div class="template" v-for="(item, index) in waitFileList" :key="index">
        <span>
          <img src="@/assets/images/icon_link.png" />
        </span>
        <span class="documentName">{{ item.name }}</span>
        <span v-if="!props.isDisableUpload">
          <el-icon color="#000000a6" size="16" @click="removeFile(item)"
            ><Close
          /></el-icon>
        </span>
        <span v-if="isDownLoad" style="paddingleft: 5px">
          <img
            src="@/assets/images/icon_download.png"
            @click="handleDownLoad(item)"
          />
        </span>
      </div>
    </div>
    <span class="tips" v-if="!props.isDisableUpload"
      >支持{{ acceptTypeDesc }};文件大小不能超过{{ props.maxFileSize }}M</span
    >
  </div>
</template>

<script lang="ts" setup>
import { ref, watch } from "vue";
import { ElLoading, ElMessage } from "element-plus";
import { request } from "@/api/axios";
import { Close } from "@element-plus/icons-vue";
const emits = defineEmits(["fileSuccess", "fileRemove"]);
interface Props {
  acceptType?: string; // 上传文件类型
  acceptTypeDesc?: string; // 描述 - 上传文件类型
  isMultiple?: boolean; //   是否可批量上传
  limitNum?: number; // 允许上传文件的最大数量
  isDisableUpload?: boolean; // 是否禁用上传
  maxFileSize?: number; // 文件大小
  action?: string;
  fileList?: any; // 回显的文件
  isDownLoad?: boolean; // 是否可以下载
}
// 接收父组件传递过来的参数
const props = withDefaults(defineProps<Props>(), {
  acceptType: ".xls,.doc",
  acceptTypeDesc: "doc/xls",
  isMultiple: true,
  limitNum: 10,
  isDisableUpload: false,
  maxFileSize: 10,
  action: "/activity/resource/uploadFile",
  fileList: [],
  isDownLoad: false,
});
let waitFileList = ref<any[]>([]);

waitFileList.value = props.fileList;
waitFileList.value?.forEach((item: any) => {
  item.name = item.original;
});

watch(
  () => props.fileList,
  () => {
    console.log("props.fileList====>", props.fileList);
    waitFileList.value = props.fileList;
    waitFileList.value?.forEach((item: any) => {
      item.name = item.original;
    });
  }
);

// 文件变化Handle 这里监听上传文件的变化是一个一个接收到变化的,所以文件也是一个一个上传到服务器上面的
const handleChange = async (file: any, fileList: any[]) => {
  // 防止多次执行change
  const rawFile = file.raw;
  const list = props.acceptTypeDesc.split("/");
  let acceptTypeList = list.map((its:string)=>{
    return getType(its)
  })
  // 如果要检索的字符串值没有出现,则该方法返回 -1
  const ars = acceptTypeList.filter((q:string)=>{
    return rawFile.type.indexOf(q)>-1
  })
  // 用于校验是否符合上传条件
  const type = props.acceptTypeDesc.replace("/", ", ");
  if (ars.length<1) {
    ElMessage.error(`仅支持格式为${type}的图片`);
    return false;
  } else if (rawFile.size / 1024 / 1024 > props.maxFileSize) {
    ElMessage.error(`文件大小不能超过${props.maxFileSize}MB!`);
    const arr = [...waitFileList.value];
    waitFileList.value = arr.filter((item: any) => {
      return item.uid != rawFile.uid;
    });
    return false;
  } else {
    let formData = new FormData();
    formData.append("file", rawFile);
    formData.append("fileType", "2");
    const loadingInstance = ElLoading.service({
      text: "正在上传",
      background: "rgba(0,0,0,.2)",
    });
    // 上传到服务器上面
    const requestURL: string = props.action;
    request("post", requestURL, formData, {
      headers: { "Content-Type": "multipart/form-data" },
    })
      .then(async (res: any) => {
        if (res.code == 0) {
          loadingInstance.close();
          let obj = {
            ...res.data,
            name: res.data.original,
          };
          emits("fileSuccess", obj);
        } else {
          loadingInstance.close();
          ElMessage.warning(`文件上传失败`);
        }
      })
      .catch(() => {
        loadingInstance.close();
        // ElMessage.warning(`文件上传失败`);
      });
  }
  return true;
};

// 校验上传文件格式
const getType = (acceptType: string) => {
  let val = "";
  switch (acceptType) {
    case "xls":
      val = "excel";
      break;
    case "doc":
      val = "word";
      break;
    case "pdf":
      val = "pdf";
      break;
    case "zip":
      val = "zip";
      break;
    case "xlsx":
      val = "sheet";
      break;
    case "pptx":
      val = "presentation";
      break;
    case "docx":
      val = "document";
      break;
    case "text":
      val = "text";
      break;
  }
  return val
};

// 移除文件
const removeFile = (file: any) => {
  const arr: any[] = [...waitFileList.value];
  waitFileList.value = arr.filter((its: any) => {
    return its.id != file.id;
  });
  emits("fileRemove", waitFileList.value);
};

const handleDownLoad = (row: { ossFile: string }) => {
  const str = window.location.href.split("#")[0];
  const herf = str.slice(0, str.length - 1);
  window.location.href = herf + row.ossFile;
};
</script>

<style lang="scss" scoped>
.upload_wrap {
  .upload {
    min-width: 468px;
    padding-bottom: 10px;
  }
  .tips {
    display: block;
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.65);
  }
}

:deep().el-upload__text {
  width: 106px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ffffff;
  border: 1px solid rgba(0, 0, 0, 0.15);
  img {
    display: block;
    width: 14px;
    height: 14px;
  }

  span {
    font-size: 14px;
    padding-left: 6px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.65);
  }
}

.template_list {
  padding-bottom: 4px;
}
.template {
  display: flex;
  align-items: center;
  padding: 5px 0;
  span {
    line-height: 16px;
  }
  img {
    margin-right: 8px;
    width: 16px;
    height: 16px;
  }
  .documentName {
    margin-right: 12px;
    font-size: 14px;
    color: rgba(0, 0, 0, 0.65);
  }
}
</style>

2、上传图片相关代码及分析
<template>
  <div class="avatar-uploader">
    <el-upload
      class="avatar-uploader"
      :show-file-list="false"
      :disabled="disabledType"
      :auto-upload="false"
      accept=".png,.jepg,.jpg"
      ref="excelUploadRef"
      :on-change="handleChange"
    >
      <img
        v-if="imagesURL || props.imageUrl"
        :src="props.imageUrl ? props.imageUrl : imagesURL"
        class="avatar"
      />
      <div class="upImgBox" v-else>
        <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
        <div>{{ imgUpText }}</div>
      </div>
    </el-upload>
    <div class="upImgText">
      {{ imgText }}
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, watch } from "vue";
import { Plus } from "@element-plus/icons-vue";
import { ElMessage, ElLoading } from "element-plus";
import { request } from "@/api/axios";
interface Props {
  imageUrl?: string; // 回显图片地址
  action?: string; //   上传地址
  imgText?: string; //   文字可以不传
  imgUpText?: string; // 上传按钮的文字
  disabledType?: boolean; // 是否禁用上传
}
const props = withDefaults(defineProps<Props>(), {
  imageUrl: "",
  action: "/activity/resource/uploadFile",
  imgText: "支持jpg/jpeg/png;文件大小不能超过2M;封面图建议尺寸940px*400px",
  imgUpText: "上传封面",
  disabledType: false,
});

const imagesURL = ref<string>(props.imageUrl);
const emits = defineEmits(["imgSuccess"]);
const handleChange = (file: any, fileList: any) => {
  console.log(file);
  console.log(fileList);
  let rawFile = file.raw;
  if (
    rawFile.type !== "image/jpeg" &&
    rawFile.type !== "image/png" &&
    rawFile.type !== "image/jpg"
  ) {
    ElMessage.error("仅支持格式为jpg, jpeg, png的图片");
    return false;
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error("图片文件大小不能超过2MB!");
    return false;
  } else {
    let formData = new FormData();
    formData.append("file", rawFile);
    formData.append("fileType", "1");
    const loadingInstance = ElLoading.service({
      text: "正在上传",
      background: "rgba(0,0,0,.2)",
    });
    // 请求接口上传图片到服务器
    let requestURL = props.action;
    request("post", requestURL, formData, {
      headers: { "Content-Type": "multipart/form-data" },
    })
      .then(async (res: any) => {
        console.log(res);
        if (res.code == 0) {
          loadingInstance.close();
          let obj = {
            imgUrl: res.data.ossFile,
            raw: res.data,
          };
          emits("imgSuccess", obj);
          imagesURL.value = res.data.ossFile;
        } else {
          loadingInstance.close();
          ElMessage.warning(`文件上传失败`);
        }
      })
      .catch(() => {
        loadingInstance.close();
        ElMessage.warning(`文件上传失败`);
      });
  }
  return true;
};
watch(
  () => props.imageUrl,
  () => {
    imagesURL.value = props.imageUrl;
  }
);
</script>

<style lang="scss" scoped>
:deep().avatar-uploader {
  .avatar {
    width: 104px;
    height: 104px;
    display: block;
  }
  .el-upload {
    border: 1px dashed #dcdfe6;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: 0.2s;
    background: rgba(0, 0, 0, 0.04) !important;
  }

  .el-upload:hover {
    border-color: #14b194;
  }
}
.el-icon.avatar-uploader-icon {
  font-size: 16px;
  color: rgba(0, 0, 0, 0.45);
  text-align: center;
}
.upImgBox {
  width: 104px;
  height: 104px;
  font-size: 14px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.65);
  text-align: center;
  padding-top: 24px;
  box-sizing: border-box;
}
.upImgText {
  font-size: 14px;
  color: rgba(0, 0, 0, 0.6);
  margin-top: 4px;
}
</style>

到了这里,关于vue3+ts - element-plus封装上传文件图片组件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3 封装 element-plus 图标选择器

    效果一: 效果二:   效果一的这个是把全部的icon图标都让它显示出来,让我们自己选择说选图标 2.1. 全局注册 icon 组件 2.2. 组件实现  2.3. 使用  效果二的这个是渲染后端返回的icon图标 3.1. 全局注册 icon 组件 3.2. 组件实现  3.3. 使用 

    2024年02月07日
    浏览(43)
  • vue3-ts- element-plus新增组件-过滤

     新增组件-所有值为空时过滤   提交: 

    2024年02月11日
    浏览(35)
  • 使用 Vite + Vue3 + Element-Plus + Pinia + Ts 搭建 Vue3 项目

    Vite 需要 Node.js 版本 14.18+,16+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。 首先 npm 输入: Project name :项目名称 Select a framework :选择一个框架 Select a variant :选择 ts 或者 js 输入项目名称后选择 vue 选择

    2024年02月09日
    浏览(43)
  • vue3 - element-plus 上传各种 word pdf 文件、图片视频并上传到服务器功能效果,示例代码开箱即用。

    在 vue3 项目中,使用 element plus 组件库的 el-upload 上传组件,进行文件、图片图像的上传功能示例。 可直接复制,再改个接口地址。 在这里上传

    2024年02月15日
    浏览(54)
  • Vue3+TS+Vite创建项目,并导入Element-plus和Sass

    1.桌面新建一个文件夹Vue3-app 打开编辑器导入文件夹,编辑器打开终端输入或者命令行工具cd到项目目录下输入 npm init vue@latest 回车运行 这里我选择了TS+Vite来开发,并选择安装路由 2.cd到 vue-project目录下 输入 npm install 回车运行 3.安装完成后 输入 npm run dev 回车运行 浏览器打开

    2024年02月16日
    浏览(44)
  • 详解Vite创建Vue3项目+vue-router+ts+vite+element-plus

    前言 在之前的文章中写过“Vue3+TS+ElementPlus的安装和使用教程【详细讲解】”,但那篇文章写的是创建vue3的项目没有使用到Vite构建工具进行创建还是使用的常规webpacket构建工具进行创建的。提到Vite和webpacket的时候我们可以简单说一下。 Vite 和 Webpack 都是现代化的前端构建工

    2024年01月18日
    浏览(43)
  • 从0开始搭建一个vue3+vite+ts+pinia+element-plus的项目

    前言:vue3+ts+vite大家已经都开始用了,最近也在学习,基本上是零基础开始ts的学习,很多语法知识是边写边查,没有系统的学习ts。此处展示从零开始,搭建的一个框架,方便拿来即用! 其中框架选择vue,语言选择typeScript 项目启动成功以后如下所示: 为了方便日常工作中

    2024年02月06日
    浏览(46)
  • vue3+ts+element-plus实际开发之导出表格和不同类型之间相互赋值

    1. 安装依赖 npm run xlsx 2. 引入,import * as XLSX from “xlsx”; 3. 报错找不到模块“xlsx”或其相应的类型声明 修改成大写就好了 import * as XLSX from \\\'XLSX\\\' ,如果没有报提示就直接用 4. 使用导出文件 //---- 导出表 1. 直接用a标签下载 鼠标移入样式,点击自动下载 2. 有特殊数据需要解析

    2024年02月15日
    浏览(32)
  • vue3 element-plus el-form的二次封装

    form表单的二次封装 vue3 element-plus el-form的二次封装 属性名 类型 默认值 说明 data Array [] 页面展示数据内容 onChange Function false 表单事件 bindProps Object {} 表单属性 formRef Object {} 表单ref ruleForm Object {} 数据

    2024年02月13日
    浏览(42)
  • vue3+ts+element-plus 之使用node.js对接mysql进行表格数据展示

    * 初始化node 查看node是否安装 node -v 初始化命令 npm init 初始化配置解释如下: 完成后会有一个package.json文件 * 安装可能用到的依赖 根据需求安装,我这里需要对接mysql,安装依赖 ,我是一次性安装完,后边会直接使用,也可以边安装边使用。如下 安装成功如下: * 配置文件

    2024年02月15日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包