冰蓝科技
|
028-81705109
|
|
微信扫一扫
|

Spire.Cloud 纯前端文档控件

Spire.PDF for Python 11.12.1 现已正式发布,本次更新带来了多项新功能,包括为数字签名添加时间戳、配置 PDF 转 Excel 时的多种布局选项、以及在 PDF 转 Markdown 时忽略图像。同时,本版本还修复了两个已知问题。更多详情如下。

新功能:

问题修复:


获取 Spire.PDF for Python 11.12.1 请点击:

https://www.e-iceblue.cn/Downloads/Spire-PDF-Python.html

Spire.OCR for Python 1.9.13 已发布。本次版本先进行了若干依赖与平台方面的调整,随后增强了错误处理与 OCR 识别能力。详细更新如下:

调整:

优化:


获取 Spire.OCR for Python 1.9.13,请点击以下链接:

https://www.e-iceblue.cn/Downloads/Spire-OCR-Python.html

随着企业数字化转型加速,纯前端文档处理已成为 Web 应用的核心需求之一。Angular 作为成熟的企业级前端框架,以其强类型校验、组件化架构和高效的状态管理能力,广泛应用于 OA 系统、文档平台、教育管理系统等复杂场景。

本文将详细介绍如何将 Spire.OfficeJS 集成到 Angular 项目中,实现本地文件上传、在线编辑、格式转换与下载等核心功能。

内容概览


Spire.OfficeJS 产品简介

Spire.OfficeJS 是一款企业级在线文档处理与编辑解决方案,包含 Spire.WordJSSpire.ExcelJS、Spire.PresentationJS、Spire.PDFJS 四个模块。该产品无需依赖本地 Office 软件,也无需安装任何插件,即可在浏览器中实现 Word、Excel、PPT、PDF 等主流格式文件的在线预览、实时编辑、批注、与格式转换等功能,同时具备云原生、跨平台、高安全性等企业级特性。

核心优势包括:

  • 模块化架构:四大核心模块各司其职,覆盖文档处理全场景 — Word 文档精细化编辑、Excel 数据计算与图表分析、PPT 演示文稿可视化编辑、PDF 文档快速预览。
  • 纯前端渲染能力:基于 WebAssembly 自研引擎,无需后端参与文档转换,降低服务器压力,提升响应速度。
  • 多格式兼容:支持 DOCX、XLSX、PPTX、PDF、WPS 等主流文件格式,支持跨格式导出(如 Word 转 PDF)。
  • 安全可控:支持静态文件加密存储,保障文档数据安全。
  • 轻量易集成:无缝适配 Angular、Vue、React 等主流前端框架,仅需简单配置即可快速集成。

环境准备与 Angular 项目初始化

在开始集成前,需先完成以下准备工作,确保开发环境符合要求。

1. 安装 Node.js 与 npm

  • 下载安装:访问 Node.js 官方下载地址,选择对应系统版本,按默认向导完成安装。
  • 版本验证:CMD 执行以下命令验证安装是否成功,若显示版本号则说明安装完成。
node -v
npm -v

通过命令行验证 Node.js 和 npm 版本

2. 安装 Angular CLI 脚手架

Angular CLI 是快速构建 Angular 项目的工具,通过 npm 全局安装:

  • 执行安装命令:
npm install -g @angular/cli
  • 安装完成后,执行以下命令查看 Angular CLI 版本,确认安装成功:
ng version

通过命令行验证Angular CLI 版本信息

3. 初始化 Angular 项目

通过 Angular CLI 创建基础项目,为后续集成 Spire.OfficeJS 搭建框架。

  • 打开 CMD 命令行,切换到目标目录(示例:F:\angular):
  • 执行以下命令创建 Angular 项目:
ng new spireOfficeJS --skip-git
  • 项目创建向导配置(按如下选择确保兼容性):
    • 是否创建无 zone.js 的 "zoneless" 应用:No
    • 样式表格式:CSS
    • 是否启用 SSR/SSG:No

Angular CLI 创建项目时的配置选项

  • 等待依赖安装完成,项目创建成功后,目录结构如下:

新建 Angular 项目的文件夹结构

4.验证项目初始化

使用 VS Code 打开项目,在终端执行以下命令启动开发服务器:

npm run start

浏览器打开 http://localhost:4200/,若显示 “Hello, spireOfficeJS” 及 Angular 默认页面,则项目初始化成功。

浏览器中显示的 Angular 默认欢迎页面


集成 Spire.OfficeJS 在线编辑器

1. 部署 Spire.OfficeJS 静态资源

下载 Spire.OfficeJS 产品包,解压后需将产品包中的核心 Web 资源复制到 Angular 项目的静态目录,确保编辑器脚本可被访问。具体操作如下:

  • 在项目 public 目录下创建 spire.cloud 文件夹(路径:public/spire.cloud)。
  • 从下载的 Spire.OfficeJS 产品包中找到 web 文件夹,将其完整复制到 public/spire.cloud/ 目录下。
  • 确保核心脚本 SpireCloudEditor.js 的最终路径为: public/spire.cloud/web/editors/spireapi/SpireCloudEditor.js

