根据element改造的文件预览组件:支持图片、doc、xlsx、ppt、PDF、视频等文件预览

element-ui框架的预览只能预览图片,其他文件不支持,不支持就自己封装一个吧,前提条件后端返回的文件预览支持访问

首先在component中新建文件:FilePreview.vue:内容如下

<template>
  <!-- 预览组件 -->
  <div class="FilePreview">
    <div class="container">
      <!-- 渲染层 -->
      <div class="object" v-if="TragetObj.format == 'jpg' || TragetObj.format == 'png' || TragetObj.format == 'JPG' || TragetObj.format == 'PNG' || TragetObj.format == 'jpeg'|| TragetObj.format == 'tiff'|| TragetObj.format == 'swf'|| TragetObj.format == 'gif'|| TragetObj.format == 'JPEG'|| TragetObj.format == 'GIF'"
        ref="imgWrap" @mousewheel.prevent="rollImg">   
          <img class="Target modal-img" ref="img" @mousedown="moveImg" :src="TragetObj.url" alt="" >
      </div>
      <!-- 视频 -->
      <div class="object" v-else-if="TragetObj.format == 'webm' || TragetObj.format == 'mov' || TragetObj.format == 'mp4'">
        <video class="Target" controls="controls" width="1200" height="700" :src="TragetObj.url" autoplay ref="videoref" >
          您的浏览器不支持。
        </video>
      </div>
      <!-- 附件 -->
      <div class="object" v-else>
        <iframe class="Target" frameborder="1" index-render="1" scrolling="yes" height="890.15" width="1220.4" :src="TragetObj.url"></iframe>
      </div>
      <!-- 操作按钮 -->
      <div class="viewer_btn">
        <ul>
          <li @click="onClickEnlarge">
            <i class="el-icon-zoom-in"></i>
          </li>
          <li @click="onClickNarrow">
            <i class="el-icon-zoom-out"></i>
          </li>
          <li @click="onClickReturnOriginal">
            <i class="el-icon-c-scale-to-original"></i>
          </li>
          <!-- 下载 -->
          <li v-if="TragetObj.downUrl">
            <a :href="TragetObj.downUrl">
              <i class="el-icon-download"></i>
            </a>
          </li>
            <!-- <li>
              <i class="el-icon-full-screen"></i>
          </li> -->
        </ul>
      </div>
      <!--下一个 -->
      <div class="next" v-if="NumIndex < this.FilePresAll.length - 1"  @click="onClickNext">
        <i class="el-icon-arrow-right"></i>
      </div>
      <!-- 上一个 -->
      <div class="previous" v-if="NumIndex != 0" @click="onCLickPrevious">
        <i class="el-icon-arrow-left"></i>
      </div>
      <!-- 关闭按钮 -->
      <div class="close" @click="onClickClose">
        <i class="el-icon-close"></i>
      </div>
    </div>
    <div class="viewer__mask" @click.stop="onClickClose">
      <div  v-loading="loadingFlag"></div>
    </div>
  </div>
</template>

