docx、pdf、xlsx文件的预览组件

package.json里面引入依赖,进行安装

"dependencies": {
    "@vue-office/docx": "^1.3.1",
    "@vue-office/excel": "^1.4.6",
    "@vue-office/pdf": "^1.5.5",
    "@vue/composition-api": "^1.7.2",
    }

组件代码

<template>
  <div class="office">
    <vue-office-docx 
        class="flex1"
        v-if="preview.fileType == 'docx'"
        :src="preview.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <vue-office-pdf 
        class="flex1"
        v-else-if="preview.fileType == 'pdf'"
        :src="preview.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <vue-office-excel
        class="flex1"
        v-else-if="preview.fileType == 'xlsx'"
        :src="preview.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <div 
      v-else
      class="flex1"
      :style="{height:height + 'px'}">
      <slot name="nopreview" :data="preview">
        <el-empty :description="`${preview.name}暂时无法预览`">
          <!-- <el-button type="primary">下载</el-button> -->
        </el-empty>
      </slot>
    </div>
    <div class="download" v-if="hasDownload">
      <el-link icon="el-icon-download" type="primary" 
        :href="`${preview.url}`"
        :underline="false" 
        target="_blank"
        class="mr5 mt5 mb5"
      ></el-link>
    </div>
  </div>
</template>

<script>
//引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
//引入相关样式
import '@vue-office/docx/lib/index.css'
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
import VueOfficePdf from '@vue-office/pdf'
export default {
  name:"FilePreview",
  data(){
    return{
    }
  },
  props:{
    /**
     * fileType 文件类型 docx pdf xlsx 
     * name 文件名称 暂时没有用到
     * title 标题 暂时没有用到
     * url 文件的地址 
     */
    preview:{
      fileType:'',
      name:'', 
      title:'',
      url:'', 
    },
    // 预览框的高度
    height:{
      type:Number,
      default:720
    },
    // 是否有下载功能
    hasDownload:{
      type:Boolean,
      default:false
    }

  },
  components: {
    VueOfficeDocx,
    VueOfficeExcel,
    VueOfficePdf
  },
  methods:{
    // 渲染完成函数
    rendered(){
      this.$emit('rendered')
    }
  }
}
</script>

<style scoped>
.office{
  width: 100%;
  position: relative;
}
.download{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: fit-content;
    background: #e8eaed;
    display: flex;
    justify-content: flex-end;
    /* border-radius: 10px; */
  }
/* 自动宽度 */
.flex1{
  flex:1
}

</style>

正常引入组件的方式使用

import FilePreview from '@/components/FilePreview/index.vue' //引入预览组件
我个人的preview数据

    goView(item){
      this.dialogVisible = true
      let fileString = item.file
        if(fileString.includes('.docx')){
          this.preview.fileType = 'docx'
        }else if(fileString.includes('.pdf')){
          this.preview.fileType = 'pdf'
        }else if(fileString.includes('.xlsx')){
          this.preview.fileType = 'xlsx'
        }else{
          this.preview.fileType = ''
        }
        this.preview.title = item.title + '附件预览'
        this.preview.url = this.preview.fileType != '' ? this.baseUrl + item.file : ''
    }

如果有更多场景使用欢迎评论改进

进一步完善功能,传入多个对象,切换

<template>
  <div class="office">
    <vue-office-docx 
        class="flex1"
        v-if="previews.fileType == 'docx'"
        :src="previews.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <vue-office-pdf 
        class="flex1"
        v-else-if="previews.fileType == 'pdf'"
        :src="previews.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <vue-office-excel
        class="flex1"
        v-else-if="previews.fileType == 'xlsx'"
        :src="previews.url"
        :style="{height:height + 'px'}"
        @rendered="rendered"
    />
    <div v-else-if="['png','jpg','jpeg'].includes(previews.fileType)">
      <slot name="image" :data="previews"></slot>
    </div>
    <div 
      v-else
      class="flex1"
      :style="{height:height + 'px'}">
      <slot name="nopreview" :data="previews">
        <el-empty :description="`${previews.name}暂时无法预览`">
          <!-- <el-button type="primary">下载</el-button> -->
        </el-empty>
      </slot>
    </div>
    <div class="download" v-if="hasDownload">
      <el-link icon="el-icon-download" type="primary" 
        :href="`${previews.url}`"
        :underline="false" 
        target="_blank"
        class="mr5 mt5 mb5"
      ></el-link>
    </div>
    <div v-if="fileResources.length>1">
      <el-button type="success" icon="el-icon-arrow-left" class="pre" :disabled="cutIndex == 0" circle @click="pre()"></el-button>
      <el-button type="success" icon="el-icon-arrow-right" class="next" :disabled="cutIndex == fileResources.length-1" circle @click="next()"></el-button>
    </div>
  </div>
