vue+el-upload 上传图片和视频小总结

Posted 南柯彡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue+el-upload 上传图片和视频小总结相关的知识,希望对你有一定的参考价值。

一、图片下标,判断,base64,获取img标签等问题

上传图片时用到的accept只会在用户点击上传时添加一个自定义文件类型,如添加了accept=".jpg,.png,",虽然会呈现出符合条件的文件,但用户仍可以通过点击所有文件类型来上传其他类型的文件,此时设置before-upload函数,

参考el-upload上传组件accept属性限制文件类型(案例详解)_辰兮要努力的博客-CSDN博客_el-upload accept 结果只有accept在生效,ElementUI el-upload上传图片限制, before-upload 不生效问题_老电影故事的博客-CSDN博客_beforeupload参考该文章发现自动把自动上传关闭导致这个问题,就只能绑定在on-change里;另外还有:on-exceed 加 limit执行上传限制长度的函数执行。

<el-form-item label="商品轮播图设置" label-width="160px">
          <p>商品轮播图</p>
          <p class="tips">
            仅支持上传图片,最少上传一张 最多可上传十张, 已上传
            <span> canonicalImage.length </span>
            / 10
          </p>
          <div class="form_canonicalImage">
            <el-upload
              action="#"
              list-type="picture-card"
              :auto-upload="false"
              :limit="10"
              :multiple="true"
              :file-list="canonicalImage"
              :on-change="uploadChange"
              :on-remove="handleRemove"
              :on-exceed="handleExceed"
              :on-preview="handlePreview"
              :before-remove="beforeRemove"
              :before-upload="beforeImageUpload" 
              ref="mYupload"             
              accept=".jpg,.png,"
            >
              <i slot="default" class="el-icon-plus"></i>
            </el-upload>
            <el-dialog :visible.sync="dialogVisible">
              <img width="100%" :src="dialogImageUrl" alt="" />
            </el-dialog>
          </div>
        </el-form-item>

methods中

    //删除之前的钩子
    beforeRemove(file, fileList) 
      return this.$confirm('删除该图片, 是否继续?', '提示', 
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        )               
    ,
    // 删除轮播图
    handleRemove(file, fileList) 
      this.canonicalImage = JSON.parse(JSON.stringify(fileList));
    ,
    //触发上传限制
    handleExceed() 
      this.$message.warning("上传超出限制!");
    ,
    //预览
    handlePreview(file) 
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    ,
    // 添加轮播图
    uploadChange(file, fileList) 
        //截取出文件末尾的类型       
      let fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1);
      const whiteList = ["jpg", "png"];
      const isLt2M = file.size / 1024 / 1024 < 4;
      if (whiteList.indexOf(fileSuffix) === -1) 
        this.$message.error("上传文件只能是jpg/png格式");
        
        fileList.pop();
        return false;
           
      else if (!isLt2M) 
        this.$message.error("上传文件大小不能超过 4MB");
        fileList.pop();
        return false;
      else
       
      this.uploadImage_loading = true;
      this.getBase64(file.raw).then((res) => 
        productcopyAPI
          .savefile(
            imagesBase64: res,
            filetype: "image",
            fileName: file.name,
            keyName: "keyName",
            ticket: this.ticket,
          )
          .then(( data ) => 
            fileList.forEach((item) => 
              item.uid == file.uid && (item.url = data.data[0].url);
            );
            this.canonicalImage = JSON.parse(JSON.stringify(fileList));
          )
          .catch((error) => 
            this.uploadImage_loading = false;
            this.$message.error(error);
          );
      );
      
    ,

    // 图片转base64
    getBase64(file) 
      return new Promise(function (resolve, reject) 
        let reader = new FileReader();
        let imgResult = "";
        reader.readAsDataURL(file);
        reader.onload = function () 
          imgResult = reader.result;
        ;
        reader.onerror = function (error) 
          reject(error);
        ;
        reader.onloadend = function () 
          resolve(imgResult);
        ;
      );
    ,

 

以及网络图片转base64格式的参考:vue网络图片url转Base64「建议收藏」 - 全栈程序员必看

