本文将详细介绍如何将 Spire.OfficeJS 集成到前端框架 Vue(基于 Vue3 + Vite)中,实现在线打开、预览及编辑 Office 文档的 Web 应用。
通过本教程,你将学会如何:
- 完整运行一个基于 Vue3 + Vite 的 Spire.OfficeJS 示例项目
- 将 Office WebAssembly 引擎正确部署到前端工程中
- 处理文档上传、读取、传递的前端工作流
- 在浏览器中打开、预览与编辑 Word、Excel、PPT 等 Office 文档
- 排查常见错误(路径无法加载、跨域、静态资源加载失败等)
文章目录
什么是 Spire.OfficeJS
Spire.OfficeJS 是一款基于 Web 的在线 Office 文档编辑产品,包含 Spire.WordJS、Spire.ExcelJS、Spire.PresentationJS、Spire.PDFJS四个模块,提供文档(Word)、电子表格(Excel)、演示文稿(PowerPoint)等格式的查看与实时编辑能力。它可以直接运行在浏览器中,支持部署在任何 Web 项目中,无需安装插件或依赖客户端软件。
Spire.OfficeJS 的主要特点包括:
- 纯前端渲染 :基于 WebAssembly,无需服务器转换文档即可编辑
- 丰富的编辑能力 :支持文档编辑、注释、批注、审阅、保存等操作
- 多格式支持 :DOCX、XLSX、PPTX、PDF 等常见文档格式
- 可集成性强 :可灵活嵌入 Vue、React、Angular、纯 HTML 项目
- 可定制性高 :支持配置工具栏、用户权限、保存回调、插件扩展等
适用于企业后台系统、文档管理系统(DMS)、协作平台、在线课程系统、表单系统等多种场景。
准备工作
安装 Node.js
请从 Node.js 官网下载并安装版本 22.12.0 或更高版本。安装完成后,通过命令验证环境:
node -v
npm -v

创建项目并启动服务
步骤1. 创建一个文件夹
选择一个位置创建新文件夹以存放项目文件。
步骤2. 通过 CMD 进入该文件夹
cd /d d:\demo

步骤3. 初始化 Vue 项目
创建 Vue3 项目并更改项目名称为 vue-spire:
npm init vue@latest

跳过其他设置,完成空白的 Vue 项目创建。

步骤4. 进入项目文件夹并启动服务
cd vue-spire
npm run dev

安装 Spire.OfficeJS
步骤1. 下载产品包
下载 Spire.OfficeJS 产品包,解压后可看到一个包含编辑器静态资源的 web 文件夹。

步骤2. 复制静态资源到 Public 目录
使用 VS Code 打开你的 Vue 项目,在 public 目录下创建 spire.cloud 文件夹,并将产品包中的 web 文件夹复制到该目录下。这样,在浏览器中可以通过 /spire.cloud/web/... 访问编辑器资源。

步骤3. 安装必要依赖 Pinia 与 Vue Router
使用 VS Code 终端命令行安装 pinia 依赖和 vue-router@4 路由:
npm install pinia
npm install vue-router@4

步骤4. 创建项目结构
在 src 下创建如下目录与文件:
src/
├── components/
│ ├── router/
│ │ └── index.js
│ ├── stores/
│ │ └── file.js
│ └── views/
│ ├── FileUpload.vue
│ └── Spire.OfficeJs.vue