<script>
export default {
    props:['TragetPic', 'FilePreAll'],
    data(){
      return{
        EleWidth:"",
        EleHeight:"", 
        TragetObj:{}, // 目标对象
        FilePresAll:[], // 渲染数组
        NumIndex:0, // 当前渲染目标的下标
        loadingFlag:false, // 加载
      }
    },
    created(){
      this.TragetObj = this.TragetPic // 目标对象
      this.FilePresAll = this.FilePreAll // 渲染数组
    },
    mounted () {
      if(this.EleWidth == ""){
        if(this.TragetObj.format != 'jpg' && this.TragetObj.format != 'png' && this.TragetObj.format != 'JPG' && this.TragetObj.format != 'PNG' && this.TragetObj.format != 'jpeg' && this.TragetObj.format != 'tiff' && this.TragetObj.format != 'swf' && this.TragetObj.format != 'gif' && this.TragetObj.format != 'JPEG' && this.TragetObj.format != 'GIF'){
          this.loadingFlag = true
        }else{
          this.loadingFlag = false
        }
      }
      // 获取目标元素值
      let  Target = document.getElementsByClassName("Target")[0];
      this.EleWidth = Target.offsetWidth
      this.EleHeight = Target.offsetHeight
      if(this.EleWidth != ""){
        this.loadingFlag = false
      }
      // console.log(this.EleWidth)

      // 获取当前目标的下标值
      this.FilePresAll.forEach((item, index)=>{
        if(item.FileName == this.TragetObj.FileName){
          this.NumIndex = index
        }
      })
    },

    beforeUpdate () {
      if(this.TragetObj.format != 'jpg' && this.TragetObj.format != 'png' && this.TragetObj.format != 'JPG' && this.TragetObj.format != 'PNG' && this.TragetObj.format != 'jpeg' && this.TragetObj.format != 'tiff' && this.TragetObj.format != 'swf' && this.TragetObj.format != 'gif' && this.TragetObj.format != 'JPEG' && this.TragetObj.format != 'GIF'){
        this.loadingFlag = true
      }else{
        this.loadingFlag = false
      }
      this.$nextTick(()=>{
        let eleParent = document.querySelector('.object')
        // 获取目标元素值
        let Target = eleParent.children[0]
        this.EleWidth = Target.offsetWidth
        this.EleHeight = Target.offsetHeight
        // console.log(Target)
          
      })
    },
    methods:{
      // 放大功能
      onClickEnlarge(){
        let Target=document.getElementsByClassName("Target")[0];
        Target.style.height=Target.height*1.1+'px';
        Target.style.width=Target.width*1.1+'px';
      },

      // 缩小功能
      onClickNarrow(){
        let Target=document.getElementsByClassName("Target")[0];
        Target.style.height=Target.height/1.1+'px';
        Target.style.width=Target.width/1.1+'px';
      },

      // 返回原图大小
      onClickReturnOriginal(){
        let Target=document.getElementsByClassName("Target")[0];
        Target.style.height=this.EleHeight+'px';
        Target.style.width=this.EleWidth +'px';
      },

      // 点击下一个事件
      onClickNext(){
        if(this.NumIndex < this.FilePresAll.length - 1){
          this.NumIndex++
          this.TragetObj = this.FilePresAll[this.NumIndex]
        }
      },

      // 点击上一个事件
      onCLickPrevious(){
        if(this.NumIndex != 0){
          this.NumIndex--
          this.TragetObj = this.FilePresAll[this.NumIndex]
        }
      },

      // 关闭按钮
      onClickClose(){
        // 关闭视频声音
        if(this.$refs.videoref != undefined){
          this.$refs.videoref.pause()
        }
        this.$emit('Close', false)
      },

      // 拖拽图片事件
      moveImg (e) {
        e.preventDefault()
        // 获取元素
        let imgWrap = this.$refs.imgWrap
        let img = this.$refs.img
        let x = e.pageX - img.offsetLeft
        let y = e.pageY - img.offsetTop
        // 添加鼠标移动事件
        imgWrap.addEventListener('mousemove', move)
        function move (e) {
          img.style.left = e.pageX - x + 'px'
          img.style.top = e.pageY - y + 'px'
        }
        // 添加鼠标抬起事件,鼠标抬起,将事件移除
        img.addEventListener('mouseup', () => {
          imgWrap.removeEventListener('mousemove', move)
        })
        // 鼠标离开父级元素,把事件移除
        imgWrap.addEventListener('mouseout', () => {
          imgWrap.removeEventListener('mousemove', move)
        })
      },

      // 鼠标滚动缩放图片事件
      rollImg (event) {
        /* 获取当前页面的缩放比 若未设置zoom缩放比,则为默认100%,即1,原图大小 */
        let zoom = parseInt(this.$refs.img.style.zoom) || 100
        /* event.wheelDelta 获取滚轮滚动值并将滚动值叠加给缩放比zoom wheelDelta统一为±120,其中正数表示为向上滚动,负数表示向下滚动 */
        zoom += event.wheelDelta / 12
        /* 最小范围 和 最大范围 的图片缩放尺度 */
        if (zoom >= 40 && zoom < 500) {
            this.$refs.img.style.zoom = zoom + '%'
        }
        return false
      },
    }
}
</script>

