el-upload上传文件

简介: el-upload上传文件

前言

公司和学校项目都用到了上传文件的功能,记录一下。

准备

express实现的上传接口

const express = require('express');
​
// 文件上传模块
const multiparty = require('multiparty')
​
// 提供跨域资源请求
const cors = require('cors')
​
// 文件操作
const fs = require('fs')
​
const app = express();
​
app.use(cors());
​
app.get('/policy', (req, res) => {
  res.json({
    code: 200,
    msg: '成功',
    url: '/upload',
    filename: 'clz'
  })
});
​
app.post('/upload', (req, res) => {
  let form = new multiparty.Form()
​
  // 配置文件存储路径
  form.uploadDir = './upload'
​
  form.parse(req, (err, fields, files) => {
    // 解析formData
​
    for (const file of files.file) {
      const newPath = form.uploadDir + '/' + file.originalFilename
​
      // renameSync(oldPath, newPath):同步重命名文件,oldPath使用默认上传路径,newPath则是想要保存到的路径
      fs.renameSync(file.path, newPath);
    }
​
    res.json({
      code: 200,
      msg: '上传成功'
    })
  })
});
​
app.listen(8088, () => {
  console.log('http://localhost:8088/');
});

如果需要使用,自行查阅express用法,也可以到本人博客中查看简单教程。

开始

简单使用版本

<template>
  <el-upload
    action="http://localhost:8088/upload"
    :show-file-list="true"
    :on-success="handleSuccess"
    :on-error="handleError"
  >
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
import { ElMessage } from "element-plus";
​
const handleSuccess = (res, file, files) => {
  console.log(res);
  console.log(file, files);
​
  new ElMessage({
    type: "success",
    message: "上传成功",
  });
};
​
const handleError = (error, file, files) => {
  console.log(error);
  console.log(file, files);
  ElMessage.error("上传失败");
};
</script>
​
<style lang="less" scoped>
</style>
​

解释下上面的属性:

  • action:请求URL
  • show-file-list:是否展文件列表(如果没上传成功,则会闪现一下,再消失)
  • on-success:文件上传成功钩子

    • 参数:
    • res:后端返回的成功响应数据(响应状态为成功时)
    • file:上传的文件
    • files:成功上传的文件列表
  • on-success:文件上传失败钩子

    • 参数:
    • error:错误对象,内容是后端返回的响应数据(响应状态为失败时,如状态码为500)
    • file:上传的文件
    • files:成功上传的文件列表

file

接下来,去后端设置的路径去看看有没有成功保存上传的文件。

image-20220508120156380

添加token

这个比较简单,因为element-plus也封装好了,只需要使用headers属性,去设置请求头即可

<el-upload
  action="http://localhost:8088/upload"
  :headers="{ token: '12345' }"
>
  <el-button type="primary">上传图片</el-button>
</el-upload>

image-20220508120607213

上传前获取签名再上传

有时候并不是直接上传就可以的,比如一开始并没有上传路径,需要调用获取签名接口来获取上传路径。这个时候就可以使用我们的上传文件之前的钩子before-upload。在上传前调用获取签名的接口,用拿到的url去修改,上传路径,就能够上传了。

<template>
  <el-upload :action="url" :before-upload="getPolicy">
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
import axios from "axios";
import { reactive, ref } from "vue";
​
const url = ref("");
​
const getPolicy = () => {
  return new Promise((resolve, reject) => {
    axios
      .get("http://localhost:8088/policy")
      .then((res) => {
        const { data } = res;
​
        if (data.code === 200) {
          url.value = `http://localhost:8088${data.url}`;
​
          resolve();
        }
      })
      .catch((error) => {
        reject(error);
      });
  });
};
</script>
​
<style lang="less" scoped>
</style>

image-20220508134523663

手动上传

我们上面的例子都是选中文件后,就会上传,但是有时候我们会有点击按钮才去上传的需求,这个时候就需要结合auto-uploadsubmit来实现手动上传了。先设置auto-uploadfalse,取消自动上传,这个时候选中图片后就没有上传了,所以我们在按钮的点击事件中,还得使用DOM去调用submit方法去手动上传。

<template>
  <el-upload
    ref="upload"
    action="http://localhost:8088/upload"
    :auto-upload="false"
  >
    <el-button type="primary">上传图片</el-button>
  </el-upload>
​
  <el-button type="primary" @click="confirm">确定</el-button>
</template>
​
<script setup>
import { getCurrentInstance } from "vue";
​
const { proxy } = getCurrentInstance();
​
const confirm = () => {
  proxy.$refs.upload.submit();
};
</script>
​
<style lang="less" scoped>
</style>

file

上传的时候修改文件名

情境:调用签名接口时也给你返回一个文件名,前端在上传的时候需要把文件名改掉再上传,让服务器保存的是规范的文件名。

首先,先说一下结论:无法通过修改File对象的name属性,实现重命名

在上传前钩子中修改File对象的name属性

<template>
  <el-upload
    action="http://localhost:8088/upload"
    :before-upload="getPolicy"
  >
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
// 上传前钩子
const getPolicy = (file) => {
  console.log(file);
​
  file.name = "clz.png";    // 如果在上传前钩子中对文件的name属性进行修改,则会导致上传不了。而且不报错,难以发现问题所在。
​
  console.log(file.name);
};
</script>
​
<style lang="less" scoped>
</style>

file

毫无波澜。

上传文件时修改

通过http-request属性,覆盖默认的上传行为。

<template>
  <el-upload action="http://localhost:8088/upload" :http-request="httpRequest">
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
const httpRequest = ({ file }) => {
  console.log(file);
  file.name = "clz.png";
};
</script>
​
<style lang="less" scoped>
</style>

