Vue 图片和PDF预览组件
可能只有我自己能看懂吧
就是一个vue的图片预览和PDF预览
<template>
<el-dialog :visible.sync="fileObj.isShowDialog" width="70%" top="7vh" v-dialogDrag :close-on-click-modal="false"
append-to-body custom-class="dialogImgBox" @close="close" :fullscreen="dialogFull" v-loading="loading">
<template slot="title">
<div style="display: flex;align-items:center;">
<span class="mr10">文件预览</span>
<i class="el-icon-full-screen" style="z-index: 999;color:red;cursor: pointer;font-size: 24px;"
@click="dialogFull? dialogFull=false: dialogFull=true"></i>
</div>
</template>
<div class="flex1 flex flexcolumn autoX autoY">
<div :class="['txtcenter', 'flex', 'mb15', $style.btnSize]">
<i class="el-icon-zoom-out cursor" @click="zoomOut" title="缩小" v-if="isImg"></i>
<i class="el-icon-zoom-in cursor ml20 mr20" @click="zoomIn" title="放大" v-if="isImg"></i>
<i class="el-icon-refresh-right cursor mrAuto" @click="rotateImg" title="图片右转" v-if="isImg"></i>
<i :class="[showFileList ? 'el-icon-s-unfold' : 'el-icon-s-fold', 'cursor']"
v-if="fileObj.fileList && fileObj.fileList.length > 1" @click="showFileList = !showFileList" title="图片列表"></i>
</div>
<div class="flex1 autoX autoY" v-if="isImg">
<img ref="dialogimg" :width="imgWidth" :height="imgHeight" v-if="fileurl" :src="fileurl"
:style="{ transform: 'rotate(' + imgrotate + 'deg)'}">
</div>
<!-- 加载全部页面的PDF是循环生成,不能指定ref,不能调用print打印方法 -->
<div class="flex1 autoX autoY" v-if="isPdf">
<pdf v-for="i in numPages" :key="i" :page="i" :src="fileurl" style="width: 100%; height: auto;"
@num-pages="pageCount = $event">
</pdf>
</div>
</div>
<!-- 右边的切换的文件名 -->
<div :class="[$style.dialogImgList, showFileList ? '' : $style.dialogImgListClose, 'autoY']"
v-if="fileObj.fileList && fileObj.fileList.length > 0">
<!-- <p @click="showFile({url: item.url, type: item.type, name: item.name})" :class="['cursor', 'mb15', name === item.name ? $style.active : '']" v-for="(item, index) of fileObj.fileList" :key="index"> {{ item.name }}</p> -->
<!-- <el-table
:data="fileObj.fileList"
style="width: 100%"
border
size="mini"
>
<el-table-column
prop="zlmc"
label="资料名称"
show-overflow-tooltip
>
</el-table-column>
<el-table-column
prop="name"
label="文件名称"
show-overflow-tooltip
>
<template slot-scope="scope">
<p
@click="showFile({url: scope.row.url, type: scope.row.type, name: scope.row.name})"
:class="['cursor', name === scope.row.name ? $style.active : '']"
>
{{ scope.row.name }}
</p>
</template>
</el-table-column>
</el-table> -->
<div class="el-tree-dialog">
<el-tree v-if="fileObj.isShowDialog" :data="dataList" :default-expand-all="true" :highlight-current="true"
:props="defaultProps" node-key="id" :current-node-key="currentId" @node-click="handleNodeClick">
</el-tree>
</div>
</div>
</el-dialog>
</template>
<script>
import '@/utils/drag.js'
// import ElDragDialog from '@/directive/el-drag-dialog'
import pdf from 'vue-pdf'
import CMapReaderFactory from "vue-pdf/src/CMapReaderFactory.js";
import { getArrayBufferFile, getBlobFile } from '@/api/permission/getFileStream'
export default {
name: 'FilePrwview',
// directives: {
// ElDragDialog
// },
props: {
fileObj: {
type: Object,
default: () => {
return {
fileList: [], // 文件列表, {url: '', name: '', type: ''}
isShowDialog: false, // 是否显示弹窗
url: '', // 是否有默认url传入
type: '',
name: '',
}
}
}
},
watch: {
fileObj: {
handler: function (val) {
if (val && val.isShowDialog) {
this.dataList = this.sameValueConcat(val.fileList)
this.dataList.forEach((item, index) => {
item.name = item.zlmc
item.id = item.id
})
this.currentId = val.id;
if (val.url) {
this.checkFileType(val)
} else {
this.showFile(val.fileList[0])
}
}
},
deep: true,
immediate: true
}
},
components: {
pdf
},
data() {
return {
fileurl: '',
isImg: false, // 是否是图片
isPdf: false, // 是否是文件
numPages: 0,
pageCount: 0,
showFileList: true,
imgWidth: 'auto',
imgHeight: 'auto',
imgrotate: 0,
name: '',
loading: false,
defaultProps: {
children: 'children',
label: 'name'
},
dataList: [],
currentId: '',
dialogFull: false,
}
},
methods: {
handleNodeClick(data) {
this.currentId = data.id;
this.showFile({ url: data.url, type: data.type, name: data.name, id: data.id })
},
sameValueConcat(data) {
let dataInfo = {}
data.forEach((item, index) => {
let { zlbh } = item
if (!dataInfo[zlbh]) {
dataInfo[zlbh] = {
zlbh,
zlmc: item.zlmc,
children: [],
}
}
dataInfo[zlbh].children.push(item)
})
let list = Object.values(dataInfo)
return list
},
// 查看图片
checkFileType(val) {
switch (val.type) {
case 'img':
this.showImg(val)
this.isPdf = false
this.isImg = true
break
case 'pdf':
this.showReadFile(val)
this.isImg = false
this.isPdf = true
break
}
},
async loadPdfHandler() {
// src为你服务器上存放pdf的路径
// this.pdfUrl = pdf.createLoadingTask(this.filepdfurl)
this.pdfUrl = pdf.createLoadingTask({
url: this.fileurl,
CMapReaderFactory
})
this.pdfUrl.promise.then(pdf => {
this.numPages = pdf.numPages // 这里拿到当前pdf总页数
this.loading = false
}).catch(err => {
console.log(err)
this.loading = false
})
},
showReadFile(val) {
if (val.url) {
console.log(val.url);
this.loading = true
getBlobFile(val.url).then(response => { // 将后台的图片二进制流转化为base64
this.fileurl = window.URL.createObjectURL(new Blob([response.data]))
this.loadPdfHandler()
}).catch(e => {
this.$message.error('获取PDF数据失败,请联系管理员')
this.loading = false
})
} else {
this.$message.error('文件链接失效')
}
this.name = val.name
},
zoomOut() {
const w = this.$refs.dialogimg.width
this.imgWidth = w * 0.9
},
zoomIn() {
const w = this.$refs.dialogimg.width
this.imgWidth = w * 0.9
},
rotateImg() {
this.imgrotate = this.imgrotate + 90
if (this.imgrotate === 360) {
this.imgrotate = 0
}
},
close() {
this.imgWidth = 'auto'
this.imgHeight = 'auto'
this.imgrotate = 0
this.fileurl = ''
this.$emit('closeDialog')
},
showImg(val) {
if (val.url) {
console.log(this.fileList, val.url)
this.loading = true
// Uint8Array 数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。
// String.fromCharCode 将 Unicode 编码转为一个字符 String.fromCharCode(65); // 输出 A
getArrayBufferFile(val.url).then(response => { // 将后台的图片二进制流转化为base64
this.fileurl = 'data:image/png;base64,' + btoa(
new Uint8Array(response.data).reduce((data, byte) => data + String.fromCharCode(byte), '')
)
}).catch(e => {
this.$message.error('获取图片数据失败:' + e)
}).finally(() => {
this.loading = false
})
} else {
this.$message.error('文件链接失效')
}
this.name = val.name
},
showFile(val) {
this.checkFileType(val)
}
}
}
</script>
<style lang="scss" module>
:global(.dialogImgBox) {
display: flex;
:global(.el-dialog__body) {
flex: 1;
display: flex;
overflow: hidden;
}
.dialogImgList {
width: 350px;
margin-left: 10px;
padding-left: 10px;
border-left: 1px solid #eee;
transition-property: width, border-left;
transition-duration: .3s;
.active {
color: #409EFF;
}
.dialogImgListItem {
padding-left: 10px;
:hover {
color: #409EFF;
}
:global(.active) {
color: #409EFF;
}
}
}
.dialogImgListClose {
width: 0;
border-left: none;
}
}
.btnSize {
font-size: 30px;
}
</style>
<style lang="scss" scoped>
// .el-tree-dialog::v-deep .el-tree-node__content {
// font-size: 18px!important;
// }
.el-tree-dialog::v-deep .el-tree-node__children {
color: #409EFF !important;
}
.el-tree-dialog::v-deep .el-tree-node .is-current>.el-tree-node__content {
background: rgba(0, 0, 0, 0.2);
border-right: 3px solid #1677ff;
color: red;
.el-tree-node__expand-icon {
color: red;
}
.is-leaf {
color: rgba(0, 0, 0, 0);
}
}
.active {
color: red;
}
</style>
getFileStream.js
import axios from 'axios'
import { getToken, getSid } from '@/utils/auth'
const sid = getSid() || ''
const uiticket = getToken()
const service = axios.create({
withCredentials: true, // send cookies when cross-domain requests
// timeout: 5000 // request timeout
})
/**
* 判断文件类型
* @param {*} type
* @returns
*/
export function getFileType (type) {
let filetype = ''
switch (type) {
case 'jpg':
case 'JPG':
case 'jpeg':
case 'JPEG':
case 'gif':
case 'GIF':
case 'bmp':
case 'BMP':
case 'png':
case 'PNG':
filetype = 'img'
break
case 'pdf':
case 'PDF':
filetype = 'pdf'
break
}
return filetype
}
/**
* 判断文件类型
* @param {*} type
* @returns
*/
export function getFileType2 (type) {
let filetype = ''
switch (type) {
case 'jpg':
case 'JPG':
case 'jpeg':
case 'JPEG':
case 'gif':
case 'GIF':
case 'bmp':
case 'BMP':
case 'png':
case 'PNG':
filetype = 'img'
break
case 'pdf':
filetype = 'pdf'
break
case 'PDF':
filetype = 'pdf'
break
case 'doc':
filetype = 'doc'
break
case 'DOC':
filetype = 'doc'
break
case 'docx':
filetype = 'docx'
break
case 'DOCX':
filetype = 'docx'
break
case 'xlsx':
filetype = 'xlsx'
break
case 'XLSX':
filetype = 'xlsx'
break
case 'xls':
filetype = 'xls'
break
case 'XLS':
filetype = 'xls'
break
}
return filetype
}
function pubDownloadFn (blob, name) {
console.log(name,'999')
let downloadElement = document.createElement('a')//创建<a>标签
let href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = name // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
}
/**
* 获取ArrayBuffer格式的二进制数据
* @param {*} url
* @returns
*/
export function getArrayBufferFile (url) {
return service({
method: 'get',
url: window.location.protocol + '//' + window.location.host + url ,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'uiticket': getToken() , // 必须添加的请求头
'sid': getSid() || '' // 必须添加的请求头
},
responseType: 'arraybuffer', // 关键 设置 响应类型为二进制流
})
}
/**
* 获取ArrayBuffer格式的二进制数据
* @param {*} url
* @returns
*/
export function getArrayBufferFile2 (url) {
return service({
method: 'get',
// url: window.location.protocol + '//' + window.location.host + url ,
url: url ,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'uiticket': getToken() , // 必须添加的请求头
'sid': getSid() || '' // 必须添加的请求头
},
responseType: 'arraybuffer', // 关键 设置 响应类型为二进制流
})
}
/**
* 获取Blob格式的二进制数据
* @param {*} url
* @returns
*/
export function getBlobFile (url) {
return service({
method: 'get',
url: window.location.protocol + '//' + window.location.host + url ,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'uiticket': getToken() , // 必须添加的请求头
'sid': getSid() || '' // 必须添加的请求头
},
responseType: 'blob', // 关键 设置 响应类型为二进制流
})
}
/**
* 获取Blob格式的二进制数据
* @param {*} url
* @returns
*/
export function getBlobFile2 (url) {
return service({
method: 'get',
// url: window.location.protocol + '//' + window.location.host + url ,
url: url ,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'uiticket': getToken() , // 必须添加的请求头
'sid': getSid() || '' // 必须添加的请求头
},
responseType: 'blob', // 关键 设置 响应类型为二进制流
})
}
/**
* 下载图片
* @param {*} url
* @param {*} name
* @returns Promesion
*/
export function downloadImage (url, name) {
return getArrayBufferFile(url).then(response => { // 将后台的图片二进制流转化为base64
const arr = name.indexOf('.') !== -1 ? name.split('.') : url.split('.')
let typename = arr[arr.length - 1].toLowerCase()
if (typename && (typename.indexOf('jpe') !== -1 || typename.indexOf('jpg') !== -1 || typename.indexOf('JPG') !== -1 || typename.indexOf('JPE') !== -1)) {
typename = 'jpeg'
}
const blob = new Blob([response.data], { type: 'image/' + typename })//这里type指定下载文件的类型
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, name)
} else {
pubDownloadFn(blob, name)
}
})
}
/**
* 下载图片
* @param {*} url
* @param {*} name
* @returns Promesion
*/
export function downloadImage2 (url, name) {
return getArrayBufferFile2(url).then(response => { // 将后台的图片二进制流转化为base64
const arr = name.indexOf('.') !== -1 ? name.split('.') : url.split('.')
let typename = arr[arr.length - 1].toLowerCase()
if (typename && (typename.indexOf('jpe') !== -1 || typename.indexOf('jpg') !== -1 || typename.indexOf('JPG') !== -1 || typename.indexOf('JPE') !== -1)) {
typename = 'jpeg'
}
const blob = new Blob([response.data], { type: 'image/' + typename })//这里type指定下载文件的类型
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, name)
} else {
pubDownloadFn(blob, name)
}
})
}
/**
* 下载PDF
* @param {*} url
* @param {*} name
*/
export function downloadPdf (url, name) {
return getBlobFile(url).then(response => { // 将后台的图片二进制流转化为base64
const blob = new Blob([response.data], { type: 'application/*' })//这里type指定下载文件的类型
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, name)
} else {
pubDownloadFn(blob, name)
}
})
}
/**
* 下载PDF
* @param {*} url
* @param {*} name
*/
export function downloadPdf2 (url, name) {
return getBlobFile2(url).then(response => { // 将后台的图片二进制流转化为base64
const blob = new Blob([response.data], { type: 'application/*' })//这里type指定下载文件的类型
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, name)
} else {
pubDownloadFn(blob, name)
}
})
}