步骤5. 添加必要代码
- main.js — 加载 Pinia 与 Router
本文件负责初始化整个 Vue 应用,包括:
- 注册 Pinia(用于全局状态管理)
- 注册 Vue Router(用于页面跳转)
- 渲染 App.vue 作为根组件。
import { createApp } from'vue'
import { createPinia } from'pinia'
import App from'./App.vue'
import router from'./router'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.use(router)
app.mount('#app')
- App.vue — 入口视图容器
App.vue 是整个项目的根组件,通常只包含一个路由占位符 <router-view>。
<script setup>
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView/>
</template>
说明:
- 所有页面均通过
<router-view>动态加载 - 这是 SPA(单页应用)的核心机制
- 路由 index.js — 页面导航
定义页面路径,例如:
- /upload → 上传页
- /document → Spire.OfficeJS 编辑器页
import { createRouter, createWebHistory } from'vue-router'
import FileUpload from'../views/FileUpload.vue'
import SpireOfficeJs from'../views/Spire.OfficeJs.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'upload',
component: FileUpload
},
{
path: '/document',
name: 'document',
component: SpireOfficeJs
},
{
path: '/:pathMatch(.*)*',
redirect: '/'
}
]
})
export default router
说明:
- 使用 history 模式避免 hash (#) URL
- 路由跳转后页面自动切换显示
- Pinia Store(file.js)— 保存上传文件与二进制数据
该 Store 用于保存:
- 文件名
- 文件的 ArrayBuffer 二进制内容
import { ref } from'vue'
import { defineStore } from'pinia'
exportconst useFileStore = defineStore('file', () => {
let file = ref(null)
let fileUint8Data = ref(null);
functionsetFileData(data) {
file.value = data;
}
functionsetFileUint8Data(data) {
fileUint8Data.value = data;
}
return { file, fileUint8Data, setFileData, setFileUint8Data }
})
说明:
- Pinia 提供响应式状态管理
- setFileData() 用于存储上传的文件对象
- setFileUint8Data() 用于存储二进制数据(Uint8Array)
- 在编辑器页面可随时读取文件内容
- FileUpload.vue — 文件上传页
用户选择文件后:
- 读取为 ArrayBuffer
- 保存到 Pinia Store
- 自动跳转至编辑器页面
<template>
<main>
<label>
<span>选择文件上传</span>
<inputtype="file" @change="handleFileChange" />
</label>
</main>
</template>
<scriptsetup>
import { useRouter } from'vue-router'
import { useFileStore } from'../stores/file'
const router = useRouter()
const fileStore = useFileStore()
asyncfunctionhandleFileChange(event) {
const selectedFile = event.target.files?.[0]
if (!selectedFile) {
return
}
fileStore.setFileData(selectedFile)
const buffer = await selectedFile.arrayBuffer()
fileStore.setFileUint8Data(newUint8Array(buffer))
router.push('/document')
}
</script>
说明:
- <input type="file"> 选择任意 Office 文档
- 浏览器的 File API 读为 ArrayBuffer
- 保存后无需再次上传
- 页面自动进入编辑器界面
- Spire.OfficeJs.vue — 集成 Spire.OfficeJS 在线编辑器
核心功能:
- 将二进制数据传给 Spire.OfficeJS 在线编辑器
- 加载文档进行在线编辑
<template>
<div class="form">
<div id="iframeEditor">
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useFileStore } from '../stores/file.js'
import { useRouter } from 'vue-router';
const fileStore = useFileStore()
// Pinia 中当存储的数据
const { file, fileUint8Data } = storeToRefs(fileStore)
const router = useRouter()
const config = ref({});
const isOpened = ref(false);
const editorInstance = ref(null);
const apiInstance = ref(null);
const originUrl = window.location.origin
onMounted(() => {
// 没有文件时直接跳回上传页
if (!file.value) {
router.replace('/');
return;
}
// 使用script的方式载入
loadScript();
window.addEventListener('resize', OnWindowReSize);
})
onUnmounted(() => {
window.removeEventListener('resize', OnWindowReSize);
})
// 初始化编辑器所需的配置对象
function initConfig() {
if (!file.value) {
throw new Error('未找到文件,请重新上传');
}
if (!fileUint8Data.value) {
throw new Error('未找到文件数据,请重新上传');
}
config.value = {
"fileAttrs": {
"fileInfo": {
"name": file.value.name,
"ext": getFileExtension(),
"primary": String(new Date().getTime()),
"creator": "Jonn",
"createTime": "2022-04-18 11:30:43"
},
"sourceUrl": originUrl + "/files/__ffff_192.168.2.134/" + file.value.name,
"createUrl": originUrl + "/open",
"mergeFolderUrl": "",
"fileChoiceUrl": "",
"templates": {}
},
"user": {
"id": "uid-1",
"name": "Jonn",
"canSave": true,
},
"editorAttrs": {
"editorMode": "edit", //edit / view
"editorWidth": "100%",
"editorHeight": "100%",
"editorType": "document",
"platform": "desktop", //desktop / mobile / embedded
"viewLanguage": "zh", //en / zh
"isReadOnly": false,
"canChat": true,
"canComment": true,
"canReview": true,
"canDownload": true,
"canEdit": true,
"canForcesave": true,
"embedded": {
"saveUrl": "",
"embedUrl": "",
"shareUrl": "",
"toolbarDocked": "top"
},
"useWebAssemblyDoc": true,
"useWebAssemblyExcel": true,
"useWebAssemblyPpt": true,
"spireDocJsLicense": "",
"spireXlsJsLicense": "",
"spirePresentationJsLicense": "",
"spirePdfJsLicense": "",
"serverless": {
"useServerless": true,
"baseUrl": originUrl,
"fileData": fileUint8Data.value,
},
"events": {
"onSave": onFileSave
},
"plugins": {
"pluginsData": []
}
}
};
}
// 创建并渲染 SpireCloudEditor 实例
function initEditor() {
let iframeId = 'iframeEditor';
initConfig();
isOpened.value = true;
editorInstance.value = new SpireCloudEditor.OpenApi(iframeId, config.value); // 创建编辑器实例
window.Api = apiInstance.value = editorInstance.value.GetOpenApi(); // 暴露 OpenApi 便于调试/保存
OnWindowReSize();
}
// 获取上传文件的扩展名,用于配置 fileInfo.ext
function getFileExtension() {
const filename = file.value.name.split(/[\\/]/).pop();
// 获取最后一个点后的内容
return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase() || '';
}
// 调整编辑器容器尺寸,使其随窗口大小自适应
function OnWindowReSize() {
let wrapEl = document.getElementsByClassName("form");
if (wrapEl.length) {
wrapEl[0].style.height = screen.availHeight + "px";
window.scrollTo(0, -1);
wrapEl[0].style.height = window.innerHeight + "px";
}
}
// 动态加载 SpireCloudEditor 脚本,避免重复注入
function loadScript() {
if (window.SpireCloudEditor) {
initEditor()
return
}
const script = document.createElement('script');
script.setAttribute('src', '/spire.cloud/web/editors/spireapi/SpireCloudEditor.js');
script.onload = () => initEditor()
document.head.appendChild(script);
}
// Spire 编辑器的保存回调,可接入自定义保存逻辑
function onFileSave(data) {
console.log('save data', data)
}
</script>
<style>
.form,
iframe,
body {
min-height: 100vh !important;
min-width: 100vh !important;
}
</style>
说明:
- Spire.Office.Editor 创建编辑器实例
- 将用户上传的文件加载成可编辑文档
- 支持 Word、Excel、PowerPoint 等格式
步骤6. 运行项目
在 VS Code 终端输入:
npm run dev

