Vue中實(shí)現(xiàn)Word、Excel、PDF預(yù)覽的操作步驟
Vue中實(shí)現(xiàn)Word、Excel、PDF預(yù)覽的詳細(xì)步驟
1. PDF預(yù)覽實(shí)現(xiàn)
方法一:使用PDF.js
npm install pdfjs-dist
<template>
<div class="pdf-viewer">
<canvas ref="pdfCanvas"></canvas>
<div class="controls">
<button @click="prevPage" :disabled="currentPage <= 1">上一頁</button>
<span>{{ currentPage }} / {{ totalPages }}</span>
<button @click="nextPage" :disabled="currentPage >= totalPages">下一頁</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as pdfjsLib from 'pdfjs-dist'
// 設(shè)置worker路徑
pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js'
const pdfCanvas = ref(null)
const currentPage = ref(1)
const totalPages = ref(0)
let pdfDoc = null
const props = defineProps({
pdfUrl: {
type: String,
required: true
}
})
const loadPDF = async () => {
try {
pdfDoc = await pdfjsLib.getDocument(props.pdfUrl).promise
totalPages.value = pdfDoc.numPages
renderPage(1)
} catch (error) {
console.error('PDF加載失敗:', error)
}
}
const renderPage = async (pageNum) => {
const page = await pdfDoc.getPage(pageNum)
const canvas = pdfCanvas.value
const context = canvas.getContext('2d')
const viewport = page.getViewport({ scale: 1.5 })
canvas.height = viewport.height
canvas.width = viewport.width
await page.render({
canvasContext: context,
viewport: viewport
}).promise
}
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--
renderPage(currentPage.value)
}
}
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++
renderPage(currentPage.value)
}
}
onMounted(() => {
loadPDF()
})
</script>
方法二:使用iframe嵌入
<template>
<div class="pdf-viewer">
<iframe
:src="pdfUrl"
width="100%"
height="600px"
frameborder="0">
</iframe>
</div>
</template>
<script setup>
const props = defineProps({
pdfUrl: String
})
</script>
2. Excel預(yù)覽實(shí)現(xiàn)
使用SheetJS (xlsx)
npm install xlsx
<template>
<div class="excel-viewer">
<div class="sheet-tabs">
<button
v-for="(sheet, index) in sheets"
:key="index"
@click="activeSheet = index"
:class="{ active: activeSheet === index }"
>
{{ sheet.name }}
</button>
</div>
<div class="table-container">
<table v-if="currentSheetData.length">
<thead>
<tr>
<th v-for="(header, index) in headers" :key="index">
{{ header }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in currentSheetData" :key="rowIndex">
<td v-for="(cell, cellIndex) in row" :key="cellIndex">
{{ cell }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import * as XLSX from 'xlsx'
const sheets = ref([])
const activeSheet = ref(0)
const workbook = ref(null)
const props = defineProps({
excelUrl: {
type: String,
required: true
}
})
const currentSheetData = computed(() => {
if (!sheets.value[activeSheet.value]) return []
return sheets.value[activeSheet.value].data
})
const headers = computed(() => {
if (!currentSheetData.value.length) return []
return currentSheetData.value[0]
})
const loadExcel = async () => {
try {
const response = await fetch(props.excelUrl)
const arrayBuffer = await response.arrayBuffer()
workbook.value = XLSX.read(arrayBuffer, { type: 'array' })
sheets.value = workbook.value.SheetNames.map(name => {
const worksheet = workbook.value.Sheets[name]
const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
return {
name,
data
}
})
} catch (error) {
console.error('Excel加載失敗:', error)
}
}
onMounted(() => {
loadExcel()
})
</script>
<style scoped>
.sheet-tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.sheet-tabs button {
padding: 8px 16px;
border: 1px solid #ddd;
background: #f5f5f5;
cursor: pointer;
}
.sheet-tabs button.active {
background: #007bff;
color: white;
}
.table-container {
overflow: auto;
max-height: 500px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
position: sticky;
top: 0;
}
</style>
3. Word預(yù)覽實(shí)現(xiàn)
方法一:使用mammoth.js
npm install mammoth
<template>
<div class="word-viewer">
<div class="loading" v-if="loading">加載中...</div>
<div class="content" v-html="wordContent" v-else></div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import mammoth from 'mammoth'
const wordContent = ref('')
const loading = ref(true)
const props = defineProps({
wordUrl: {
type: String,
required: true
}
})
const loadWord = async () => {
try {
loading.value = true
const response = await fetch(props.wordUrl)
const arrayBuffer = await response.arrayBuffer()
const result = await mammoth.convertToHtml({ arrayBuffer })
wordContent.value = result.value
if (result.messages.length > 0) {
console.warn('Word轉(zhuǎn)換警告:', result.messages)
}
} catch (error) {
console.error('Word加載失敗:', error)
wordContent.value = '<p>文檔加載失敗</p>'
} finally {
loading.value = false
}
}
onMounted(() => {
loadWord()
})
</script>
<style scoped>
.word-viewer {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.content {
line-height: 1.6;
font-family: 'Times New Roman', serif;
}
.content :deep(p) {
margin-bottom: 1em;
}
.content :deep(h1),
.content :deep(h2),
.content :deep(h3) {
margin-top: 1.5em;
margin-bottom: 0.5em;
}
</style>
方法二:使用在線預(yù)覽服務(wù)
<template>
<div class="office-viewer">
<iframe
:src="previewUrl"
width="100%"
height="600px"
frameborder="0">
</iframe>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
fileUrl: {
type: String,
required: true
},
fileType: {
type: String,
required: true // 'word', 'excel', 'pdf'
}
})
const previewUrl = computed(() => {
const encodedUrl = encodeURIComponent(props.fileUrl)
// 使用Microsoft Office Online預(yù)覽
if (props.fileType === 'word' || props.fileType === 'excel') {
return `https://view.officeapps.live.com/op/embed.aspx?src=${encodedUrl}`
}
// 使用Google Docs預(yù)覽
return `https://docs.google.com/gview?url=${encodedUrl}&embedded=true`
})
</script>
4. 通用文件預(yù)覽組件
<template>
<div class="file-preview">
<div class="file-info">
<h3>{{ fileName }}</h3>
<span class="file-type">{{ fileType.toUpperCase() }}</span>
</div>
<!-- PDF預(yù)覽 -->
<PDFViewer v-if="fileType === 'pdf'" :pdf-url="fileUrl" />
<!-- Excel預(yù)覽 -->
<ExcelViewer v-else-if="fileType === 'excel'" :excel-url="fileUrl" />
<!-- Word預(yù)覽 -->
<WordViewer v-else-if="fileType === 'word'" :word-url="fileUrl" />
<!-- 不支持的文件類型 -->
<div v-else class="unsupported">
<p>不支持預(yù)覽此文件類型</p>
<a :href="fileUrl" rel="external nofollow" download>下載文件</a>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import PDFViewer from './PDFViewer.vue'
import ExcelViewer from './ExcelViewer.vue'
import WordViewer from './WordViewer.vue'
const props = defineProps({
fileUrl: {
type: String,
required: true
},
fileName: {
type: String,
default: '未知文件'
}
})
const fileType = computed(() => {
const extension = props.fileName.split('.').pop().toLowerCase()
switch (extension) {
case 'pdf':
return 'pdf'
case 'doc':
case 'docx':
return 'word'
case 'xls':
case 'xlsx':
return 'excel'
default:
return 'unknown'
}
})
</script>
<style scoped>
.file-preview {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}
.file-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background-color: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.file-type {
background-color: #007bff;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
}
.unsupported {
padding: 40px;
text-align: center;
color: #666;
}
</style>
5. 使用示例
<template>
<div class="app">
<h1>文件預(yù)覽示例</h1>
<div class="file-list">
<div v-for="file in files" :key="file.id" class="file-item">
<FilePreview
:file-url="file.url"
:file-name="file.name"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import FilePreview from './components/FilePreview.vue'
const files = ref([
{
id: 1,
name: 'sample.pdf',
url: '/files/sample.pdf'
},
{
id: 2,
name: 'data.xlsx',
url: '/files/data.xlsx'
},
{
id: 3,
name: 'document.docx',
url: '/files/document.docx'
}
])
</script>
注意事項(xiàng)
- 跨域問題:確保文件服務(wù)器支持CORS
- 文件大小:大文件可能影響加載性能
- 瀏覽器兼容性:某些功能可能需要現(xiàn)代瀏覽器支持
- 安全性:驗(yàn)證文件來源,防止XSS攻擊
- 移動(dòng)端適配:考慮響應(yīng)式設(shè)計(jì)
這些方案可以根據(jù)具體需求選擇使用,建議先測試小文件確保功能正常。
以上就是Vue中實(shí)現(xiàn)Word、Excel、PDF預(yù)覽的操作步驟的詳細(xì)內(nèi)容,更多關(guān)于Vue Word、Excel、PDF預(yù)覽的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue3.x項(xiàng)目中,出現(xiàn)紅色波浪線問題及解決
這篇文章主要介紹了vue3.x項(xiàng)目中,出現(xiàn)紅色波浪線問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
vue學(xué)習(xí)筆記之指令v-text && v-html && v-bind詳解
這篇文章主要介紹了vue學(xué)習(xí)筆記之指令v-text && v-html && v-bind詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
vue項(xiàng)目中跳轉(zhuǎn)到外部鏈接的實(shí)例講解
今天小編就為大家分享一篇vue項(xiàng)目中跳轉(zhuǎn)到外部鏈接的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue?perfect-scrollbar(特定框架里使用非該框架定制庫/插件)
這篇文章主要為大家介紹了vue?perfect-scrollbar在特定框架里使用一款并非為該框架定制的庫/插件如何實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2023-05-05
vue-router使用next()跳轉(zhuǎn)到指定路徑時(shí)會(huì)無限循環(huán)問題
這篇文章主要介紹了vue-router使用next()跳轉(zhuǎn)到指定路徑時(shí)會(huì)無限循環(huán)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
vue DatePicker日期選擇器時(shí)差8小時(shí)問題
這篇文章主要介紹了vue DatePicker日期選擇器時(shí)差8小時(shí)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05

