使用vue和element-ui上传图片及视频文件方式

目录
  • 效果图
  • 上传后
  • 图片上传
  • 视频上传

项目使用vue+element-ui,实现了表单多图上传图片,上传视频,以及表单图片回显,视频回显,表格渲染图片等功能

效果图

上传后

图片可回显,视频可播放,,这时候全部缓存在页面,并没有提交到后端服务器,只要到用户提交的那一步才确定上传,减低不必要的服务器开支

图片上传

前端缓存base64方便回显,以及后台上传,视频上传则使用file类型去上传(base64对视频编码会导致请求参数过长)

<!--
	描述:图片上传,  基于 element-ui 组件
-->
<template>
  <div>
    <div class="upload">
      <div
        class="img_mode"
        v-for="(item, index) in path_list"
        :key="index"
        :style="'height:' + height + ';width:' + width"
        @mouseenter.stop="over(index)"
        @mouseleave="out"
      >
        <img :src="item.path" />
        <transition name="el-fade-in-linear">
          <div v-show="curIndex == index" class="transition-box">
            <div class="mask">
              <i class="el-icon-delete" @click="remove(index)"></i>
              <i
                class="el-icon-zoom-in"
                @click="enlarge(index)"
                v-if="bigBox"
              ></i>
            </div>
          </div>
        </transition>
      </div>
      <div
        class="select_mode"
        :style="'height:' + height + ';width:' + width"
        v-if="isLimit"
        v-loading="load"
      >
        <input
          type="file"
          @change="change($event)"
          ref="file"
          :multiple="isMultiple"
        />
        <img
          :src="selectImgPath || selectImg"
          :width="selectImgWidth || '50%'"
        />
      </div>
    </div>
    <el-dialog :visible.sync="isShow" center>
      <div class="big_img_mode">
        <img :src="bigImg" />
      </div>
    </el-dialog>
  </div>