file

直接报错

解决方案

既然不能直接修改File对象的name属性来实现重命名操作,那么应该怎么办呢?

这个时候就需要通过new File构造函数去再创建一个文件,创建的同时更改名字。

<template>
  <el-upload action="http://localhost:8088/upload" :http-request="httpRequest">
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
const httpRequest = ({ file }) => {
  console.log(file);
​
  const cloneFile = new File([file], "clz.png");
​
  console.log(cloneFile);
};
</script>
​
<style lang="less" scoped>
</style>

注意:如果是更改一个文件的文件名的话,File的构造函数第一个参数应该是包住file的数组

image-20220508164215907

但是这个时候,又有问题了,我们已经使用http-request覆盖默认的上传的行为了,所以我们还得重新实现上传。

上传文件首先需要formData对象,然后给formData添加上数据,在把formData通过接口发出去即可。

<template>
  <el-upload action="#" :http-request="httpRequest">
    <el-button type="primary">上传图片</el-button>
  </el-upload>
</template>
​
<script setup>
import axios from "axios";
import { ElMessage } from "element-plus";
​
const httpRequest = ({ file }) => {
  console.log(file);
​
  const cloneFile = new File([file], "clz.png");
​
  const formData = new FormData();
  formData.append("file", cloneFile);
​
  axios.post("http://localhost:8088/upload", formData).then((res) => {
    if (res === 200) {
      new ElMessage({
        type: "success",
        message: "上传成功",
      });
    }
  });
};
</script>
​
<style lang="less" scoped>
</style>

image-20220508165110118

小贴士

上面已经说出解决方法了,但是,重命名一般不会帮你把文件后缀都给改掉。所以这个时候可以通过正则表达式把后缀给取出来。

const houzhui = file.name.replace(/.+./, "");
const newFile = new File([file], filename+houzhui);

一次请求上传多个文件

el-upload默认一个请求上传一个文件。需要上传多个文件首先得添加multiple属性。

file

上面的例子中,我们可以发现,我们上面选中了两个文件,点击确定,上传图片时调用了两次上传接口。

既然el-upload默认一个请求上传一个文件,那么我们就不要使用el-upload的上传方法就行了。点击确定按钮时,去调用一个上传文件方法。

因为我们点击确定时,需要获取选中的文件,所以需要有file-list属性,保存选中的文件。

<template>
  <el-upload
    ref="upload"
    action="#"
    multiple
    :file-list="fileList"
    :auto-upload="false"
  >
    <el-button type="primary">上传图片</el-button>
  </el-upload>
​
  <el-button type="primary" @click="confirm">确定</el-button>
</template>

点击确定按钮,会触发confirm事件,实现一个请求上传多个文件的关键就在这,这个时候创建一个formData对象,遍历选中的文件列表,通过append添加到formData上。最后在调用uploadFile函数,真正把文件上传上去。

const fileList = reactive([]);
​
const confirm = () => {
  const formData = new FormData();
​
  console.log(fileList);
​
  for (const file of fileList) {
    formData.append("file", file.raw);
  }
​
  uploadFiles(formData);
};
​
function uploadFiles(data) {
  axios.post("http://localhost:8088/upload", data).then((res) => {
    if (res === 200) {
      new ElMessage({
        type: "success",
        message: "上传成功",
      });
    }
  });
}

file

小技能

获取图片的宽高像素

// 创建Image对象
const img = new Image();
​
// 设置图片的src
img.src = 'https://www.clzczh.top/medias/featureimages/19.png';
​
// 添加load事件,图片加载完成后执行
img.onload = () => {
  // 获取图片的宽高像素
  console.log(img.width, img.height);
};
目录
相关文章
|
前端开发 JavaScript 安全
【前端相关】elementui使用el-upload组件实现自定义上传
【前端相关】elementui使用el-upload组件实现自定义上传
3496 0
|
存储 前端开发 Java
Element el-upload 文件上传/图片上传/拖拽上传/附带参数/附带请求头部详解
文目录 1. 前言 2. 基本用法 2.1 前端部分 2.2 后端部分 2.3 获取后端返回信息 3. 外观功能介绍 3.1 拖拽上传 3.2 显示图片 3.3 设置文件列表样式 3.4 显示提示信息 4. 事件功能介绍 4.1 限制上传文件数量 4.2 限制上传文件类型和大小 4.3 移除文件处理 4.4 手动上传 5. 附带参数 6. 附带请求头部 7. 小结
8044 0
|
JavaScript 前端开发
Element_文件上传&&多个文件上传
Element_文件上传&&多个文件上传
1190 0
el-upload图片上传,删除
el-upload是ElementUI中的一个组件,可以用来实现图片上传功能。下面是一个基本的el-upload的示例代码:
851 0
|
前端开发 JavaScript 容器
使用echarts遇到的问题及解决
使用echarts遇到的问题及解决
1088 0
|
JavaScript
js---三元表达式详解
js---三元表达式详解
530 0
Element UI 上传文件 el-upload —— 手动上传文件,限制上传文件数量,文件类型校验等
Element UI 上传文件 el-upload —— 手动上传文件,限制上传文件数量,文件类型校验等
4727 0
|
JavaScript
Vue路由传参实战指南:三种常用方法示例演示
Vue路由传参实战指南:三种常用方法示例演示
818 0
element UI【解决方案】消息弹框被对话框遮挡($message消息框被dialog或$alert遮罩)
element UI【解决方案】消息弹框被对话框遮挡($message消息框被dialog或$alert遮罩)
866 3