在VS Code中确认SpireCloudEditor.js 的文件路径

⚠️ 注意:此路径需与后续配置的 office-js.ts 中路径完全一致,否则编辑器无法加载


2. 状态管理配置

用于同步文件上传数据(文件对象 + 二进制数据),确保编辑器组件可访问。

(1)安装依赖

使用 NgRx Signals 管理文件数据,在VS Code 终端执行以下安装命令:

npm install @ngrx/effects @ngrx/signals @ngrx/store

(2)创建状态管理 Store

  • 在 src/app/ 目录下创建 store 文件夹,新建 index.ts 文件。
  • 复制以下代码到 index.ts,定义文件状态与操作方法:
import { signalStore, withState, withMethods, patchState } from '@ngrx/signals';

// 定义文件状态接口
interface FileState {
  file: File | null;          // 上传的文件对象
  fileUint8Data: Uint8Array | null; // 文件二进制数据
}

// 初始状态
const initialState: FileState = {
  file: null,
  fileUint8Data: null,
};

// 创建全局 Store
export const fileStore = signalStore(
  { providedIn: 'root' },
  withState(initialState),
  withMethods((store) => ({
    // 更新文件对象
    setFileData(data: File | null): void {
      patchState(store, { file: data });
    },
    // 更新文件二进制数据
    setFileUint8Data(uint8Data: Uint8Array | null): void {
      patchState(store, { fileUint8Data: uint8Data });
    }
  }))
);

3. 核心组件开发(上传 + 编辑器)

(1)创建组件

在终端执行以下命令,创建文件上传组件和编辑器集成组件:

ng g c spire/uploadFile
ng g c spire/officeJS

执行完成后,src/app/spire/ 目录下会生成 upload-file/ 和 office-js/ 两个组件文件夹。

在VS Code 中验证新生成的组件目录

(2)文件上传组件(upload-file)配置

上传组件负责接收用户拖放或选择的文件,转换为二进制格式后存储到全局状态,再跳转至编辑器页面。

  • 定义上传界面样式(upload-file.css):
:host {
  display: block;
  min-height: 100vh;
}

.upload-main {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f5f5;
}

.upload-container {
  width: 80%;
  max-width: 600px;
  padding: 40px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  text-align: center;
}

.drop-area {
  border: 2px dashed #ccc;
  border-radius: 6px;
  padding: 40px;
  margin-bottom: 20px;
  transition: all 0.3s;
}

.drop-area.highlight {
  border-color: #4CAF50;
  background-color: #f0fff0;
}

button {
  background-color: #4CAF50;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  margin-top: 10px;
}

button:hover {
  background-color: #45a049;
}

#fileInput {
  display: none; /* 隐藏原生文件选择框 */
}
  • 设置上传界面结构(upload-file.html),支持拖放上传和点击选择文件两种方式:
<main class="upload-main">
  <div class="upload-container">
    <h2>拖放文件上传</h2>
    <div class="drop-area" id="dropArea">
      <p>拖放文件到浏览器</p>
      <p>或</p>
      <button id="browseBtn" #browseBtn (click)="handleButtonClick($event)">选择文件</button>
      <input type="file" id="fileInput" #fileInput (change)="handleDrop($event)">
    </div>
  </div>
</main>
  • 上传逻辑实现(upload-file.ts),处理文件拖放、选择、二进制转换与状态储存:
import { ViewChild, ElementRef, Component, AfterViewInit, inject } from '@angular/core';
import { Router } from '@angular/router';
import { fileStore } from '../../store/index';

@Component({
  selector: 'app-upload-file',
  imports: [],
  templateUrl: './upload-file.html',
  styleUrl: './upload-file.css',
})
export class UploadFile implements AfterViewInit {
  constructor(private router: Router) { }
  // 注入状态管理 Store
  store = inject(fileStore);

  // 绑定 HTML 元素
  @ViewChild('browseBtn') browseBtn!: ElementRef<HTMLButtonElement>;
  @ViewChild('fileInput') fileInput!: ElementRef<HTMLInputElement>;

  file: File | null = null; // 上传的文件对象
  fileUint8Data: Uint8Array | null = null; // 文件二进制数据

  // 组件视图初始化完成后执行
  ngAfterViewInit() {
    this.init();
  }