//初始化时调用    
getimage() 
      this.$refs.mYupload.clearFiles();
      this.uploadImage_loading = true;
      let data = [];
      
      this.canonicalImage.forEach((item, i) => 
        if (item.url.includes("baidu")) 
          data.push( url: item.url, index: i );         
        else
          data = []
        
      );
      let num = 0;
      if(data[num])
        this.imageUrlToBase64(data, num);
            
    ,
    //网络图片url转换为base64
    imageUrlToBase64(data_, num) 
      //一定要置空!!!!
      this.base64Datas = [];
      let image = new Image();
      //解决跨域问题
      image.setAttribute("crossOrigin", "anonymous");
      
      let imageUrl = data_[num].url;    
      image.src = imageUrl;
      let that = this;
      //image.onload为异步加载
      image.onload = () => 
        var canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;
        var context = canvas.getContext("2d");
        context.drawImage(image, 0, 0, image.width, image.height);
        var quality = 0.8;
        //这里的dataurl就是base64类型
        var dataURL = canvas.toDataURL("image/jpeg", quality); //使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
        //数组存放图片base64
        this.base64Datas = dataURL;
        productcopyAPI
          .savefile(
            imagesBase64: this.base64Datas,
            filetype: "image",
            fileName: "file.name",
            keyName: "keyName",
            ticket: this.ticket,
          )
          .then(( data ) => 
            data_[num].url = data.data[0].url;
            if(num <data_.length-1)
                num++               
                this.imageUrlToBase64(data_, num);
             else
              data_.forEach((item,i)=> 
                
                this.canonicalImage[item.index].url = item.url;
              );
             

            this.uploadImage_loading = false;
          )
          .catch((error) => 
            
            this.uploadImage_loading = false;
            this.$message.error(error);
          );
      ;
       
    ,

 转换格式的时候,一定要将中间的变量置空!另外为防止根据默认下标有的是网络图片有的不是,导致删除错误,还需要在对象中将该图片现在图片列表中的下标当做添加index属性以当做key值

破解循环中的异步操作,不能直接用for循环,在我看来有效的办法方法体内的num++,再回调此函数

以及在商品详情中仍需要借此转换成base64的格式,但需要先用正则表达式将所有img标签里的src获取到,其他的基本大同小异了。