在浏览器输入 http://localhost:5173/(默认),并上传文档。

上传文档后,即可在 Web 页面使用 Spire.OfficeJS 实现在线编辑。

常见问题解答
Q1. 编辑器加载失败,页面空白? 可能原因如下:
- 静态资源路径错误
- SpireCloudEditor.js 未成功加载
- WebAssembly 文件未找到
Q2. 上传文件后跳转到编辑器但无法打开?
请检查:
- 文件二进制是否已正确写入 Pinia
- fileUint8Data 是否为 Uint8Array 格式
- serverless.fileData 是否成功传入编辑器配置
Q3. 支持哪些文件格式?
常见格式包括:
- .doc, .docx
- .xls, .xlsx
- .ppt, .pptx
- .pdf (仅浏览)
Q4. 能否实现自定义保存?
可以,通过配置:
events: {
onSave: onFileSave
}
你可以将 data 传给后端 API,实现真正的文件持久化。
Q5. 可以部署到生产服务器吗?
可以,部署时需确保:
- 保留 /public/spire.cloud/web/ 的完整结构
- 使用 HTTPS 以避免浏览器安全策略阻止加载 WebAssembly
- 根据环境设置正确的 baseUrl
申请临时License
如果您需要去除生成文档中的评估提示或解除功能限制,请联系我们获取有效期 30 天的临时许可证。







