Implementing File Preview Functionality in Frontend with Vue3
This article demonstrates how to build a Vue3‑based file preview feature that supports images, Word documents, Excel sheets, and PDFs by using iframe tags, npm packages like docx‑preview, xlsx, and pdfjs‑dist, and provides complete code snippets and practical tips.
Frontend File Preview Implementation
The goal is to create an online preview for PDF, Excel, Word, and image files using Vue3, with the suggestion to place the preview component inside a modal dialog.
Image Preview
An <iframe> can embed an image URL directly. The sandbox attribute is optional for simple image preview but can restrict scripts, navigation, same‑origin access, and pop‑ups when needed.
<iframe :src="图片地址"
style="z-index: 1000; height:650px; width: 100%; margin: 0 auto"
sandbox="allow-scripts allow-top-navigation allow-same-origin allow-popups">
</iframe>Word Document Preview (docx)
Install the docx-preview package, create a container element, and render the Blob data with renderAsync .
npm i docx-preview --save <div class="docxRef"></div>
<script>
import { renderAsync } from 'docx-preview';
function previewDocx(blob) {
const container = document.getElementsByClassName('docxRef')[0];
renderAsync(blob, container);
}
// example usage with a Blob response
previewDocx(res.data);
</script>Excel File Preview (xlsx)
Install a specific version of xlsx , read the Blob as an ArrayBuffer, convert it to a worksheet, and render the HTML representation.
npm install [email protected] <div class="xlsxClass"></div>
const reader = new FileReader();
reader.readAsArrayBuffer(res.data);
reader.onload = (event) => {
const data = new Uint8Array(event.target.result);
const workbook = XLSX.read(data, { type: "array" });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const html = XLSX.utils.sheet_to_html(sheet);
document.getElementsByClassName('xlsxClass')[0].innerHTML = html;
};PDF Preview
Install pdfjs-dist , then use a canvas to render pages. The component provides navigation buttons for previous/next pages and handles asynchronous loading of the PDF file.
npm install [email protected] <template>
<div class="box">
<div class="tool-bar">
<div>{{ pdfParams.pageNumber }} / {{ pdfParams.total }}</div>
<button type="primary" :disabled="pdfParams.pageNumber == pdfParams.total" @click="nextPage">Next</button>
<button type="primary" :disabled="pdfParams.pageNumber == 1" @click="prevPage">Prev</button>
</div>
<canvas id="pdf-render"></canvas>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
const pdfParams = reactive({ pageNumber: 1, total: 0 });
let pdfDoc = null;
onMounted(async () => {
const pdfjs = await import('pdfjs-dist/build/pdf');
const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.entry');
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const url = ref('/test2.pdf');
pdfjs.getDocument(url.value).promise.then(doc => {
pdfDoc = doc;
pdfParams.total = doc.numPages;
getPdfPage(1);
});
});
const getPdfPage = (number) => {
pdfDoc.getPage(number).then(page => {
const viewport = page.getViewport();
const canvas = document.getElementById('pdf-render');
const ctx = canvas.getContext('2d');
canvas.width = viewport.viewBox[2];
canvas.height = viewport.viewBox[3];
const renderContext = {
canvasContext: ctx,
viewport: viewport,
transform: [1, 0, 0, -1, 0, viewport.height]
};
page.render(renderContext);
});
};
const prevPage = () => {
if (pdfParams.pageNumber > 1) pdfParams.pageNumber--;
getPdfPage(pdfParams.pageNumber);
};
const nextPage = () => {
if (pdfParams.pageNumber < pdfParams.total) pdfParams.pageNumber++;
getPdfPage(pdfParams.pageNumber);
};
</script>Important Notes
PDF files must be loaded asynchronously.
The demo PDF is placed in public/test2.pdf .
The canvas transform uses a matrix [1, 0, 0, -1, 0, viewport.height] to flip the Y‑axis.
Navigation buttons trigger a re‑render of the current page.
For further details, refer to the original CSDN blog and the official pdfjs examples.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.