  // 初始化拖放事件监听
  init() {
    // 阻止浏览器默认拖放行为
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
      document.addEventListener(eventName, this.preventDefaults, false);
    });

    // 监听文件拖放事件
    document.addEventListener('drop', (e) => {
      this.handleDrop.call(this, e);
    }, false);
  }

  // 阻止默认事件
  preventDefaults(e: Event) {
    e.preventDefault();
    e.stopPropagation();
  }

  // 点击“选择文件”按钮触发原生文件选择框
  handleButtonClick(e: Event) {
    e.preventDefault();
    this.fileInput.nativeElement.click();
  }

  // 处理文件拖放/选择事件
  async handleDrop(e: any) {
    // 获取文件对象(拖放或点击选择)
    if (e.target && e.target.files) {
      this.file = e.target.files[0];
    } else if (e.dataTransfer && e.dataTransfer.files) {
      this.file = e.dataTransfer.files[0];
    }

    // 转换文件为 Uint8Array 二进制格式
    this.fileUint8Data = await this.handleFile(this.file) as Uint8Array;

    // 更新状态到 Store(供编辑器组件使用)
    this.store.setFileData(this.file);
    this.store.setFileUint8Data(this.fileUint8Data);

    // 跳转到编辑器页面
    this.openDocument();
  }

  // 将文件转换为 Uint8Array 二进制数据
  handleFile(file: any) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => {
        const arrayBuffer = reader.result as ArrayBuffer;
        const uint8Array = new Uint8Array(arrayBuffer);
        resolve(uint8Array);
      };
      reader.onerror = (error) => reject(error);
      reader.readAsArrayBuffer(file); // 以 ArrayBuffer 格式读取文件
    });
  }

  // 跳转到编辑器页面(路由导航)
  openDocument() {
    this.router.navigate(['spire']);
  }
}

(3) 编辑器组件(office-js)配置

编辑器组件负责加载 Spire.OfficeJS 脚本、初始化编辑器实例、配置编辑权限与功能,是核心交互模块。

  • 定义编辑器容器 (office-js.html):
<div class="form">
    <div id="iframeEditor">
    </div>
</div>
  • 实现编辑器脚本加载、配置初始化、文件解析与事件监听等核心逻辑(office-js.ts):
import { Component, AfterViewInit, inject } from '@angular/core';
import { Router } from '@angular/router';
import { fileStore } from '../../store/index';

// 声明 SpireCloudEditor 全局变量(来自产品脚本)
declare const SpireCloudEditor: any;

@Component({
  selector: 'app-office-js',
  imports: [],
  templateUrl: './office-js.html',
  styleUrl: './office-js.css',
})
export class OfficeJS implements AfterViewInit {
  constructor(private router: Router) { };
  // 注入状态管理 Store
  store = inject(fileStore);

  // 从 Store 获取文件数据
  file = this.store.file() as File;
  fileUint8Data = this.store.fileUint8Data() as Uint8Array;
  originUrl = window.location.origin; // 当前项目域名
  Editor: any; // 编辑器实例
  config: any; // 编辑器配置
  Api: any;    // 编辑器 API

  // 组件视图初始化完成后执行
  ngAfterViewInit() {
    this.init();
  }

  // 初始化校验(无文件则跳回上传页)
  init() {
    if (!this.file) {
      this.router.navigate(['']); // 跳转到上传页面
      return;
    }
    this.loadSrcipt(); // 加载编辑器脚本
  }

  // 动态加载 SpireCloudEditor.js 脚本
  loadSrcipt() {
    const script = document.createElement('script');
    // 脚本路径需与静态资源部署路径一致
    script.setAttribute('src', '/spire.cloud/web/editors/spireapi/SpireCloudEditor.js');
    script.onload = () => this.initEditor(); // 脚本加载完成后初始化编辑器
    document.head.appendChild(script);
  }

  // 初始化编辑器配置与实例
  initEditor() {
    const iframeId = 'iframeEditor'; // 与模板文件中容器 ID 一致
    this.initConfig(); // 配置编辑器参数
    // 创建编辑器实例
    this.Editor = new SpireCloudEditor.OpenApi(iframeId, this.config);
    this.Api = this.Editor.GetOpenApi(); // 获取编辑器 API (用于扩展功能)
    this.OnWindowReSize(); // 适配窗口大小
  }

