vue+elementUI实现多文件上传与预览功能实战记录(word/PDF/图片/docx/doc/xlxs/txt)

 

需求

最近在做vue2.0+element UI的项目中遇到了一个需求:需求是多个文件上传的同时实现文件的在线预览功能。需求图如下:

看到这个需求的时候,小栗脑袋一炸。并不知道该如何下手,之前的实践项目中也并没有遇到相似的功能。因此也废了一番功夫想要实现这样一个功能。

首先先查看elemnt UI的官方文档发现,大部分的实现文件上传效果的功能,即使可以提供预览的功能,但是不能指定该功能的样式和内容有一定的局限性

然后小栗查找“多文件上传预览、PDF预览、word预览等关键词”,发现大部分的大佬的方法都是实现了图片预览,并没有实现多文件上传(也可能是因为我并没有找到相关的功能)。

因此小栗决定自己封装这个功能,并希望有朋友能在这个的基础上进行调整优化。期待你们的参与哦~~

话不多说,上才艺

 

实现需求

1、利用on-preview+window.open()实现简易版预览效果

查看element UI文档后发现el-upload里面有一个Attribute叫on-preview( 点击文件列表中已上传的文件时的钩子)是专门用来做文件预览的。点击文件就可以出发该函数。再结合window.open()方法可以直接完成一个新开窗口页的查看文件

代码如下:

HTML部分

//on-preview="Previewf"是必须的也是预览的关键
<el-upload
         class="upload-demo"
         :action="uploadUrl"
         :on-success="handlePreview"
         :on-remove="handleRemove"
         :before-upload="beforeUpload"
         :on-preview="Previewf"
         multiple
         :limit="5"
         :on-exceed="handleExceed"
         :file-list="file-list"
         :accept="accepts"
       >
         <el-button icon="el-icon-upload2" @click="uploadFileClick($event)"
           >上传文件</el-button
         >
       </el-upload>

methods部分

Previewf(file) {
    console.log(file);
    // window.open(file.response)
    if (file) {
      const addTypeArray = file.name.split(".");
      const addType = addTypeArray[addTypeArray.length - 1];
      console.log(addType);
      if (addType === "pdf") {
        let routeData = this.$router.resolve({
          path: "/insurancePdf",
          query: { url: file.response, showBack: false },
        });
        window.open(routeData.href, "_blank");
      }
      //".rar, .zip, .doc, .docx, .xls, .txt, .pdf, .jpg,  .png, .jpeg,"
      else if (addType === "doc" || addType === "docx" || addType === "xls") {
        window.open(
          "http://view.officeapps.live.com/op/view.aspx?src=" + file.response
        );
      } else if (addType === "txt") {
        window.open(file.response);
      } else if (["png", "jpg", "jpeg"].includes(addType)) {
        window.open(file.response);
      } else if (addType === "rar" || addType === "zip") {
        this.$message({
          message: "该文件类型暂不支持预览",
          type: "warning",
        });
         return false;
      }
    }
  },

功能预览

点击蓝色的文件部分就可以出现新开页面,这个简易的利用element UI就完成了这个功能啦~有没有觉得还是不那么难呢?

2、封装组件实现更完整的上传完成、预览功能

上述的功能可以完成预览,但与我们的需求有一部分的出入,不能够完全满足我的业务需求,因此在element UI的基础上,我进行了组件封装,以求完成以下功能:

话不多说,还是上代码:

HTML部分