</template>

<script>
//引入VueOfficeDocx组件
import VueOfficeDocx from '@vue-office/docx'
//引入相关样式
import '@vue-office/docx/lib/index.css'
//引入VueOfficeExcel组件
import VueOfficeExcel from '@vue-office/excel'
//引入相关样式
import '@vue-office/excel/lib/index.css'
import VueOfficePdf from '@vue-office/pdf'
export default {
  name:"FilePreview",
  data(){
    return{
      previews:{
        fileType:'',
        name:'', 
        title:'',
        url:'', 
      },
      fileResources:[],
      cutIndex:null
    }
  },
  props:{
    /**
     * fileType 文件类型 docx pdf xlsx 
     * name 文件名称 暂时没有用到
     * title 标题 暂时没有用到
     * url 文件的地址 
     */
    preview:{
      fileType:'',
      name:'', 
      title:'',
      url:'', 
    },
    // 预览框的高度
    height:{
      type:Number,
      default:720
    },
    // 是否有下载功能
    hasDownload:{
      type:Boolean,
      default:false
    },
    // 多文件预览数据源
    fileResource:{
      type:Array,
      default:()=>{return[]}
    },
    // 请求的前缀
    baseUrl:{
      type:String,
      default:process.env.VUE_APP_BASE_API
    }

  },
  components: {
    VueOfficeDocx,
    VueOfficeExcel,
    VueOfficePdf
  },
  watch:{
    fileResource:{
      handler(newVal, oldVal) {
        if(this.fileResource.length != 0){
          this.splitRequestPath()
        }
        
      },
      deep: true, // 加这个属性,深度监听
    },
    preview:{
      handler(newVal, oldVal) {
        console.log("preview🚀 ~ handler ~ newVal:", newVal,oldVal)
        this.previews = this.preview
        
      },
      deep: true, // 加这个属性,深度监听
    }
  },
  mounted(){
    console.log("🚀 ~ mounted ~ mounted:")
    this.previews = this.preview
    console.log("🚀 ~ mounted ~ this.previews:", this.previews)
    if(this.fileResource.length != 0){
      this.splitRequestPath()
    }
  },
  destroyed(){
    this.previews = {}
    this.preview = {}
    this.fileResources = []
    this.fileResource = []
  },
  methods:{
    // 渲染完成函数
    rendered(){
      this.$emit('rendered')
    },
    // 拼接请求路径
    splitRequestPath(){
      this.fileResources = []
      if(this.baseUrl){
        this.fileResource.forEach((element,index) => {
          if(this.preview.url.includes(element)){
            this.cutIndex = index
          }
          let info = this.returnFileInfo(element)
          this.fileResources.push({
            ...info,
            url:this.baseUrl + info.url
          })          
        });
      }
    },
    // 根据路径分解出文件类型,名称,标题,url等等
    returnFileInfo(path){
      console.log("🚀 ~ returnFileInfo ~ path:", path)
      let o = {
          fileType:'',
          name:'', 
          title:'',
          url:path, 
        }
      if (path.lastIndexOf("/") > -1) {
        o.name = path.slice(path.lastIndexOf("/") + 1);
        let index = path.slice(path.lastIndexOf("/") + 1).lastIndexOf(".")
        o.fileType = o.name.slice(index + 1)
      } else {
        o.name = "";
      }
      return o;
    },
    next(){
      this.previews = this.fileResources[++this.cutIndex]
      this.$forceUpdate()
    },
    pre(){
      this.previews = this.fileResources[--this.cutIndex]
      this.$forceUpdate()
    }
  }
}
</script>

<style scoped>
.office{
  width: 100%;
  position: relative;
}
.download{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: fit-content;
    background: #e8eaed;
    display: flex;
    justify-content: flex-end;
    /* border-radius: 10px; */
  }
/* 自动宽度 */
.flex1{
  flex:1
}
.pre{
  position: absolute;
  top:50%;
  
}
.next{
  position: absolute;
  top:50%;
  right: 10px;
}
</style>
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值