  // 编辑器核心配置(文件信息 + 用户权限 + 编辑器行为)
  initConfig() {
    this.config = {
      "fileAttrs": {
        "fileInfo": {
          "name": this.file.name, // 文件名
          "ext": this.getFileExtension(), // 文件后缀
          "primary": String(new Date().getTime()), // 唯一标识(时间戳)
          "creator": "",
          "createTime": ""
        },
        "sourceUrl": `${this.originUrl}/files/__ffff_192.168.3.121/${this.file.name}`,
        "createUrl": `${this.originUrl}/open`,
        "mergeFolderUrl": "",
        "fileChoiceUrl": "",
        "templates": {}
      },
      "user": {
        "id": "uid-1",
        "name": "Jonn",
        "canSave": true, // 允许保存文件
      },
      "editorAttrs": {
        "editorMode": this.file.name.endsWith('.pdf') ? 'view' : "edit", // PDF 默认为预览模式
        "editorWidth": "100%", // 编辑器宽度
        "editorHeight": "100%", // 编辑器高度
        "editorType": "document", // 编辑器类型(文档)
        "platform": "desktop", // 平台类型(桌面端)
        "viewLanguage": "zh", // 界面语言(中文)
        "isReadOnly": false, // 非只读模式
        "canChat": true, // 启用聊天功能
        "canComment": true, // 启用批注功能
        "canReview": true, // 启用审阅功能
        "canDownload": true, // 允许下载文件
        "canEdit": this.file.name.endsWith('.pdf') ? false : true, // PDF 禁止编辑
        "canForcesave": true, // 允许强制保存
        "embedded": {
          "saveUrl": "",
          "embedUrl": "",
          "shareUrl": "",
          "toolbarDocked": "top" // 工具栏置顶
        },
        // 启用 WebAssembly 加速(提升编辑和转换性能)
        "useWebAssemblyDoc": true,
        "useWebAssemblyExcel": true,
        "useWebAssemblyPpt": true,
        "useWebAssemblyPdf": true,
        // 许可证配置(若有许可证,填写对应密钥)
        "spireDocJsLicense": "",
        "spireXlsJsLicense": "",
        "spirePresentationJsLicense": "",
        "spirePdfJsLicense": "",
        "serverless": {
          "useServerless": true,
          "baseUrl": this.originUrl,
          "fileData": this.fileUint8Data, // 核心:传入文件二进制数据
        },
        "events": {
          "onSave": this.onFileSave // 保存回调事件
        },
        "plugins": {
          "pluginsData": []
        }
      }
    };
  }

  // 窗口大小适配
  OnWindowReSize() {
    const wrapEl = document.getElementsByClassName("form") as any;
    if (wrapEl.length) {
      wrapEl[0].style.height = window.innerHeight + "px";
      window.scrollTo(0, -1);
    }
  }

  // 获取文件后缀名
  getFileExtension() {
    const filename = this.file.name.split(/[\\/]/).pop() as String;
    return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase() || '';
  }

  // 自定义保存逻辑(可根据需求扩展)
  onFileSave(data: any) {
    console.log('保存的数据:', data);
  }
}

4. 路由配置 (实现页面跳转)

为上传页面和编辑器页面配置路由,实现页面跳转。

  • 修改路由规则(app.routes.ts),配置上传页和编辑器页的路由:
import { Routes } from '@angular/router';
import { UploadFile } from './spire/upload-file/upload-file';
import { OfficeJS } from './spire/office-js/office-js';

export const routes: Routes = [
  { path: '', component: UploadFile }, // 默认路由:文件上传页
  { path: 'spire', component: OfficeJS } // 编辑器路由:/spire
];
  • 注入路由配置(app.config.ts),确保路由配置生效:
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes), // 注入路由
  ]
};
  • 设置路由出口(app.html),确保页面正确渲染:
<main class="app-main">
  <router-outlet /> <!-- 路由出口:渲染当前路由对应的组件 -->
</main>

启动运行与功能验证

1. 启动项目

保存所有修改后,在项目根目录(F:\angular\spireOfficeJS)执行以下命令,重启开发服务器:

npm run start

2. 功能验证

  • 访问上传页面:浏览器打开 http://localhost:4200/,显示 “拖放文件上传” 界面,支持两种上传方式:
    • 拖放文件到浏览器指定区域;
    • 点击 “选择文件” 按钮,从本地上传文档(支持 Word、Excel、PPT、PDF 等格式)。