/*
重点关注的代码:
	:show-file-list="false"
	ref="contentWrap
*/
<el-upload
          class="upload-demo"
          ref="uploadCom"
          :show-file-list="false"
          :action="uploadUrl"
          :on-success="onSuccess"
          :on-remove="handleRemove"
          :before-upload="beforeUpload"
          multiple
          :limit="5"
          :on-exceed="handleExceed"
          :file-list="file-list"
          :accept="accepts"
        >
          <el-button icon="el-icon-upload2" @click="uploadFileClick($event)"
            >将文件拖到此处,或<em>点击上传</em></el-button
          >
          <div slot="tip" class="el-upload__tip">
            支持扩展名:.rar .zip .doc .docx .xls .txt .pdf .jpg .png .jpeg,最多上传5个文件,每个大小不超过50Mb
          </div>
        </el-upload>
        <div class="flex mt20" v-if="file-list.length > 0">
              <div
                class="items-wrap"
                ref="contentWrap"
                :style="wrapHeight <= 70 ? 'height: auto' : `height: 60px;`"
                :class="{ noHidden: noHidden }"
              >
                <uploadfile-item
                  v-for="(item, index) in file-list"
                  :key="index"
                  :file="item"
                  @cancel="cancelFile"
                  :showDel="true"
                  class="mr20"
                ></uploadfile-item>
              </div>
              <div
                class="on-off"
                v-if="wrapHeight > 70"
                @click="noHidden = !noHidden"
              >
                {{ noHidden ? "收起" : "更多" }}
              </div>
            </div>

methods部分

import UploadfileItem from "";
export default {
components: {
  UploadfileItem,
},
data() {
  return {
    noHidden: true,
    wrapHeight: 0,
    delDialogitem: 0,
    imgLoad: false,
    centerDialogVisible: false,
   file-list:[],
    },
  };
},
methods: {
  cancelFile(file) {
    console.log(file);
  },

  // 上传文件只能添加五条
  uploadFileClick(event) {
    if (this.formLabelAlign.annex.length === 5) {
      this.$message({
        type: "warning",
        message: "最多只可以添加五条",
      });
      event.stopPropagation();
      return false;
    }
  },
  //
  onSuccess(response, file, annex) {
    if (!response) {
      this.$message.error("文件上传失败");
    } else {
      this.imgLoad = false;
      this.$message({
        message: "上传成功!",
        type: "success",
      });
    }
  },
 
  beforeUpload(file) {
   console.log(file);
  },
  handleExceed(files, ) {
		console.log(file);
},
};

UploadfileItem组件内容

<template>
<div class="file-style-box">
  <div class='upload-file-item'>
    <img :src="imgsrc[getEnd(file.fileName)]" alt="">
    <div>
      <p class='file-name'>
        <span class='name'>{{file.fileName}}</span>
        </p>
      <div class='option'>
        <span class='size'>{{file.size | toKB}}kb</span>
        <div>
          <span v-if='showDel && (isPdf(file) || isImg(file))' @click='previewHandler(file.url)' class='preview mr10'>预览</span>
          <a v-if='!showDel' @click='downLoadHandler' class='preview' :href="file.url" rel="external nofollow" >下载</a>
          <span v-if='showDel' class='mr10 success'>上传完成</span>
        </div>
      </div>
      <div class='delBtn' v-if='showDel' @click='cancelHanlder(file)'>
        <img src="@/assets/public/tips-err.png" alt="">
      </div>
    </div>
  </div>
  <el-dialog
    title="图片预览"
    width="800px"
    class="imgDlgBox"
    :visible.sync="imgDlgVisible"
    :close-on-click-modal="true"
    :modal="false"
    append-to-body
  >
    <img :src="imgUrl" alt="">
  </el-dialog>
</div>

</template>