</template>
<script>
//这里是图片上传时候的图标,可以自行替换
import selectImg from "../../assets/img/selectedImg.png";
export default {
  props: {
    height: String,
    width: String, // 组件预览图片大小
    selectImgPath: String, // 未选择图片时显示的图片
    selectImgWidth: String,
    bigBox: Boolean, // 是否显示图片放大按钮
    /* 多图上传 */
    isMultiple: Boolean, // 是否可多选图片
    limit_size: Number, // 限制上传数量
    quality: Number, // 图片压缩率
    limit: Number, // 图片超过 (limit * 1024)kb 将进行压缩
    isCompress: Boolean, // 是否开启图片压缩
    /* 单图上传 */
    isChangeUpload: false, // 是否选择文件后触发上传
    action: "", // 单图上传路径,
    param: "", // 上传的参数名
    data: Object, // 单图上传附带的参数
    success: Function, // 单图上传成功后的回调函数
  },
  data() {
    return {
      selectImg,
      path_list: [],
      curIndex: -1,
      bigImg: "",
      isShow: false,
      isLimit: true,
      load: false,
    };
  },
  watch: {
    path_list() {
      if (this.path_list.length >= this.limit_size) {
        this.isLimit = false;
      } else {
        this.isLimit = true;
      }
      this.load = false;
      this.curIndex = -1;
    },
  },
  mounted() {},
  methods: {
    // 鼠标移入
    over(index) {
      this.curIndex = index;
    },
    // 鼠标移出
    out() {
      this.curIndex = -1;
    },
    // 选择图片
    change() {
      this.load = true;
      var That = this;
      let fileList = this.$refs.file.files;
      if (!fileList.length) {
        this.load = false;
        return;
      }
      for (var i = 0; i < fileList.length; i++) {
        var file_temp = fileList[i];
        let name = file_temp.name.toLowerCase();
        if (!/\.(jpg|jpeg|image|img|png|bmp|)$/.test(name)) {
          this.$message.warning("请上传图片");
          this.clean();
        }
        let reader = new FileReader(); //html5读文件
        reader.fileName = file_temp.name;
        reader.readAsDataURL(file_temp);
        reader.onload = (data) => {
          //读取完毕后调用接口
          // 图片压缩
          this.canvasDataURL(
            data.currentTarget.result,
            { fileSize: data.total, quality: this.quality },
            (baseCode) => {
              if (this.isChangeUpload) {
                this.changeUpload(baseCode, reader.fileName);
              } else {
                this.path_list.push({
                  path: baseCode,
                  fileName: reader.fileName,
                });
              }
            }
          );
        };
      }
      this.$emit("change", this.path_list);
    },
    // 移除图片
    remove(index) {
      this.path_list.splice(index, 1);
    },
    //清空图片
    clean() {
      this.path_list = [];
    },
    //后台添加图片
    addPathList(urls) {
      console.log(urls);
      let arr = urls.split(",");
      if (arr.length == 1) {
        let obj = { path: this.$common.getUrl() + arr[0] };
        this.path_list.splice(0, 1, obj);
      } else {
        arr.forEach((item, index) => {
          let obj2 = { path: this.$common.getUrl() + item };
          this.path_list.splice(index, 1, obj2);
        });
      }
    },
    //后台添加图片
    addUrlPathList(urls) {
      console.log(urls);
      let arr = urls.split(";");
      console.log("数组" + arr);
      if (arr.length == 1) {
        let obj = { path: this.$common.getUrl() + arr[0] };
        this.path_list.splice(0, 1, obj);
      } else {
        arr.forEach((item, index) => {
          let obj2 = { path: this.$common.getUrl() + item };
          this.path_list.splice(index, 1, obj2);
        });
      }
    },
    //重新图片
    clearImgs() {
      this.path_list = [];
    },
    // 放大图片
    enlarge(index) {
      this.isShow = true;
      this.bigImg = this.path_list[index].path;
    },
    // 单图上传
    changeUpload(baseCode, fileName) {
      let formData = new FormData();
      formData.append(this.param, baseCode);
      formData.append("fileName", fileName);
      for (var item in this.data) {
        formData.append(item, this.data[item]);
      }
      this.$axios
        .post(this.action, formData)
        .then((response) => {
          if (response.data.message == "succ") {
            this.success(); // 上传成功后的回调函数
          }
          this.load = false;
        })
        .catch((e) => {
          console.log(e);
          this.load = false;
        });
    },
    /**
     * @uploadPath 上传的路径
     * @path_list  base64 集合, 为空则调用 this.path_list
     * @callback 上传成功后的回调函数, 返回上传成功后的路径
     */
    upload(uploadPath, path_list, callback) {
      var formData = new FormData();
      if (!path_list) {
        this.path_list.forEach((item) => {
          formData.append(
            "files",
            this.convertBase64UrlToBlob(item.path),
            item.fileName
          );
        });
      } else {
        path_list.forEach((item) => {
          formData.append(
            "files",
            this.convertBase64UrlToBlob(item.path),
            item.fileName
          );
        });
      }
      let headers = { headers: { "Content-Type": "multipart/form-data" } };
      this.$axios
        .post(uploadPath, formData, headers)
        .then((response) => {
          if (response.data.message == "succ") {
            // 回调函数返回上传成功后的路径
            callback("succ", response.data.result);
          } else {
            this.$message.error("文件上传失败");
            callback("error");
          }
        })
        .catch((error) => {
          if (error == "timeout") {
            this.$message.error("文件上传超时");
          }
          this.$message.error("文件上传异常");
          console.log(error);
          callback("error");
        });
    },
    getName() {
      return this.path_list.fileName;
    },
    // 获取base64 集合
    getPaths() {
      let paths = [];
      if (this.path_list.length == 1) {
        return this.path_list[0].path;
      } else if (this.path_list.length == 0) {
        return "";
      } else {
        for (var i = 0; i < this.path_list.length; i++) {
          paths.push(this.path_list[i].path);
          // if(i == 0){
          // 	paths = this.path_list[i].path
          // }else{
          // 	arr.push(this.path_list[i].path)
          // }
        }
      }
      return paths;
    },
    photoCompress() {},
    // 图片压缩
    canvasDataURL(path, obj, callback) {
      var suffix = path.match(/\/(\S*);/)[1];
      var img = new Image();
      img.src = path;
      img.onload = function () {
        var that = this;
        // 默认按比例压缩
        var w = that.width,
          h = that.height,
          scale = w / h;
        w = obj.width || w;
        h = obj.height || w / scale;
        var quality = 0.7; // 默认图片质量为0.7
        this.limit = this.limit ? this.limit : 1; // 默认为超过1M 进行压缩
        //生成canvas
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        // 创建属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量
        if (obj.quality && obj.quality <= 1 && obj.quality > 0)
          quality = obj.quality;
        var base64 = "";
        if (this.isCompress) {
          // quality值越小,所绘制出的图像越模糊
          base64 =
            obj.fileSize > this.limit * 1024
              ? canvas.toDataURL("image" + suffix, quality)
              : canvas.toDataURL("image" + suffix);
        } else {
          base64 = canvas.toDataURL("image/" + suffix, quality);
        }
        // 回调函数返回base64的值
        callback(base64);
      };
    },
    // base64 转 blob 对象
    convertBase64UrlToBlob(urlData) {
      //去掉url的头,并转换为byte
      var bytes = window.atob(urlData.split(",")[1]);
      //处理异常,将ascii码小于0的转换为大于0
      var ab = new ArrayBuffer(bytes.length);
      var ia = new Uint8Array(ab);
      for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], { type: "image/png" });
    },
  },
};
</script>
<style scoped="upload">
.upload {
  width: 100%;
  overflow: hidden;
  display: flex;
  flex-wrap: wrap;
  padding: 10px 4px;
  box-sizing: border-box;
}
.select_mode {
  width: 120px;
  height: 120px;
  display: flex;
  justify-content: center;
  align-items: center;
  /* border: 1px dashed #cfcfcf; */
  border-radius: 10px;
  position: relative;
  box-sizing: border-box;
  /* background-color: #fcfbfe; */
}
.select_mode:hover {
  /* border: 1px dashed #00A2E9; */
}
.select_mode img {
  width: 100%;
  position: absolute;
  z-index: 1;
  cursor: pointer;
}
.select_mode input[type="file"] {
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  z-index: 2;
}
.img_mode {
  margin-right: 10px;
  margin-bottom: 10px;
  box-shadow: 0px 1px 5px #cccccc;
  position: relative;
}
.mask {
  background: rgb(0, 0, 0, 0.5);
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0px;
  left: 0px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.img_mode,
.img_mode img {
  height: 120px;
  max-width: 200px;
}
.mask i {
  font-family: element-icons !important;
  color: #ffffff;
  font-size: 25px;
  margin: 0px 8px;
  cursor: pointer;
}
.big_img_mode {
  text-align: center;
  width: 100%;
  height: 100%;
  max-height: 400px;
}
.big_img_mode img {
  max-width: 400px;
  max-height: 400px;
}
</style>

使用方法:

引入上面的模块,然后在 components里面注册,即可用标签使用

import Upload from "../../../components/utils/Upload.vue";
components: { editor: editor, Upload },
<el-form-item label="轮播图:" prop="img">
//这里面的参数在上面的模块里面去看,ref就是你绑定的对象
    <upload
       ref="addBanner"
       :limit_size="4"
       :isCompress="true"
       :bigBox="true"
     ></upload>
</el-form-item>

上传之前获取base64图片编码,存到表单中,然后直接提交给后台

this.addForm.img = this.$refs.addBanner.getPaths();

注意:这里上传后会是一段base64字符串,如果是多图,会是一段字符串数组,后端可以直接用jsonArray接收

视频上传

//表单
 <el-form-item label="视频:" prop="video">
   <video class="video" controls v-if="videoShow" :src="videoShow" />
   <input
     ref="videoFile"
     @change="fileChange($event)"
     type="file"
     id="video_file"
     accept="video/*"
   />
</el-form-item>
//方法
fileChange(e) {
      var files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;
      let name = files[0].name.toLowerCase();
      if (
        !/\.(avi|wmv|mpeg|mp4|mov|mkv|flv|f4v|m4v|rmvb|rm|3gp|dat|ts|mts|vob)$/.test(
          name
        )
      ) {
        this.$message.warning("请上传视频");
        return;
      }
      if (files[0].size > 1024 * 1024 * 20) {
        this.$message.warning("视频大小不能大于20M");
        return;
      }
      //这里是file文件
      this.addForm.video = files[0];
      var reader = new FileReader();
      reader.readAsDataURL(files[0]);
      reader.onload = () => {
      //这里是一段base64,用于视频回显用
        this.videoShow = reader.result;
      };
},

表格渲染相关

表格内多图渲染

这段代码的意思是渲染当前行img字段的列表,遍历生成img图片标签

因为img字段返回的是一个数组,不能直接渲染,所以加上一个JSON.parse解析一下

另外加了一个判断最多渲染不超过三张,防止界面过长超出

<el-table-column prop="name" label="轮播图" align="center"  width="300px">
          <template slot-scope="scope">
            <el-image
              v-for="(item,index) in JSON.parse(scope.row.img)"
              :src="item" 
              v-if="index<3"
              style="width: 30%;height: 100%;margin-right: 5px"
            ></el-image>
          </template>
</el-table-column>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)

    效果 若使用 请自行优化代码和样式 不显示图片/播放视频音频代码如下 <template> <div> <div v-on:dragover="tts" v-on:drop="ttrs" style="width: 800px;height: 200px;border: 1px solid black;font-size: 40px;line-height: 200px"> {{dt}} </div>

  • vue vantUI实现文件(图片、文档、视频、音频)上传(多文件)

    说在前面 网上有很多种文件上传的方法,根据公司最近的业务需求,要求实现多种文件的上传,在实现过程中,查阅了很多资料,最后,终于把功能实现了,开心! <template> <div> <v-header :left-text="`上传${columnName}`"></v-header> <div class="upload"> <div v-if="columnName === '视频'&q

  • Vue图片与文字混输的实现方法

    前言 用多了JQuery,习惯了使用JQuery的API操作DOM,几乎忘记了原生JS对DOM操作,今天在项目中遇到了文字和图片混输的情况,第一个想到的办法是用textarea实现,结果发现实现不了图片输入,然后想着找个富文本编辑器的插件实现,深思熟虑之后,我的需求好像也没那么复杂,不至于引用个插件,看了掘金的发布沸点功能,然后就模仿了其作法,于是就有了这篇文章的分享.先给大家展示下最后实现的效果

  • vue-cropper插件实现图片截取上传组件封装

    基于vue-cropper插件实现图片截取上传组件封装的具体代码,供大家参考,具体内容如下 需求场景: 后台开发需要上传图片并进行相应比例尺寸图片的截取,本组件开发采用Ant Design Vue组件库搭配vue-cropper插件进行封装 实现如下 html <template> <div> <a-upload name="avatar" list-type="picture-card" class="avatar-uplo

  • vue截取视频第一帧的图片问题

    已拿到视频的url,现在要截取视频的第一帧,作为封面图片. 在网上找了几种,都是空白.稍微改了一下,终于成功了. 基本就是用cavas进行绘制,解决一下跨域问题,截视频第一帧,然后根据视频原本的宽高进行绘制,最后转一下图片格式即可. 代码如下: <template> ...... <video :src="videoSrc" id="upvideo">您的浏览器不支持 video 标签.</video> ...... <sp

  • 使用vue和element-ui上传图片及视频文件方式

    目录 效果图 上传后 图片上传 视频上传 项目使用vue+element-ui,实现了表单多图上传图片,上传视频,以及表单图片回显,视频回显,表格渲染图片等功能 效果图 上传后 图片可回显,视频可播放,,这时候全部缓存在页面,并没有提交到后端服务器,只要到用户提交的那一步才确定上传,减低不必要的服务器开支 图片上传 前端缓存base64方便回显,以及后台上传,视频上传则使用file类型去上传(base64对视频编码会导致请求参数过长) <!-- 描述:图片上传, 基于 element-ui 组件

  • VUE 实现element upload上传图片到阿里云

    首先安装依赖 cnpm install ali-oss 封装client 若是想减小打包后静态资源大小,可在index.html引入:(然后在client.js里注释掉const OSS = require('ali-oss')) <script src="http://gosspublic.alicdn.com/aliyun-oss-sdk-4.4.4.min.js"></script> const OSS = require('ali-oss') expor

  • vue+axios+element ui 实现全局loading加载示例

    实现全局loading加载 分析需求,我们只需要在请求发起的时候开始loading,响应结束的时候关闭loading,就这么简单 对不对? import axios from 'axios'; import { Message, Loading } from 'element-ui'; import Cookies from 'js-cookie'; import router from '@/router/index' let loading //定义loading变量 function st

  • vue使用element实现上传图片和修改图片功能

    目录 前言 一.应用场景 1.上传图片并进行放大预览 2.图片上传代码 二.修改已经上传的图片,并展示到图片列表中 1.效果展示(先展示原来的图片,再上传新图片,也可删除原来的图片) 2.编辑代码 总结 前言 开发后台管理项目时,遇到了上传图片的模块,这个比较简单,但是保存后的图片需要编辑就比较麻烦了,自己记录一下,也分享一下,多多指教 一.应用场景 1.上传图片并进行放大预览 2.图片上传代码 我这里的实现是直接将图片上传到接口,成功后返回图片路径,表单提交时,后台要路径拼成的字符串格式,类似

  • vue项目element UI input框扫码枪扫描过快出现数据丢失问题及解决方案

    目录 项目需求: 解决方案探索 错误代码: 问题就出在 解决方法 完整代码 如下 项目需求: 输入框要掉两个接口,根据第一个验证接口返回的code,弹不同的框,点击弹框确认再掉第二个接口 根据客户现场反应,扫描枪快速扫描会出现 料号前几位字符丢失 不完整的问题.于是开始了测试之路. 解决方案探索 1.首先考虑 ,可能是因为扫描过快,服务端接口还没返回过来,输入框就已经清空了值 导致条码有丢失字符的现象,所以我这边做了一个缓存,将输入框的值存到一个数组中去,定时上传到接口. [x]2.考虑到可能是

  • python cv2读取rtsp实时码流按时生成连续视频文件方式

    我就废话不多说了,直接上代码吧! # coding: utf-8 import datetime import cv2 import os ip = '192.168.3.160'.replace(".", "_") rtsp = 'rtsp://admin:admin@192.168.3.160:554/1/1' # 初始化摄像头 cap = cv2.VideoCapture(rtsp) fourcc = cv2.VideoWriter_fourcc(*'XVID

  • vue实现把接口单独存放在一个文件方式

    第一步:在src/router目录下,建立一个js文件(文件名:httpConfig.js): 第二步:在httpConfig.js文件里面写上 const aa = 'http://192.168.1.123';//本地测试 const config = { bb: aa+ '/article/articleListPage',//所需的接口 } //需要让外部拿到 export default config; 第三步:掉接口 _this.$http({ url: _this.$httpCon

  • vue3.0安装Element ui及矢量图使用方式

    在此只关注v3的安装及使用,如果想了解v2可移步到其官网:https://element.eleme.io/#/zh-CN/component/installation v3官网:https://element-plus.org/zh-CN/guide/installation.html 使用element ui时vue2和vue3的区别 安装命令 main.js中引入文件有所不同 使用icon时v2不需要安装,v3需安装 v2和v3在vue文件中使用icon时编写方式有所不同 icon在v2中

  • 关于element ui中el-cascader的使用方式

    目录 element ui中el-cascader使用 例→ 代码 element中el-cascader使用及自定义key名 element ui中el-cascader使用 要想实现进入页面直接选中选择器中的选项 例→ 那v-model绑定的值必须是数组形式的!!(element ui官方文档中没提到这一点好像,我也是试了很多次才发现的) 代码 <el-form-item label="分类:" prop="region" class="regi

  • Vue 前端导出后端返回的excel文件方式

    目录 前端导出后端返回的excel文件 处理文件的下载(后端Excel导出) 后端文件流 通过 Blob 下载 拼接 URL 下载 前端导出后端返回的excel文件 在网上搜索了一番之后,决定采用Blob方式,这也是大家推荐的一种的方式,特此做下记录. 页面: 先筛选,向后端请求接口返回excel文件,代码如下: const apiUrl = this.Global.httpUrl + '/laima/export/new/exportTackOutOrder' console.log(this

随机推荐