需求

最近在做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" /> + 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-uploadclass="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"><divclass="items-wrap"ref="contentWrap":style="wrapHeight 'height: auto' : `height: 60px;`":class="{ noHidden: noHidden }"><uploadfile-itemv-for="(item, index) in file-list":key="index":file="item"@cancel="cancelFile":showDel="true"class="mr20"></uploadfile-item></div><divclass="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">下载</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-dialogtitle="图片预览"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 = truethis.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" />首先:不需要再安装其他预览资源加载包,所有的预览都是通过windom.open()方法打开一个新窗口预览。PDF的预览时使用的office官方的接口文档:`https://view.officeapps.live.com/op/view.aspx?src=${data}就可以预览PDF文档了。图片的预览是通过dialog的弹窗实现的,就简单一个弹窗rar和zip不支持预览,只能下载查看

如果有帮助请别忘了点赞、评论、互动、关注哦~