<script>
export default {
props: {
  file: {
    type: Object,
    default: {}
  },
  showDel: {
    type: Boolean,
    default: false
  }
},
data() {
  return {
    imgDlgVisible: false,
    imgUrl: '',
    pdfUrl: '',
    imgsrc: {
    /*
		*imgsrc 是关于内部静态图片的显示的路径,需要自己设置
		*示例"xls": require('@/assets/image/xls.png'),
		xis的文件所需要加载的路径是;assets文件下的image文件夹下的xls.png
	*/
      "rar": require('@'),
      "zip": require('@'),
      "pdf": require('@'),
      "jpg": require('@'),
      "jpeg": require('@'),
      "png": require('@'),
      "doc": require('@'),
      "docx": require('@'),
      "txt": require('@'),
      "xls": require('@/assets/image/xls.png'),
    }
  }
},
filters: {
  toKB(val) {
    return (Number(val) / 1024).toFixed(0);
  }
},
methods: {
  cancelHanlder(item) {
    this.$emit('cancel', item)
  },
  previewHandler(data) {
    if (data) {
      const addTypeArray = data.split(".");
      const addType = addTypeArray[addTypeArray.length - 1];
      if (addType === "pdf") {
        let routeData = this.$router.resolve({ path: "/insurancePdf", query: { url: data, showBack: false } });
        window.open(routeData.href, '_blank');
      } else if (addType === "doc") {
        window.open(
          `https://view.officeapps.live.com/op/view.aspx?src=${data}`
        );
      } else if (addType === "txt") {
        window.open(`${data}`);
      } else if (['png','jpg','jpeg'].includes(addType)) { // 图片类型
        this.imgDlgVisible = true
        this.imgUrl = data
      }
    }
  },
}
</script>
<style lang='scss'>
.file-style-box {
padding: 10px 10px 0 0;
}
.imgDlgBox {
.el-dialog {
  .el-dialog__body {
    text-align: center;
    img {
      width: 700px;
      height: auto;
    }
  }
}
}
.upload-file-item {
background: #FAFAFA;
border-radius: 4px;
padding: 5px 10px;
margin-bottom: 10px;
display: flex;
font-size: 14px;
width: 236px;
box-sizing: border-box;
position: relative;
img {
  width: 32px;
  height: 40px;
  margin-top: 5px;
  margin-right: 10px;
}
.option {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.file-name {
  width: 163px;
  display: flex;
  flex-wrap: nowrap;
  font-size: 14px;
  color: #333;
  font-weight: 400;
  .name {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
  }
  .end {
    flex: 0 0 auto;
  }
  .el-button{
    border: none;
    padding: 0px;
    width: 90%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}
.size {
  color: #969696;
}
.success {
  color: #78C06E;
}
.delBtn {
  position: absolute;
  top: -14px;
  right: -18px;
  cursor: pointer;
  img {
    width:16px;
    height:16px
  }
}
// .del {
//   color: #E1251B;
//   cursor: pointer;
// }
.preview {
  color: #0286DF;
  cursor: pointer;
}
.mr10 {
  margin-right: 10px;
}
}
</style>

效果图

以上就可以实现实现多文件上传+预览(word/PDF/图片/docx/doc/xlxs/txt)啦,希望这样的实现方式也对你有帮助哦

 

追加关于问的比较多的问题回复

1、imgsrc路径

imgsrc: {
"rar": require('@/assets/material/zip.png'),
}
这个位置会报错

这里报错是因为此处的内容是静态资源,他是我们预览图片的一些细节,长成如下图所示:

你本地应该也需要配置这样一个文件夹的路径就可以啦。

2、显示原本elementui的那个上传样式

重点关注el- upload的代码
:show-file-list="false" //关闭原来的上传样式
ref="contentWrap //这个是通过父子组件传值将子组件的页面

3、file.response显示没有这个属性和方法

file.response是element UI的内置的组件的方法,引入element UI使用文件上传组件就可以实现
我之前写这儿的file.response 时候,有一个传递值也有问题,好像是element UI的钩子函数的问题,你先打印file。然后看是不是file.response ,不是的话 查看一下file的其他属性,有一个是跟回调相关的返回值
就可以解决啦

4、https://view.officeapps.live.com/op/view.aspx?src=${data}是干嘛的?预览PDF需要安装其他的插件吗?

首先:不需要再安装其他预览资源加载包,所有的预览都是通过windom.open()方法打开一个新窗口预览。
PDF的预览时使用的office官方的接口文档:`https://view.officeapps.live.com/op/view.aspx?src=${data}就可以预览PDF文档了。
图片的预览是通过dialog的弹窗实现的,就简单一个弹窗
rar和zip不支持预览,只能下载查看

 

总结

关于vue+elementUI实现多文件上传与预览功能(word/PDF/图片/docx/doc/xlxs/txt)的文章就介绍至此,更多相关vue+elementUI多文件上传预览内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 引言在这篇文章, 我们会创建一个 slider 滑块来对比两张图片。老样子,话不多说,先看效果。CSS.container {position: relative;}.resizer {ba ...