🎯 目标
-
前端打开新标签页预览 PDF(来自后端生成的 PDF blob)。
-
该标签页中提供一个“下载 Word 文件”的按钮。
-
点击按钮后,调用你自己定义的方法(比如调接口获取 Word 文件 blob 并下载)。
用 Vue 3 Composition API 封装整套,并贴完整版本
✅ 功能说明
-
后端返回 PDF Blob,新标签页预览
-
子页面中有一个按钮 点击可触发主页面下载 Word 文件
-
主页面通过 Axios 调接口获取 Word Blob 并下载
🧩 第一步:封装组合式函数 usePdfPreviewWithWordDownload.ts
// composables/usePdfPreviewWithWordDownload.ts
import { onMounted, onBeforeUnmount } from "vue";
export function usePdfPreviewWithWordDownload(
downloadWordFile: () => Promise<Blob>
) {
const openPdfPreview = (pdfBlob: Blob) => {
const blobUrl = URL.createObjectURL(pdfBlob);
const html = `
<html>
<head>
<title>PDF预览</title>
<style>
body { margin: 0; }
#downloadBtn {
position: fixed;
top: 16px;
right: 16px;
z-index: 1000;
background: #409EFF;
color: white;
border: none;
padding: 8px 14px;
font-size: 14px;
cursor: pointer;
border-radius: 4px;
}
</style>
</head>
<body>
<button id="downloadBtn">下载 Word</button>
<embed src="${blobUrl}" type="application/pdf" width="100%" height="100%"/>
<script>
window.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById('downloadBtn');
btn.addEventListener('click', () => {
window.opener.postMessage({ type: 'DOWNLOAD_WORD' }, '*');
});
});
</script>
</body>
</html>
`;
const previewWindow = window.open();
if (previewWindow) {
previewWindow.document.write(html);
previewWindow.document.close();
} else {
console.warn("浏览器拦截了新标签页");
}
};
// 监听子页面请求下载 Word
const messageHandler = async (event: MessageEvent) => {
if (event.data?.type === "DOWNLOAD_WORD") {
try {
const wordBlob = await downloadWordFile();
const url = URL.createObjectURL(wordBlob);
const a = document.createElement("a");
a.href = url;
a.download = "通知.docx";
a.click();
URL.revokeObjectURL(url);
} catch (err) {
console.error("下载 Word 文件失败", err);
}
}
};
onMounted(() => {
window.addEventListener("message", messageHandler);
});
onBeforeUnmount(() => {
window.removeEventListener("message", messageHandler);
});
return {
openPdfPreview,
};
}
✅ 第二步:组件中使用
<!-- components/PdfPreview.vue -->
<template>
<el-button type="primary" @click="handlePreview">预览 PDF 并下载 Word</el-button>
</template>
<script setup lang="ts">
import { usePdfPreviewWithWordDownload } from '@/composables/usePdfPreviewWithWordDownload';
import axios from 'axios';
// 你自己的 API 封装(可替换)
const fetchPdfBlob = async (): Promise<Blob> => {
const res = await axios.post('/api/pdf', {}, { responseType: 'blob' });
return new Blob([res.data], { type: 'application/pdf' });
};
const fetchWordBlob = async (): Promise<Blob> => {
const res = await axios.post('/api/word', {}, { responseType: 'blob' });
return new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
};
const { openPdfPreview } = usePdfPreviewWithWordDownload(fetchWordBlob);
const handlePreview = async () => {
const pdfBlob = await fetchPdfBlob();
openPdfPreview(pdfBlob);
};
</script>
✅ 效果展示
-
点击按钮 ➜ 打开新标签页 ➜ 显示 PDF 内容
-
右上角按钮 ➜ 触发主页面下载 Word 文件(无需暴露 Word 地址)