<style lang="scss" scoped>
.FilePreview{
  position: fixed;
  left: 0;
  top: 0;
  z-index: 8888;
  height: 100%;
  width: 100%;
  .container{
    display: flex;
    flex-direction: column;
    align-items:center;/*由于flex-direction: column,因此align-items代表的是水平方向*/
    justify-content: center;/*由于flex-direction: column,因此justify-content代表的是垂直方向*/
    position: relative;
    left: 0;
    top: 0;
    height: 100%;
    width: 100%;
    .object{
      z-index: 10001;
      display: flex;
      flex-direction: column;
      align-items:center;/*由于flex-direction: column,因此align-items代表的是水平方向*/
      justify-content: center;/*由于flex-direction: column,因此justify-content代表的是垂直方向*/
      margin: 25px;
      .modal-img {
          position: absolute;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
          max-width: 100%;
          cursor: move;
          &-wrap {
          position: relative;
          width: 960px;
          height: 560px;
          overflow: hidden;
        }
      }
    }
    .viewer_btn{
      position: absolute;
      left: 50%;
      bottom: 20px;
      z-index: 10020;
      -webkit-transform: translateX(-50%);
      transform: translateX(-50%);
      // width: 250px;
      height: 44px;
      padding: 0 23px;
      background-color: #606266;
      border-color: #fff;
      border-radius: 22px;
      ul{
        padding: 0;
        margin: 0;
        display: flex;
        justify-content: space-between;
        align-items: center;
        li{
          font-size: 30px;
          color: #fff;
          padding: 6px 10px;
          cursor: pointer;
        }
      }
    }
    .next{
      position: absolute;
      top: 50%;
      right: 15px;
      z-index: 10020;
      font-size: 30px; 
      height: 44px;
      width: 44px;
      line-height: 44px;
      text-align: center;
      background: #606266;
      color: #fff;
      border-radius: 50%;
      cursor: pointer;
    }
    .previous{
      position: absolute;
      top: 50%;
      left: 15px;
      z-index: 10020;
      font-size: 30px;
      height: 44px;
      width: 44px;
      line-height: 44px;
      text-align: center;
      background: #606266;
      color: #fff;
      border-radius: 50%;
      cursor: pointer; 
    }
    .close{
      position: absolute;
      top: 15px;
      right: 15px;
      z-index: 10020;
      font-size: 30px;
      cursor: pointer;
      background: #606266;
      border-radius: 50%;
      width: 44px;
      height: 44px;
      line-height: 44px;
      text-align: center;
    }
  }
  .viewer__mask{
    position: absolute;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.9);
    top: 0;
    left: 0;
    z-index: 8888;
    display: flex;
    flex-direction: column;
    align-items:center;/*由于flex-direction: column,因此align-items代表的是水平方向*/
    justify-content: center;/*由于flex-direction: column,因此justify-content代表的是垂直方向*/
  }
}
</style>
<style>
/* 关闭图标 */
.FilePreview .el-icon-close{   
  color: #fff;
}
</style>

在需要使用的页面引入组件:

import FilePreview from '@/pageCommon/FilePreview.vue' // 预览组件;
components: {
    FilePreview,
  },
  data(){
  	return{
  		// 预览数据
      IsPreview:false, // 控制预览弹窗字段
      timers:"", //时间戳
      FilePreAll:[], // 预览数组
      TragetPic:{}, // 当前点击的预览文件对象
  	}
  },
methods: {
	// 打开预览
    onClickOpenPreview(val){
      this.TragetPic  = { // 当前点击的文件
        FileName: val.name, // 文件名称
        name: val.name, // 文件名称(可以不传)
        id:val.guid_name, // 文件id
        format:val.extensions, // 文件格式
        url: this.previewFile + val.guid_name,  // 预览地址
        downUrl:"", // 下载地址
      } // 目标对象

      this.tableData.forEach(item =>{ // 需要预览的文件数组(可以传空数组就是单张预览)
        let obj = {
          FileName: item.name,
          name: item.name,
          id:item.guid_name,
          format:item.extensions,
          url: this.previewFile + item.guid_name,
          downUrl:"",
        }
        this.FilePreAll.push(obj)
      })

     
      this.IsPreview = true // 打开预览弹窗
      this.timers = new Date().getTime() // 刷新预览地址
    },
	// 关闭预览
    onClickClosePreview(val){
      this.IsPreview = val  // 由组件内部传入的关闭数据赋值关闭
    },
}