浏览器中显示的文件拖放上传界面

  • 在线编辑文档: 上传文件后,自动跳转到编辑器页面(http://localhost:4200/spire),可实现:
    • 文档编辑(PDF 仅支持预览);
    • 添加批注、评论、跟踪修订等功能;
    • 界面语言为中文,工具栏布局清晰。

Spire.OfficeJS 在线编辑器的中文界面及工具栏

  • 下载 / 转换文档:编辑完成后,点击编辑器顶部 “文件→“下载为”,可将文档导出为PDF、TXT、RTF、HTML等多种格式。

编辑器内文件菜单下的导出格式选项列表


常见问题解答

Q1:编辑器加载失败,页面空白?

  • 排查路径:确认 SpireCloudEditor.js 路径与 office-js.ts 中 script.src 一致
  • 浏览器兼容:升级至 Chrome 100+ 等支持 WebAssembly 的浏览器

Q2:安装 NgRx 依赖时提示 peer dependency 冲突?

  • Angular 版本与 NgRx 版本存在依赖约束差异,可使用 --legacy-peer-deps 强制兼容安装:
npm install @ngrx/signals @ngrx/store --legacy-peer-deps
  • 或根据 Angular 升级指南调整版本

Q3:启动项目时,浏览器控制台报错,提示找不到 zone.js 模块?

  • 原因:初始化项目时误选 “zoneless” 模式(无 zone.js 依赖),但 Spire.OfficeJS 依赖 zone.js 处理异步事件。
  • 解决方案:
    • 先安装 zone.js 依赖:npm install zone.js --save
    • 再打开 src/main.ts,在文件顶部添加导入:import 'zone.js';
    • 最后重新启动项目,确认报错消失。

完整示例下载

下载 Angular 集成 Spire.OfficeJS 的完整示例项目,包含所有配置文件与代码,直接运行即可体验功能。

点击下载


临时许可证申请

如需去除水印或解锁全部功能,可联系我们获取 30 天临时许可证。

Spire.Doc 13.12.2 现已正式发布。本版本支持双行合一功能,强化了 Word 转 PDF 的效果。同时,支持设置段落文本的“Horizontal in Vertical”属性、Markdown 转 Docx 时从模板文档复制样式,以及获取样式更改修订。更多详情如下。

新功能:

问题修复:


获取 Spire.Doc 13.12.2,请点击:

https://www.e-iceblue.cn/Downloads/Spire-Doc-NET.html

Spire.Doc for Java 13.12.2 现已正式发布。该版本支持检测写保护密码是否正确,此外还修复了一些在转换 Word 到 PDF、HTML 到 Word,和替换书签时出现的问题。详情如下。

新功能:

问题修复:


获取 Spire.Doc for Java 13.12.2 请点击:

https://www.e-iceblue.cn/Downloads/Spire-Doc-JAVA.html

Spire.Doc for Python 13.12.0 已正式发布,该版本带来了多项重要的 API 增强功能,包括针对文档元素的精细化格式控制、图表配置选项的强化以及文档比较功能的升级。此外,还对辅助功能进行了增强,重构了列表系统,并对整体 API 进行了全面优化,从而显著提升了用户体验。具体更新内容如下。

调整:


获取 Spire.Doc for Python 13.12.0 请点击:

https://www.e-iceblue.cn/Downloads/Spire-Doc-Python.html

Spire.PDF 11.12.0 现已正式发布。该版本新增 PdfFreeTextAnnotation.StringFormat 属性,用于设置文本的水平与垂直对齐方式,并对 WPF 平台下的 PDF 转图片渲染逻辑进行了优化。同时,还修复了多项与 PDF 转换、多语言文本渲染以及注释处理相关的问题。更多详情如下。

调整:

新功能:

HTML(超文本标记语言)是一种用于创建网页的标记语言,能让开发者构建内容丰富、视觉吸引力强的页面布局。然而,HTML 文件通常包含大量标签,若仅需获取主要内容,这些标签会使其难以阅读。通过 Python 将 HTML 转换为文本,可轻松解决这一问题。与原始 HTML 不同,转换后的文本文件会剥离所有不必要的标记,仅保留干净易读的内容,更便于存储、分析或进一步处理。

主要内容:


安装 HTML 转文本 Python 库

推荐使用 Spire.Doc for Python 实现转换。该 Python Word 库不仅是轻量高效的 HTML 转文本工具,还支持几乎所有 Word 操作(如创建、内容编辑等),兼容性强、上手简单。

通过 pip 命令安装(推荐)

打开终端 / 命令行,执行以下命令即可自动完成安装:

pip install spire.doc

Python 将 HTML 文件转换为文本

借助 Spire.Doc for Python,仅需 3 个简单步骤即可将本地 HTML 文件转换为纯文本:创建 Document 对象 → 加载 HTML 文件 → 保存为 TXT 格式。整个过程简洁高效,新手也能轻松上手!下面详细介绍代码实现:

代码示例 — HTML 文件转 TXT 文本文件

from spire.doc import *
from spire.doc.common import *

# 打开 HTML 文件
document = Document()
document.LoadFromFile("sample.html.html", FileFormat.Html, XHTMLValidationType.none)

# 保存为文本文件
document.SaveToFile("HTML转文本.txt", FileFormat.Txt)

document.Close()

转换效果预览(源文件 vs 输出文件):

Python将HTML文件转换为文本

请注意:若 HTML 文件包含表格,输出的文本文件将仅保留表格中的数据,无法保留原始表格格式。若希望移除标记的同时保留特定样式,建议先将 HTML 转换为 Word 文档,这样可保留标题、表格等格式,让内容更易于编辑和使用。


Python 将 HTML 字符串转换为文本

如果仅需提取网页部分内容(如爬取的 HTML 片段),可直接将 HTML 字符串转换为文本,无需加载完整 HTML 文件,更灵活高效。

Spire.Doc 转换 HTML 字符串到文本文件的实现步骤:

  1. 直接输入 HTML 字符串或从本地文件读取;
  2. 创建 Document 对象并添加节(Section)和段落(Paragraph);
  3. 使用 Paragraph.AppendHTML() 方法将 HTML 字符串插入段落;
  4. 通过 Document.SaveToFile() 方法将文档保存为 .txt 文件。

代码示例 — HTML 字符串转 TXT 文本文件

from spire.doc import *
from spire.doc.common import *

# 获取 HTML 字符串(可注释下方代码,取消注释读取本地文件的逻辑)
# with open(inputFile) as fp:
#     html = fp.read()

# 定义 HTML 字符串
html = """
 <html>
     <body>
         <h1>示例HTML内容</h1>
         <p>这是一个包含<strong>粗体</strong>和<em>斜体</em>文本的段落。</p>
         <p>另一行带有<a href='https://example.com'>链接</a>。</p>
         <ul>
             <li>列表项1</li>
              <li>列表项2(带有<em>斜体</em>文本)</li>
         </ul>
         <p>特殊字符:&copy; &amp; &reg;</p>
     </body>
 </html>
"""

# 创建新文档
document = Document()
section = document.AddSection()

# 将 HTML 字符串插入段落
section.AddParagraph().AppendHTML(html)

# 保存为 TXT 文件
document.SaveToFile("HTML字符串转文本.txt", FileFormat.Txt)
document.Close()

转换后的 TXT 文件预览:

Python将HTML字符串转换为文本


总结

借助 Spire.Doc for Python,仅需几行代码即可完成 HTML 文件 / 字符串到纯文本的转换,操作简单、效率高,且能适配大多数实际场景。若需探索更多功能,可申请 30 天免费试用许可,解锁全部功能。

无论是数据分析、内容提取还是文档处理,HTML 转文本都是高频需求 — 掌握这一技巧,能大幅提升 Python 数据处理的灵活性和效率!


常见问题解答

问题1:如何批量转换多个 HTML 文件为纯文本文件?

答:可通过遍历文件夹内的 HTML 文件,循环调用 Spire.Doc 的转换逻辑实现批量处理,核心是结合os模块遍历文件,示例代码如下:

from spire.doc import *
from spire.doc.common import *
import os

# 定义输入/输出文件夹路径
input_folder = "./html_files"
output_folder = "./txt_files"

# 确保输出文件夹存在
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# 遍历输入文件夹下所有HTML文件
for filename in os.listdir(input_folder):
    if filename.endswith(".html") or filename.endswith(".htm"):
        # 拼接文件路径
        input_path = os.path.join(input_folder, filename)
        # 生成输出文件名(替换后缀为txt)
        output_filename = os.path.splitext(filename)[0] + ".txt"
        output_path = os.path.join(output_folder, output_filename)
        
        # 执行转换逻辑
        document = Document()
        document.LoadFromFile(http://cdn.e-iceblue.cn/input_path, FileFormat.Html, XHTMLValidationType.none)
        document.SaveToFile(output_path, FileFormat.Txt)
        print(f"成功转换:{filename} → {output_filename}")
        document.Close()

问题2:Spire.Doc 能否处理格式错误的 HTML?

答:可以。Spire.Doc 内置了对格式错误 HTML 的容错能力,但需要禁用严格验证以确保正确解析,即加载 HTML 文件时,使用 XHTMLValidationType.none 跳过严格的 XHTML 检查:

问题3:转换包含图片、视频、音频标签的 HTML,会如何处理这些媒体标签?

答:Spire.Doc for Python 仅处理 HTML 中的文本内容,图片(<img>)、视频(<video>)、音频(<audio>)等媒体标签会被直接剥离,不会在文本中保留标签本身或媒体文件相关信息。

Spire.Presentation for Python 10.12.0 现已正式发布。本次更新针对 PPTX 转 PDF 的准确性和稳定性进行了增强,修复了文本丢失、内容重叠以及表格布局不正确等问题。详情如下。

问题修复:


获取 Spire.Presentation for Python 10.12.0 请点击:

https://www.e-iceblue.cn/Downloads/Spire-Presentation-Python.html

随着 Web 前端技术的发展,越来越多的企业与开发者开始将文档处理和文件管理等能力迁移至纯前端体系中,以提升应用的响应速度、安全性和易用性。

作为当前流行的前端框架之一,React 以其声明式、组件化的优势,广泛应用于构建从后台管理系统、在线文档平台到教育管理系统等各类复杂Web应用。 本文将指导你便捷地在 React 项目中集成使用Spire.OfficeJS,让复杂的文档处理变得简单、可控。

目录:

关于 Spire.OfficeJS

Spire.OfficeJS 是 E-ICEBLUE 推出的纯前端文档编辑组件套件,包含 Word、Excel、PowerPoint、PDF 等多种格式的查看、编辑、创建与转换能力。开发者无需安装 Microsoft Office,也无需依赖后端服务,即可在浏览器中完成从打开到编辑、再到导出的完整文档处理流程。其轻量、高效、易集成的特性,使其非常适合用于构建在线文档平台、知识库、教育平台及各类管理后台。

套件包括以下四款前端编辑器组件:

核心功能:

  • 多格式支持:支持 Word、Excel、PPT 预览,编辑与导出,以及 PDF 格式文档的预览
  • 在线编辑能力:可在浏览器中直接操作 Office 文档编辑文档内容,例如文本、表格、图片、样式等
  • 高性能纯前端运行:基于 WebAssembly,加载轻量、运行高效,无需后端参与
  • 灵活集成:可轻松接入 React、Vue、Angular 等框架,原生 JavaScript 中使用也非常便捷

创建 React 项目并集成 Spire.OfficeJS

步骤一:安装 Node.js

下载安装 Node.JS (Node.JS 官方网站:https://nodejs.org/en/download/),安装后可通过打开 cmd 后输入下述命令验证版本:

node -v
npm -v

使用代码确认Node.js 版本

步骤二:使用 Vite 创建 React 项目

指定项目文件夹位置,cmd 进入执行命令:npm create vite@latest my-officejs-app -- --template react 创建初始化 React 项目。

使用vite创建空白react项目

步骤三:npm 安装依赖

Vscode 打开 my-officejs-app 项目,命令执行:npm install react-router-dom 安装路由管理库,以便页面之间更好地切换显示。

步骤四:集成 Spire.OfficeJS

下载 Spire.OfficeJS 产品包, 在 React 项目 public 文件下新建 spire.cloud 文件夹,并将产品解压包中的web文件夹复制到 spire.cloud 下,路径配置跟 Editor.jsx 中路径保持一致

复制到 public 目录

在项目中构建文件上传与编辑器页面

  1. App.jsx 中配置以下内容,处理路由及全局文件状态管理
import { createContext, useContext, useState } from 'react';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Home from './Home';
import Editor from './Editor';

// 文件状态 Context
const FileContext = createContext();

export const useFileStore = () => useContext(FileContext);

function FileProvider({ children }) {
  const [file, setFile] = useState(null);
  const [fileUint8Data, setFileUint8Data] = useState(null);

  return (
    <FileContext.Provider value={{
      file,
      fileUint8Data,
      setFileData: setFile,
      setFileUint8Data
    }}>
      {children}
    </FileContext.Provider>
  );
}

const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  { path: '/editor', element: <Editor /> },
]);

function App() {
  return (
    <FileProvider>
      <RouterProvider router={router} />
    </FileProvider>
  );
}

export default App;
  1. Home.jsx 中配置以下内容用于文件上传功能,包括拖拽上传、选择本地文件、用 FileReader 转成 Uint8Array、将文件保存到 Context,以及跳转到编辑器页面。

说明:

  • FileReader:用于读取本地文件;
  • Uint8Array:OfficeJS 的 WebAssembly 接收二进制格式
  • useNavigate:React Router 的页面跳转函数
  • drag&drop: 浏览器拖拽上传
import { useRef, useEffect } from "react"
import { useFileStore } from './App';
import { useNavigate } from 'react-router-dom';

function Home() {
    const { setFileData, setFileUint8Data } = useFileStore();
    const navigate = useNavigate();

    let dropArea = null;
    let fileInput = useRef();
    let file = null;
    let fileUint8Data = null;

    useEffect(() => {
        dropArea = document;

        // 阻止默认拖放行为
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, preventDefaults, false);
        });

        // 处理文件拖放
        dropArea.addEventListener('drop', handleDrop, false);
    }, [])

    const preventDefaults = (e) => {
        e.preventDefault();
        e.stopPropagation();
    }

    const handleBtnClick = (e) => {
        e.preventDefault();
        fileInput.current.click();
    }

    const handleDrop = async (e) => {
        if (e.target && e.target.files)
            file = e.target.files[0]
        else if (e.dataTransfer && e.dataTransfer.files)
            file = e.dataTransfer.files[0];

        if (!file) return;

        fileUint8Data = await handleFile(file);
        setFileData(file);
        setFileUint8Data(fileUint8Data);
        openDocument();
    }

    const handleFile = (file) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => {
                const arrayBuffer = reader.result;
                const uint8Array = new Uint8Array(arrayBuffer);
                resolve(uint8Array);
            };
            reader.onerror = (error) => reject(error);
            reader.readAsArrayBuffer(file);
        });
    }

    const openDocument = () => {
        navigate('/editor')
    }

    return (
        <div>
            <div>
                <h2>文件上传</h2>
                <div>
                    <p>拖放文件到浏览器</p>
                     <p style={{ marginLeft: '20px' }}>或</p>
                    <button ref={fileInput} onClick={handleBtnClick}>选择文件</button>
                    <input
                        type="file"
                        id="fileInput"
                        ref={fileInput}
                        onChange={handleDrop}
                        style={{ display: 'none' }}
                    />
                </div>
            </div>
        </div>
    )
}