//正则匹配详情里所有img标签    
      var regex0 = new RegExp(/(?<=(img src="))[^"]*?(?=")/gims); //eslint-disable-line
      this.detailimgtag = this.outdetail.match(regex0);
      let data= []
        let num = 0
      this.detailimgtag.forEach((item,i)=>
         if (item.includes("baidu")) 
          data.push(url:item,index:i)
          
      )

二、formdata的方式上传视频,原生axios上传,进度条等问题

视频(也是文件)用formdata的方式上传报错,参考:vue上传文件formData入参为空,接口请求500_静静心中的梦_66的博客-CSDN博客用到了原生axios上传,另外在接口中上传和返回时间过长,需要添加一个进度条展示,参考:element ui 图片自定义上传进度条消失问题_我是顾昀峰的博客-CSDN博客_vue和elementui视频上传成功后进度条消失但展示中只会有上传进度的展示,返回以及添加至页面还需要等待很久,进度条以及到100%了。

// 视频上传函数
    uploadVideo(file,fileList) 
      //截取出文件末尾的类型
      let fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1);
      const blackList = ["mp4"];
      const isLt2M = file.size / 1024 / 1024 < 10;
      if (blackList.indexOf(fileSuffix) === -1) 
        this.$message.error("上传文件只能是mp4格式");
        
        // this.canonicalVideo = fileList.slice(0,1) 
        
        return false;
      else if (!isLt2M) 
        this.$message.error("上传文件大小不能超过 10MB");
        // this.canonicalVideo = fileList.slice(0,1)
        return false;
      else 
      this.isShowUploadVideo = false;
    this.videoFlag = true;
      var formdata = new FormData();
      formdata.append("file", file.raw);
      formdata.append("filetype", "video");
      formdata.append("ticket", this.ticket);
      formdata.append("keyname", "keyName");
      formdata.append("filenames", file.name);
      this.$axios.post('https://aicaigoufuwuapi.yiwangtui.com/api/upload/UploadFile',formdata,
        onUploadProgress: progressEvent => 
          if(progressEvent.lengthComputable)
            var val = parseInt(progressEvent.loaded / progressEvent.total * 100 ).toFixed(0)
            this.videoUploadPercent = Math.floor(val)-1;
          
          
          )    
      .then(res=>
          this.canonicalVideo=[
            src:res.data.data.data[0].url,
            video_id:''
            ];
            this.videoFlag = false;
            this.videoUploadPercent  = 100;
        )
        .catch((error)=>
          this.$message.error(error+',请重新上传!');         
          this.videoFlag = false;
          this.videoUploadPercent = 0;
        )
      
     
    ,

elementUI使用el-upload上传文件写法总结及避坑,上传图片/视频到本地/服务器以及回显+删除

Element Upload 上传

Element Upload官方文档:el-upload
具体细节只看官方文档,本篇主要介绍避坑点和用法总结

注意点以及坑

  • 本地上传想要回显图片视频,使用on-success是没办法再在上传后获取到本地文件路径后进行回显的,因为只有在上传的action成功,即不报错的情况下才会调用,本地上传用的action="#这个接口不存在,所以也不会上传成功,更不会调用获取到文件参数进行回显

  • 如果想要先在本地进行回显,然后再上传的话,需要使用on-change钩子(还需:auto-upload ="false")获取文件本地路径,再生成一个formData传给后端上传文件的接口,

  • 官方文档中提供的上传图片接口https://jsonplaceholder.typicode.com/posts/现已无法使用

  • 下面给大家总结几种常用的上传文件方法

el-upload上传文件用法总结

1. 上传单张图片到服务器并进行回显,不可删除只能替换

这种上传单张图片的运行场景一般是上传头像,没有删除功能,只能进行替换

<el-upload
  class="avatar-uploader"
  action="后端上传接口"
  :show-file-list="false"
  :on-success="handleAvatarSuccess"
  :before-upload="beforeAvatarUpload">
  <img v-if="imageUrl" :src="imageUrl" class="avatar">
  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>

<style>
 /deep/ .avatar-uploader .el-upload 
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  
  .avatar-uploader .el-upload:hover 
    border-color: #409EFF;
  
  .avatar-uploader-icon 
    font-size: 28px;
    color: #8c939d;
    width: 178px;
    height: 178px;
    line-height: 178px;
    text-align: center;
  
  .avatar 
    width: 178px;
    height: 178px;
    display: block;
  
</style>

<script>
  export default 
    data() 
      return 
        imageUrl: ''
      ;
    ,
    methods: 
      // 上传成功后的回显
      handleAvatarSuccess(res, file) 
        this.imageUrl = URL.createObjectURL(file.raw);
      ,
      // 上传前对类型大小的验证
      beforeAvatarUpload(file) 
        const isJPG = file.type === 'image/jpeg';
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG) 
          this.$message.error('上传头像图片只能是 JPG 格式!');
        
        if (!isLt2M) 
          this.$message.error('上传头像图片大小不能超过 2MB!');
        
        return isJPG && isLt2M;
      
    
  
</script>

2. 拖拽上传单张图片到本地回显再上传到服务器,可删除

可以手动上传,也可以拖拽上传,图片可以在没有后端上传接口时进行回显,可删除
template:

<el-upload
          drag
          action="#"
          :show-file-list="false"
          :auto-upload="false"
          :on-change="uploadFile"
          accept="image/jpg,image/jpeg,image/png"
        >
          <i
            v-if="imageUrl1"
            class="el-icon-circle-close deleteImg"
            @click.stop="handleRemove1"
          ></i>
          <img v-if="imageUrl1" :src="imageUrl1" class="avatar" />

          <div v-else>
            <i
              class="el-icon-picture"
              style="margin-top: 40px; font-size: 40px; color: #999a9c"
            ></i>
            <div class="el-upload__text1">上传图片</div>
            <div class="el-upload__text">* 建议尺寸比例2.2:1,不超过4m,</div>
            <div class="el-upload__text">格式为png、jpeg或jpg</div>
          </div>
        </el-upload>
<style scoped>
.deleteImg 
  font-size: 30px;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 999;

</style>

data:

 data() 
      return 
        imageUrl1: ''
      ;
    ,

method:

 uploadFile(item) 
      console.log(item);

      let formData = new FormData();
      let file = item.raw;
      this.imageUrl1 = URL.createObjectURL(file);
      formData.append("file", file);
      // 传formData给后台就行
      // 比如
      // 接口(formData).then(res=>
          // this.videoUrl=res.url
      // )
    ,
    // 删除只需清空imageUrl1即可
   handleRemove1(file, fileList) 
      // console.log(file, fileList);
      this.imageUrl1 = "";
    ,


3. 多图上传到服务器,可回显预览删除

list-type="picture-card"hover会自动有预览删除菜单,不需自己写样式,绑定事件即可

<el-upload
  action="后端接口地址"
  list-type="picture-card"
  :on-preview="handlePictureCardPreview"
  :on-remove="handleRemove">
  <i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
  <img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<script>
  export default 
    data() 
      return 
        dialogImageUrl: '',
        dialogVisible: false
      ;
    ,
    methods: 
      handleRemove(file, fileList) 
        console.log(file, fileList);
      ,
      handlePictureCardPreview(file) 
        this.dialogImageUrl = file.url;
        this.dialogVisible = true;
      
    
  
</script>

以上是关于vue+el-upload 上传图片和视频小总结的主要内容,如果未能解决你的问题,请参考以下文章

el-upload配合vue-cropper实现上传图片前裁剪

el-upload配合vue-cropper实现上传图片前裁剪

el-upload上传视频没有封面

el-upload多文件上传

el-upload上传图片

elementui el-upload图片文件上传必传校验