iShot_2024-10-14_16.47.10
目录结构
content.vue
javascript
<template>
<div class="no-content-block">
<i class="iconfont icondocument large-file" />
<div class="text-wrapper">{{ t('__ui__.siPreview.previewSupported') }}</div>
<div class="buttons-default" @click="donwload(url)">
<i class="iconfont el-icon-download" />
<div class="button-name">{{ t('__ui__.siPreview.downloadAttachment') }}</div>
</div>
</div>
</template>
<script>
import Locale from '../../../../mixins/locale'
export default {
name: 'BlankContent',
mixins: [Locale],
inject: ['app'],
props: {
url: {
type: String,
default: ''
}
},
methods: {
donwload(url) {
this.app.download()
window.open(url, '_blank')
}
}
}
</script>
previewContent.vue
javascript
<template>
<div class="pre-view-content">
<div class="buttons-icons-con" @click="donwload(fileUrl)">
<i class="iconfont el-icon-download" />
</div>
<div class="buttons-icons-set" @click="closeDialogue(fileType)">
<i class="iconfont el-icon-close" />
</div>
</div>
</template>
<script>
export default {
name: 'PreviewContent',
inject: ['app'],
props: {
fileUrl: {
type: String,
default: ''
},
fileType: {
type: String,
default: ''
}
},
methods: {
donwload(url) {
this.app.donwload(url)
},
closeDialogue(type) {
this.app.closeDialogue(type)
}
}
}
</script>
index.js
javascript
/*
Exposure to the outside world
fileUrl、Other parameters;
Transfer data
fileUrl address;
openLoad Yes, it's all function calls;
Exclusive introduction
import Vue from 'vue'
import { FilePreview } from '@payermax/components-manage-base'
Vue.use(FilePreview)
(= ̄ω ̄=) file you use this component
this.$filePreview('xxx');
*/
// import Vue from 'vue'
import _component from './index.vue'
import { prefix } from '../../../const'
const FilePreview = {
install(Vue, options) {
Vue.prototype.$filePreview = (url, downLoadCallback, closeCallback) => {
// Builder
const ComponentInstance = Vue.extend({
render(h) {
return h(_component, {
props: {
fileUrl: url,
downloadFile: downLoadCallback,
closeFile: closeCallback,
openLoad: true
}
})
}
})
// Create a singleton
const instance = new ComponentInstance().$mount()
document.body.appendChild(instance.$el)
}
Vue.component(`${prefix}${_component.name}`, _component)
}
}
export default FilePreview
index.js 代码解释
当前代码定义了一个名为
$filePreview
的 Vue 实例方法,该方法用于在页面中预览文件。以下是对代码的详细解释:
方法定义:
javascript
javascriptVue.prototype.$filePreview = (url, downLoadCallback, closeCallback) => { //... }
这里定义了一个 Vue 实例方法
$filePreview
,它接受三个参数:url
(文件的 URL 地址),downLoadCallback
(下载文件的回调函数),closeCallback
(关闭文件预览的回调函数)。组件实例化:
javascript
javascriptconst ComponentInstance = Vue.extend({ render(h) { return h(_component, { props: { fileUrl: url, downloadFile: downLoadCallback, closeFile: closeCallback, openLoad: true } }) } })
这里使用
Vue.extend
创建了一个 Vue 组件的子类ComponentInstance
,并在其render
函数中使用h
函数渲染_component
组件,并传递了四个属性:fileUrl
、downloadFile
、closeFile
、openLoad
。创建实例并挂载:
javascript
javascriptconst instance = new ComponentInstance().$mount() document.body.appendChild(instance.$el)
这里创建了
ComponentInstance
的实例instance
,并将其挂载到一个新的 DOM 元素上,然后将这个 DOM 元素添加到文档的 body 中。
总结来说,$filePreview
方法通过创建一个 Vue 组件实例,并将其渲染到页面上,实现了文件预览的功能。用户可以通过传递文件的 URL 和相应的回调函数来使用这个方法。
index.vue
javascript
<template>
<div ref="filePreviewContainer" class="file-preview-container">
<div class="download-card">
<div class="preview-wrap">
<div v-if="openLoad" />
<div v-else class="click-default">
<!-- Click arera -->
<div @click="previewFile()">
<div v-if="!hasSlot" />
<slot v-else />
</div>
</div>
<!-- Preview types -->
<template v-if="pdfContainerVisible && fileType == 'pdf'">
<div>
<div id="pdf-container" />
<div v-loading="loading" class="pdf-loading" />
<div class="pdf-download">
<div class="pdf-download-container">
<PreviewContent :file-url="fileUrl" :file-type="fileType" />
</div>
</div>
</div>
</template>
<div v-if="imageVisible && fileType == 'image'">
<div class="other-container">
<div class="header">
<PreviewContent :file-url="fileUrl" :file-type="fileType" />
</div>
<div class="other-containe-content">
<img loading="lazy" alt="" :src="fileUrl">
</div>
</div>
</div>
<div v-if="otherVisible" class="other-container">
<div class="header">
<PreviewContent :file-url="fileUrl" :file-type="fileType" />
</div>
<div class="other-containe-content">
<div v-if="openLoad" class="no-content-block">
<i class="iconfont icondocument large-file" />
</div>
<BlankContent v-else :url="fileUrl" />
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import PDFObject from 'pdfobject'
import BlankContent from './components/content.vue'
import PreviewContent from './components/previewContent.vue'
import Locale from '../../../mixins/locale'
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
const pdfExtensions = ['pdf']
const SCOPE_NAME = 'FilePreview'
export default {
name: SCOPE_NAME,
components: {
BlankContent,
PreviewContent
},
mixins: [Locale],
provide() {
return {
app: this
}
},
inheritAttrs: false,
props: {
fileUrl: {
type: String,
default: ''
},
closeFile: {
type: Function,
default: () => { }
},
downloadFile: {
type: Function,
default: () => { }
},
openLoad: {
type: Boolean,
default: false
}
},
data() {
return {
fileType: '',
pdfContainerVisible: false,
imageVisible: false,
otherVisible: false,
loading: false,
hasSlot: false
}
},
mounted() {
this.init()
this.mountPlugIn()
},
methods: {
mountPlugIn() {
if (this.openLoad) {
this.previewFile()
}
},
init() {
this.justFileType()
this.checkSlots()
},
checkSlots() {
if (this.$slots.default) {
this.hasSlot = true
} else {
this.hasSlot = false
}
},
justFileType() {
const extension = this.fileUrl.split('.').pop().toLowerCase() || ''
if (imageExtensions.includes(extension)) {
this.fileType = 'image'
} else if (pdfExtensions.includes(extension)) {
this.fileType = 'pdf'
} else {
this.fileType = 'other'
}
},
close() {
this.$emit('closeFile')
this.openLoad && this.closeFile()
this.openLoad && this.dealPluginPreviewNode()
},
download() {
this.$emit('downloadFile')
this.openLoad && this.downloadFile()
this.openLoad && this.dealPluginPreviewNode()
},
dealPluginPreviewNode() {
var containers = document.querySelectorAll('.file-preview-container')
if (containers.length > 0) {
var lastContainer = containers[containers.length - 1]
var parent = lastContainer.parentNode
parent.removeChild(lastContainer)
}
},
previewFile() {
switch (this.fileType) {
case 'pdf':
this.pdfPreview(this.fileUrl)
break
case 'image':
this.imagePreview(this.fileUrl)
break
case 'other':
this.otherPreview()
break
default:
break
}
},
async pdfPreview(fileUrl) {
this.loading = true
try {
const response = await fetch(fileUrl)
const status = response?.status || ''
if (status === 200) {
this.pdfContainerVisible = true
this.loading = false
this.$nextTick(() => {
let url = ''
if (fileUrl.startsWith('http://')) {
url = fileUrl.substring(5)
} else if (fileUrl.startsWith('https://')) {
url = fileUrl.substring(6)
} else {
url = fileUrl
}
PDFObject.embed(url, '#pdf-container', {
width: '100%'
})
})
} else {
this.loading = false
this.otherVisible = true
}
} catch (error) {
this.loading = false
this.otherVisible = true
}
},
imagePreview(fileUrl) {
this.loading = true
this.checkImageAccessibility(fileUrl, (accessible) => {
if (accessible) {
this.imageVisible = true
} else {
this.otherVisible = true
}
this.loading = false
})
},
checkImageAccessibility(url, callback) {
const img = new Image()
img.onload = function() {
callback(true)
}
img.onerror = function() {
callback(false)
}
img.src = url
},
otherPreview() {
this.otherVisible = true
},
closeDialogue(type) {
switch (type) {
case 'pdf':
this.pdfContainerVisible = false
this.close()
break
case 'image':
this.imageVisible = false
this.close()
break
case 'other':
this.otherVisible = false
this.close()
break
default:
break
}
},
donwload(url) {
this.download()
window.open(url, '_blank')
}
}
}
</script>
全局引入
javascript
import locale from './locale'
import { prefix } from './const'
import FilePreview from './src/Other/FilePreview'
const components = [
FilePreview
]
export {
FilePreview
}
function install(Vue, options = {}) {
locale.i18n(options.i18n)
components.forEach((component) => {
console.log(component.name, component)
if (component.install) {
component.install(Vue, options)
} else {
Vue.component(`${prefix}${component.name}`, component)
}
})
}
export default install
按需引入
Text.vue
html
<el-row>
<el-col :span="6">
<h2>图片(默认)</h2>
<m-FilePreview
:file-url="fileUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
/>
</el-col>
<el-col :span="6">
<h2>其他类文件(默认)</h2>
<m-FilePreview
:file-url="otherFileUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
/>
</el-col>
<el-col :span="6">
<h2>PDF文件(默认)</h2>
<m-FilePreview
:file-url="PdfUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
/>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<h2>图片(自定义按钮样式)</h2>
<m-FilePreview
:file-url="fileUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
>
<div class="haoren">
<el-button type="primary" plain>图片按钮</el-button>
</div>
</m-FilePreview>
</el-col>
<el-col :span="6">
<h2>其他类文件(自定义按钮样式)</h2>
<m-FilePreview
:file-url="otherFileUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
>
<div class="haoren">
<el-button type="success" plain>无法预览的文件</el-button>
</div>
</m-FilePreview>
</el-col>
<el-col :span="6">
<h2>PDF文件 (自定义按钮样式)</h2>
<m-FilePreview
:file-url="PdfUrl"
@closeFile="closeTest"
@downloadFile="downloadTest"
>
<div
style="color:red;
width:200px;
height: 80px;
background-color: aquamarine;
display: flex;
font-weight: 700;
justify-content: center;
align-items: center;
border-radius: 12px;
cursor: pointer;"
>PDF预览演示</div>
</m-FilePreview>
</el-col>
</el-row>
<el-row style="margin-top: 80px;">
<el-col :span="6">
<h2>图片(函数式调用)</h2>
<div @click="TestMess('img')">
<el-button type="primary">函数式预览图片</el-button>
</div>
</el-col>
<el-col :span="6">
<h2>PDF (函数式调用)</h2>
<div @click="TestMess('pdf')">
<el-button type="info">函数式预览PDF</el-button>
</div>
</el-col>
<el-col :span="6">
<h2>其他类型</h2>
<div @click="TestMess('other')"><button>函数式调用其他类型</button></div>
</el-col>
</el-row>
html
fileUrl: 'https://s3.ap-s%29.gif',
PdfUrl: 'https://s3.ap-south36596/NL2SQL.pdf',
otherFileUrl: 'https://gimg4.baidu.com/poster/f',
javascript
TestMess(val) {
if (val === 'img') {
this.$filePreview(this.fileUrl, this.downloadTest, this.closeTest)
} else if (val === 'pdf') {
this.$filePreview(this.PdfUrl, () => { console.log('click download!') }, () => { console.log('close window!') })
} else {
this.$filePreview(this.otherFileUrl, () => { console.log('click download!') }, () => { console.log('close window!') })
}
}