export default Home
  1. 新增含以下内容的 Editor.jsx 集成 OfficeJS 编辑器
import { useRef, useEffect } from "react"
import { useFileStore } from './App';
import { useNavigate } from 'react-router-dom';

function Editor() {
    const { file, fileUint8Data } = useFileStore();
    const navigate = useNavigate();

    const config = useRef({});
    let Editor = useRef(null);
    let Api = useRef(null);
    let originUrl = window.location.origin;

    useEffect(() => {
        if (!file) {
            navigate('/')
            return;
        }
        // 动态加载SpireCloudEditor.js
        loadScript();
    }, [])

    const loadScript = () => {
        var script = document.createElement('script');
        // 根据你的产品包路径调整
        script.setAttribute('src', '/spire.cloud/web/editors/spireapi/SpireCloudEditor.js');
        script.onload = () => initEditor()
        document.head.appendChild(script);
    }

    const initEditor = () => {
        let iframeId = 'iframeEditor';
        initConfig();
        Editor = new SpireCloudEditor.OpenApi(iframeId, config.value);
        window.Api = Api = Editor.GetOpenApi();
        OnWindowReSize();
    }

    const initConfig = () => {
        config.value = {
            "fileAttrs": {
                "fileInfo": {
                    "name": file.name,
                    "ext": getFileExtension(),
                    "primary": String(new Date().getTime()),
                    "creator": "User",
                    "createTime": new Date().toLocaleString()
                },
                "sourceUrl": originUrl + "/files/" + file.name,
                "createUrl": originUrl + "/open",
                "mergeFolderUrl": "",
                "fileChoiceUrl": "",
                "templates": {}
            },
            "user": {
                "id": "uid-1",
                "name": "User",
                "canSave": true,
            },
            "editorAttrs": {
                "editorMode": "edit",
                "editorWidth": "100%",
                "editorHeight": "100%",
                "editorType": "document",  // document/spreadsheet/presentation
                "platform": "desktop",
                "viewLanguage": "zh",  // en/zh
                "isReadOnly": false,
                "canChat": true,
                "canComment": true,
                "canReview": true,
                "canDownload": true,
                "canEdit": true,
                "canForcesave": true,
                "embedded": {
                    "saveUrl": "",
                    "embedUrl": "",
                    "shareUrl": "",
                    "toolbarDocked": "top"
                },
                // 启用WebAssembly以提升性能
                "useWebAssemblyDoc": true,
                "useWebAssemblyExcel": true,
                "useWebAssemblyPpt": true,
                "spireDocJsLicense": "",
                "spireXlsJsLicense": "",
                "spirePresentationJsLicense": "",
                "spirePdfJsLicense": "",
                // Serverless模式:直接使用文件数据,无需服务器
                "serverless": {
                    "useServerless": true,
                    "baseUrl": originUrl,
                    "fileData": fileUint8Data,  // 文件的Uint8Array数据
                },
                "events": {
                    "onSave": onFileSave
                },
                "plugins": {
                    "pluginsData": []
                }
            }
        };
    }

    const OnWindowReSize = () => {
        let wrapEl = document.getElementById("editor-container");
        if (wrapEl) {
            wrapEl.style.height = screen.availHeight + "px";
            window.scrollTo(0, -1);
            wrapEl.style.height = window.innerHeight + "px";
        }
    }

    const getFileExtension = () => {
        const filename = file.name.split(/[\\/]/).pop();
        return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase() || '';
    }

    const onFileSave = (data) => {
        console.log('保存数据:', data)
        // 在这里实现你的保存逻辑
        // 例如:发送到服务器、下载文件等
    }

    return (
        <div id="editor-container">
            <div id="iframeEditor"></div>
        </div>
    )
}