在template中使用:

<!-- 预览 -->
    <div class="preview" v-if="IsPreview">
      <file-preview :key="timers" :TragetPic="TragetPic" :FilePreAll="FilePreAll" @Close="onClickClosePreview"></file-preview>
    </div>

最后看效果图:
图片预览:
在这里插入图片描述
文件预览:
在这里插入图片描述
在这里插入图片描述

虽然封装的不是很好,文件预览主要是使用了iframe,同时还支持视频的预览,先将就用着,后续再进行更好的优化,更简易化的使用,目前还是有些复杂。不懂的可以评论咨询哈,谢谢支持;

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
在Vue中预览docx、docpdf、xls、xlsx文件,可以使用第三方库来实现。 对于docx、doc、xls、xlsx文件,可以使用`js-xlsx`库来进行解析和预览。该库可以将Excel文件转换为JSON格式,而对于Word文件,可以使用`docx.js`库来进行解析和预览。 对于pdf文件,可以使用`pdf.js`库来进行预览。该库可以通过Canvas将PDF文件渲染成图片,然后在Vue中显示。 下面是一个示例代码,演示如何使用上述库来预览不同类型的文件: ```html <template> <div> <div v-if="fileType === 'docx' || fileType === 'doc'"> <div v-html="docContent"></div> </div> <div v-else-if="fileType === 'xls' || fileType === 'xlsx'"> <table> <tr v-for="row in excelData"> <td v-for="cell in row">{{ cell }}</td> </tr> </table> </div> <div v-else-if="fileType === 'pdf'"> <canvas ref="pdfCanvas"></canvas> </div> </div> </template> <script> import XLSX from 'xlsx'; import Docx from 'docx'; import pdfjsLib from 'pdfjs-dist'; export default { data() { return { fileType: '', docContent: '', excelData: [], }; }, mounted() { // 根据文件类型进行解析和预览 if (this.fileType === 'docx' || this.fileType === 'doc') { const reader = new FileReader(); reader.onload = (event) => { const content = event.target.result; const doc = new Docx(); doc.load(content); this.docContent = doc.getHtml(); }; reader.readAsArrayBuffer(this.file); } else if (this.fileType === 'xls' || this.fileType === 'xlsx') { const reader = new FileReader(); reader.onload = (event) => { const content = event.target.result; const workbook = XLSX.read(content, { type: 'array' }); const sheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[sheetName]; this.excelData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); }; reader.readAsArrayBuffer(this.file); } else if (this.fileType === 'pdf') { const canvas = this.$refs.pdfCanvas; const ctx = canvas.getContext('2d'); pdfjsLib.getDocument(this.file).promise.then((pdf) => { pdf.getPage(1).then((page) => { const viewport = page.getViewport({ scale: 1.5 }); canvas.height = viewport.height; canvas.width = viewport.width; page.render({ canvasContext: ctx, viewport, }); }); }); } }, props: { file: { type: File, required: true, }, }, created() { // 根据文件后缀名判断文件类型 const fileExtension = this.file.name.split('.').pop(); if (fileExtension === 'docx' || fileExtension === 'doc') { this.fileType = 'docx'; } else if (fileExtension === 'xls' || fileExtension === 'xlsx') { this.fileType = 'xls'; } else if (fileExtension === 'pdf') { this.fileType = 'pdf'; } }, }; </script> ``` 在上述代码中,根据文件后缀名判断文件类型,然后使用不同的库进行解析和预览。对于Word文件,使用`docx.js`库将文件解析为HTML格式,然后在Vue中显示;对于Excel文件,使用`js-xlsx`库将文件解析为JSON格式,然后在Vue中生成表格;对于PDF文件,使用`pdf.js`库将文件渲染成图片,然后在Vue中显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值