export default Editor
  1. main.jsx 配置以下内容
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  // 注意:StrictMode会导致Spire编辑器渲染两次,建议禁用
  <App />
)
  1. vite.config.js 中自定义配置Vite 端口
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  server: {
    host: '0.0.0.0',
    port: 8050
  },
  plugins: [react()],
})

项目运行

命令执行:npm run dev 运行配置后的项目,浏览器访问http://localhost:8050/

运行首页,上传文件

通过”选择文件“上传本地文档打开编辑。

文件上传后跳转前端编辑界面

通过“文件“—>”下载为” 可以下载或转换为其它格式。

编辑完后可将文档保存为其他格式

完整示例下载

点击下载

常见问题及解答

1. 创建项目时报错 npm或 node 版本不兼容:

可能是 Node.js 版本 问题,建议安装较新版本。

2. 依赖安装失败:

  • 清理缓存;
  • 删除 node_modules 和 package-lock.json,并重新安装;
  • 确保项目目录正确,不要在 Vite 项目外执行安装。

3. Spire.OfficeJS 文件无法加载:

  • 确认你已将 web 文件夹复制到对应目录下;
  • 确保项目运行时服务器可访问 public 下资源。

申请临时授权

如果您需要去除生成文档中的评估提示或解除功能限制,请联系我们获取有效期 30 天的临时许可证。