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

Spire.Cloud 纯前端文档控件

在日常 Excel 数据处理中,排序是最常用的操作之一——无论是按名称、数值还是日期重新排列数据,都能让表格更有条理、便于检索。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成数据排序,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。

本文介绍两个核心功能点:

有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。


对单元格区域内的数据升序排序

对指定单元格区域进行升序排序是最常见的数据整理需求。Spire.XLS for JavaScript 通过 Workbook.DataSorter.SortColumns.Add() 方法添加排序字段并指定排序方式,再通过 Workbook.DataSorter.Sort() 方法对指定区域进行排序。具体操作步骤如下:

  1. 创建 Workbook 对象,并使用 LoadFromFile() 方法加载 Excel 文档。
  2. 通过 Workbook.Worksheets.get() 方法获取指定工作表。
  3. 使用 Workbook.DataSorter.SortColumns.Add() 方法添加排序字段,指定排序列和排序方式。
  4. 使用 Workbook.DataSorter.Sort() 方法对指定单元格区域进行排序。
  5. 通过 Workbook.SaveToFile() 方法保存文档到指定路径。

下面是一个完整的代码示例,展示了在 React 中按单个列对单元格区域进行升序排序:

function App() {
  const sortAscending = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 将字体和 Excel 文件载入 VFS
    await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'DataSorting.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // 加载工作簿
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // 获取第一个工作表
    const sheet = workbook.Worksheets.get(0);

    // 添加排序字段:按第 5 列(人口)升序排序
    workbook.DataSorter.SortColumns.Add({ key: 4, orderBy: xlsModule.OrderBy.Ascending });

    // 对指定单元格区域 A1:E19 排序
    workbook.DataSorter.Sort(sheet.Range.get("A1:E19"));

    // 保存文档
    const outputFileName = 'SortDataAscending_output.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 释放资源
    workbook.Dispose();

    // 从 VFS 读取转换后的文件,触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Sort Data in Ascending Order</h1>
      <button onClick={sortAscending}>
        Start
      </button>
    </div>
  );
}

export default App;

排序后,数据将按照第 5 列(人口)的数值从小到大升序排列,同一行中的其余列数据会与人口列保持对齐。

对单元格区域内的数据升序排序


按多个列对数据排序

当单列排序无法满足需求时,可以同时按多个列进行排序。Spire.XLS for JavaScript 支持多次调用 SortColumns.Add() 方法添加多个排序字段,排序时先按第一个字段排序,再按后续字段排序。具体操作步骤如下:

  1. 创建 Workbook 对象,并使用 LoadFromFile() 方法加载 Excel 文档。
  2. 通过 Workbook.Worksheets.get() 方法获取指定工作表。
  3. 多次调用 Workbook.DataSorter.SortColumns.Add() 方法添加多个排序字段。
  4. 使用 Workbook.DataSorter.Sort() 方法对指定单元格区域进行排序。
  5. 通过 Workbook.SaveToFile() 方法保存文档到指定路径。

下面是一个完整的代码示例,展示了在 React 中按多个列对单元格区域进行排序:

function App() {
  const sortMultipleColumns = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 将字体和 Excel 文件载入 VFS
    await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'DataSorting.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // 加载工作簿
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // 获取第一个工作表
    const sheet = workbook.Worksheets.get(0);

    // 添加多个排序字段:先按第 3 列(洲)升序,再按第 4 列(面积)升序
    workbook.DataSorter.SortColumns.Add({ key: 2, orderBy: xlsModule.OrderBy.Ascending });
    workbook.DataSorter.SortColumns.Add({ key: 3, orderBy: xlsModule.OrderBy.Ascending });

    // 对指定单元格区域 A1:E19 排序
    workbook.DataSorter.Sort(sheet.Range.get("A1:E19"));

    // 保存文档
    const outputFileName = 'SortDataMultipleColumns_output.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 释放资源
    workbook.Dispose();

    // 从 VFS 读取转换后的文件,触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Sort Data by Multiple Columns</h1>
      <button onClick={sortMultipleColumns}>
        Start
      </button>
    </div>
  );
}

export default App;

排序后,数据先按第 3 列(洲)升序排列,将同属一个洲的国家归拢在一起;当洲相同时,再按第 4 列(面积)升序排列。

按多个列对数据排序


常见问题

排序时表头行也被参与了排序

原因:DataSorter.Sort() 方法默认将排序区域的首行视为标题行并保留在原位置。如果表头被移到了数据行中,通常是排序区域起始行设置不正确。

解决:确认传入 Sort() 方法的区域包含表头行,且表头行位于区域的顶部,例如 sheet.Range.get("A1:E19")。也可以从数据行开始排序,如 sheet.Range.get("A2:E19")。

单列排序后,其他列的数据没有跟随变化

原因:排序只对传入 Sort() 方法的单元格区域生效。如果只对单独一列的区域排序,其他列不会跟随重排,导致同行数据错位。

解决:让排序区域覆盖所有相关列(例如包含名称、首都、洲、面积、人口的完整区域 A1:E19),从而保证整行数据一起移动。


获取免费许可证

如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。

在 Web 应用中处理 Excel 文件时,查找和替换数据是常见的需求。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成 Excel 操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。它提供了 FindAllString() 和 FindAllNumber() 等查找方法,支持在整个工作表或指定的单元格区域中查找目标数据,并快速将其替换为新的内容,同时还可以通过高亮颜色标记替换后的单元格。

通过 Spire.XLS for JavaScript,您既可以批量替换整个工作表中的文本,也可以将查找范围限定在特定的单元格区域内,在需要精确更新部分数据时更加灵活高效。

本文介绍两个核心功能点:

有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。


在 Excel 中查找和替换工作表中的数据

使用 Spire.XLS for JavaScript,您可以在整个工作表中查找包含指定文本的单元格,并将其替换为新的内容。FindAllString() 方法会返回所有匹配的单元格区域,您可以通过设置 range.Text 属性来替换文本,并通过 range.Style.Color 属性为替换后的单元格设置高亮颜色,从而清晰地标记被修改的位置。具体操作步骤如下:

  1. 创建 Workbook 对象并加载已有的 Excel 文件。
  2. 通过 workbook.Worksheets.get() 获取要操作的工作表。
  3. 使用 worksheet.FindAllString() 查找工作表中包含指定文本的所有单元格区域。
  4. 遍历查找结果,通过设置 range.Text 替换文本,并通过 range.Style.Color 设置高亮颜色。
  5. 使用 SaveToFile() 保存工作簿为 Excel 文件。

下面是一个完整的代码示例,展示了在 React 中查找并替换整个工作表中的数据:

function App() {
  const findAndReplace = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    let excelFileName = 'Sample.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}static/data/`);

    // 创建新工作簿并加载已有的 Excel 文件
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // 获取第一个工作表
    let worksheet = workbook.Worksheets.get(0);

    // 查找工作表中包含 "总计" 文本的所有单元格
    let ranges = worksheet.FindAllString("总计", false, false);

    // 遍历查找结果,替换文本并设置高亮颜色
    for (let range of ranges) {
      range.Text = "总支出";
      range.Style.Color = xlsModule.Color.get_Yellow();
    }

    // 保存工作簿
    const outputFileName = 'FindAndReplaceData.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
    workbook.Dispose();

    // 从 VFS 读取文件并触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>在 Excel 中查找并替换工作表数据</h1>
      <button onClick={findAndReplace}>
        生成
      </button>
    </div>
  );
}

export default App;

在 Excel 中查找并替换工作表数据

在 Excel 中查找并替换工作表数据


在 Excel 中查找和替换特定单元格区域中的数据

当只需要更新部分数据时,您可以将查找范围限定在特定的单元格区域内。使用 sheet.Range.get() 方法指定目标区域后,range.FindAllString() 会在该区域内查找包含指定文本的单元格,从而确保区域外的数据不受影响。具体操作步骤如下:

  1. 创建 Workbook 对象并加载已有的 Excel 文件。
  2. 通过 workbook.Worksheets.get() 获取要操作的工作表。
  3. 使用 sheet.Range.get() 指定要查找的单元格区域。
  4. 使用 range.FindAllString() 在指定区域内查找包含目标文本的单元格,遍历结果并替换文本、设置高亮颜色。
  5. 使用 SaveToFile() 保存工作簿为 Excel 文件。

下面是一个完整的代码示例,展示了在 React 中查找并替换特定单元格区域中的数据:

function App() {
  const findAndReplaceInRange = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 示例文件加载到虚拟文件系统(VFS)
    let excelFileName = 'FindCellsSample.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}static/data/`);

    // 创建新工作簿并加载已有的 Excel 文件
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // 获取第一个工作表
    let worksheet = workbook.Worksheets.get(0);

    // 指定要查找的单元格区域
    let range = worksheet.Range.get({
      row: 1,
      column: 1,
      lastRow: 12,
      lastColumn: 2,
    });

    // 在指定区域内查找包含 "总计" 文本的单元格
    let ranges = range.FindAllString("总计", false, false);

    // 遍历查找结果,替换文本并设置高亮颜色
    for (let r of ranges) {
      r.Text = "总支出";
      r.Style.Color = xlsModule.Color.get_Yellow();
    }

    // 保存工作簿
    const outputFileName = 'FindAndReplaceInRange.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
    workbook.Dispose();

    // 从 VFS 读取文件并触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>在指定区域查找并替换数据</h1>
      <button onClick={findAndReplaceInRange}>
        生成
      </button>
    </div>
  );
}

export default App;

在 Excel 中查找并替换特定单元格区域中的数据

在 Excel 中查找并替换特定单元格区域中的数据


常见问题

如何控制查找是否区分大小写或匹配整个单词

原因:FindAllString() 方法的后两个布尔参数分别用于控制查找是否区分大小写以及是否要求匹配整个单词。如果参数设置不当,可能会找到过多或过少的匹配结果。

解决:根据实际需求调整 FindAllString() 的参数:

// 不区分大小写,不要求整个单词匹配
let ranges = worksheet.FindAllString("Area", false, false);

// 区分大小写,要求整个单词匹配
let ranges = worksheet.FindAllString("Total", true, true);

如何在指定区域中查找并替换数字

原因:查找和替换不仅适用于文本,也适用于数字。如果只使用 FindAllString() 处理文本,将无法匹配数值型的单元格。

解决:使用 range.FindAllNumber() 方法在指定区域内查找数字,然后通过设置 Text 属性替换数值:

let numberRanges = range.FindAllNumber(100, true);
for (let r of numberRanges) {
  r.Text = "200";
  r.Style.Color = xlsModule.Color.get_Yellow();
}

获取免费许可证

如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。

在 React 中使用 JavaScript 将 Markdown 转换为 HTML 的图文教程

快速概览: 本文介绍如何在 React 应用中使用 JavaScript 和 Spire.Doc WebAssembly(WASM),直接在浏览器中将 Markdown 文件或字符串转换为 HTML,无需服务器端处理。

Markdown 常用于 README 文件、技术文档、技术文章以及其他结构化内容。但在某些应用场景中,需要将这些内容转换为 HTML 文件,例如发布为网页,或交给其他基于 HTML 的工作流继续处理。

本文将介绍如何在 React 应用中使用 Spire.Doc for JavaScript 将 Markdown 转换为 HTML,主要包括以下两种常见场景:

前提条件与项目配置

步骤 1:安装 Spire.Doc for JavaScript

在 React 项目的根目录中打开终端,并通过 NPM 安装 Spire.Doc:

npm i spire.office

步骤 2:复制运行时资源

安装完成后,将 node_modules/spire.office 中的以下运行时资源复制到 React 项目的 public 目录:

  • _framework
  • spire.doc.js
  • Spire.Doc.Wasm.zip
  • spire.common.js
  • Spire.Common.Wasm.zip

下面的示例还会使用 CALIBRI.ttf 进行文本渲染。请将该字体文件放置在 public/static/font/ 目录下。

对于基于文件的转换示例,请将源 Markdown 文档放置在 public/static/data/MarkdownExample.md。

有关详细的项目配置方法,请参阅 如何在 React 中集成 Spire.Doc for JavaScript。

注意: 以下示例使用 process.env.PUBLIC_URL,这是 Create React App 中常用的公共资源路径写法。如果项目使用 Vite 或其他构建工具,请根据实际项目结构调整公共资源路径。

在 React 中使用 JavaScript 将 Markdown 文件转换为 HTML

如果 Markdown 内容已经以 .md 文件形式存在,可以先将文件加载到 WebAssembly 虚拟文件系统(VFS)中,再通过 Document.LoadFromFile() 打开。随后,使用 Document.SaveToFile() 即可将文档导出为 HTML。

基于文件的转换主要分为以下四个阶段:

  1. 初始化模块: React 组件挂载后,加载并初始化 Spire.Doc WebAssembly 模块。
  2. 加载输入文件: 使用 FetchFileToVFS() 将所需字体和源 Markdown 文件加载到 VFS。
  3. 转换文档: 使用 FileFormat.Markdown 加载 .md 文件,并通过 FileFormat.Html 保存为 HTML。
  4. 处理输出文件: 从 VFS 中读取生成的 HTML 文件,并在浏览器中下载。

下面的示例将 MarkdownExample.md 转换为 MarkdownToHtml.html。

import React, { useState, useEffect } from 'react';

function App() {
  const [wasmModule, setWasmModule] = useState(null);

  // 加载 Spire.Doc
  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';

        const spireModule = await import(
          /* webpackIgnore: true */
          `${publicUrl}/spire.doc.js`
        );

        const rawModule = spireModule.default || spireModule;

        window.wasmModule =
          typeof rawModule === 'function'
            ? await rawModule({
                locateFile: (path) =>
                  path.endsWith('.wasm')
                    ? `${publicUrl}/${path}`
                    : path
              })
            : rawModule;

        setWasmModule(window.wasmModule);
      } catch (error) {
        console.error(
          'Failed to load spire.doc.js WASM module:',
          error
        );
      }
    })();
  }, []);

  // 将 Markdown 文件转换为 HTML
  const convertMarkdownFileToHtml = async () => {
    const wasmModule = window.wasmModule?.spiredoc;

    if (!wasmModule) return;

    // 将所需字体加载到 VFS
    await window.spire.FetchFileToVFS(
      'CALIBRI.ttf',
      '/Library/Fonts/',
      `${process.env.PUBLIC_URL}/static/font/`
    );

    // 将 Markdown 文件加载到 VFS
    const inputFileName = 'MarkdownExample.md';

    await window.spire.FetchFileToVFS(
      inputFileName,
      '',
      `${process.env.PUBLIC_URL}/static/data/`
    );

    // 创建 Document 实例
    const doc = new wasmModule.Document();

    try {
      // 加载 Markdown 文档
      doc.LoadFromFile({
        fileName: inputFileName,
        fileFormat: wasmModule.FileFormat.Markdown
      });

      // 设置 HTML 导出选项
      doc.HtmlExportOptions.CssStyleSheetType = wasmModule.CssStyleSheetType.Internal;      
      doc.HtmlExportOptions.ImageEmbedded = true;
	  
      // 将文档保存为 HTML
      const outputFileName = 'MarkdownToHtml.html';

      doc.SaveToFile({
        fileName: outputFileName,
        fileFormat: wasmModule.FileFormat.Html
      });

      // 从 VFS 中读取生成的 HTML 文件
      const htmlBytes =
        window.dotnetRuntime.Module.FS.readFile(
          outputFileName
        );

      // 下载 HTML 文件
      const blob = new Blob(
        [htmlBytes],
        { type: 'text/html;charset=utf-8' }
      );

      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');

      link.href = url;
      link.download = outputFileName;

      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);

      URL.revokeObjectURL(url);
    } finally {
      doc.Dispose();
    }
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>转换 Markdown 文件为 HTML</h1>

      <button
        onClick={convertMarkdownFileToHtml}
        disabled={!wasmModule}
      >
        转换并下载
      </button>
    </div>
  );
}

export default App;

WebAssembly 模块加载完成后,点击 转换并下载。应用会从 public/static/data/ 目录加载 MarkdownExample.md,将其转换为 HTML,并下载生成的 MarkdownToHtml.html 文件。

在这一过程中,FetchFileToVFS() 用于将源 Markdown 文件加载到 WebAssembly 虚拟文件系统中,Document.LoadFromFile() 用于从 VFS 读取该文件。CssStyleSheetType.Internal 和 ImageEmbedded 用于将样式和图片直接嵌入 HTML 中,最后通过 Document.SaveToFile() 将文档导出为 HTML。

输出结果:

在 React 中使用 JavaScript 将 Markdown 文件转换为 HTML

在 React 中使用 JavaScript 将 Markdown 字符串转换为 HTML

Markdown 内容也经常直接在应用中生成或编辑。例如,从 API 或 CMS 返回的内容可能已经是 JavaScript 字符串,而不是现有的 .md 文件。

由于 Document.LoadFromFile() 需要从 WebAssembly 虚拟文件系统中读取文件,因此可以先使用 FS.writeFile() 将 Markdown 字符串写入一个临时 .md 文件,再按照处理普通 Markdown 文件的方式完成转换。

基于字符串的转换主要包括以下五个步骤:

  1. 初始化模块: 加载并初始化 Spire.Doc WebAssembly 模块。
  2. 准备内容: 定义或获取需要转换的 Markdown 字符串。
  3. 创建虚拟文件: 使用 FS.writeFile() 将 Markdown 字符串写入 VFS 中的临时 .md 文件。
  4. 转换文档: 加载虚拟 Markdown 文件并将其保存为 HTML。
  5. 处理输出文件: 从 VFS 中读取 HTML 文件,根据需要进行下载或后续处理。

下面的示例将一段包含标题、列表、代码、链接和表格的 Markdown 字符串转换为 HTML。

import React, { useState, useEffect } from 'react';

function App() {
  const [wasmModule, setWasmModule] = useState(null);

  // 加载 Spire.Doc
  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';

        const spireModule = await import(
          /* webpackIgnore: true */
          `${publicUrl}/spire.doc.js`
        );

        const rawModule = spireModule.default || spireModule;

        window.wasmModule =
          typeof rawModule === 'function'
            ? await rawModule({
                locateFile: (path) =>
                  path.endsWith('.wasm')
                    ? `${publicUrl}/${path}`
                    : path
              })
            : rawModule;

        setWasmModule(window.wasmModule);
      } catch (error) {
        console.error(
          'Failed to load spire.doc.js WASM module:',
          error
        );
      }
    })();
  }, []);

  // 将 Markdown 字符串转换为 HTML
  const convertMarkdownStringToHtml = async () => {
    const wasmModule = window.wasmModule?.spiredoc;

    if (!wasmModule) return;

    // 将所需字体加载到 VFS
    await window.spire.FetchFileToVFS(
      'CALIBRI.ttf',
      '/Library/Fonts/',
      `${process.env.PUBLIC_URL}/static/font/`
    );

    // 定义 Markdown 字符串
    const markdownString = `# 项目文档

本项目提供一个**基于浏览器的文档转换工具**。

## 功能特点

- 将 Markdown 转换为 HTML
- 在浏览器中直接处理文档内容
- 导出生成的 HTML 文件

## 代码示例

\`\`\`javascript
function greet(name) {
  console.log(\`你好,\${name}!\`);
}

greet("世界");
\`\`\`

## 支持的内容

| 功能 | 是否支持 |
|------|----------|
| 标题 | 是 |
| 列表 | 是 |
| 表格 | 是 |
| 链接 | 是 |

有关 Markdown 的更多信息,请访问 [Markdown 官方指南](https://www.markdownguide.org/)。
`;

    const inputFileName = 'MarkdownString.md';
    const outputFileName = 'MarkdownStringToHtml.html';

    // 将 Markdown 字符串写入 VFS
    window.dotnetRuntime.Module.FS.writeFile(
      inputFileName,
      markdownString,
      { encoding: 'utf8' }
    );

    // 创建 Document 实例
    const doc = new wasmModule.Document();

    try {
      // 加载 Markdown 文档
      doc.LoadFromFile({
        fileName: inputFileName,
        fileFormat: wasmModule.FileFormat.Markdown
      });

      // 设置 HTML 导出选项
      doc.HtmlExportOptions.CssStyleSheetType = wasmModule.CssStyleSheetType.Internal;      
      doc.HtmlExportOptions.ImageEmbedded = true;
	  
      // 将文档保存为 HTML
      doc.SaveToFile({
        fileName: outputFileName,
        fileFormat: wasmModule.FileFormat.Html
      });

      // 从 VFS 中读取生成的 HTML 文件
      const htmlBytes =
        window.dotnetRuntime.Module.FS.readFile(
          outputFileName
        );

      // 下载 HTML 文件
      const blob = new Blob(
        [htmlBytes],
        { type: 'text/html;charset=utf-8' }
      );

      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');

      link.href = url;
      link.download = outputFileName;

      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);

      URL.revokeObjectURL(url);
    } finally {
      doc.Dispose();
    }
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>转换 Markdown 字符串为 HTML</h1>

      <button
        onClick={convertMarkdownStringToHtml}
        disabled={!wasmModule}
      >
        转换并下载
      </button>
    </div>
  );
}

export default App;

与前一个示例不同,这里没有现成的 .md 文件需要加载,而是直接通过 FS.writeFile() 将 Markdown 内容写入 VFS:

window.dotnetRuntime.Module.FS.writeFile(
  inputFileName,
  markdownString,
  { encoding: 'utf8' }
);

这种方式同样适用于从 API、数据库、CMS 或文本编辑器中获取的 Markdown 内容。实际使用时,无需在代码中直接定义 markdownString,只需将获取到的 Markdown 内容传入 FS.writeFile() 即可。

输出结果:

在 React 中使用 JavaScript 将 Markdown 字符串转换为 HTML

Markdown 转 HTML 常见问题排查

在 React JavaScript 项目中,常见的转换问题通常与 WebAssembly 初始化、公共资源路径配置,或文件未正确加载到 VFS 有关。下表列出了几种常见问题以及优先检查的内容。

问题 可能原因 检查方法
spiredoc 为 undefined WASM 尚未初始化完成就开始执行转换 在 wasmModule 可用之前保持转换按钮禁用状态
加载运行时文件时出现 404 一个或多个 Spire.Doc 资源缺失,或公共资源路径配置不正确 检查 spire.doc.js、_framework/、WASM 资源以及浏览器的 Network 面板
无法加载 MarkdownExample.md 传递给 FetchFileToVFS() 的源文件路径不正确 确认文件位于 public/static/data/ 目录下
字体加载失败 缺少 CALIBRI.ttf,或字体路径配置不正确 确认字体文件可以通过 public/static/font/ 路径访问
本地转换正常,但部署后失败 部署环境使用了不同的公共基础路径 检查生成的资源 URL,并调整 process.env.PUBLIC_URL 或对应构建工具中的公共路径设置
多次转换后浏览器内存持续增加 创建的 Document 对象未释放 每次转换完成后调用 doc.Dispose(),建议放在 finally 块中执行

常见问题

Q:如何将用户选择的 Markdown 文件转换为 HTML?

A:通过 <input type="file"> 选择的文件,与存放在应用公共资源目录中的 Markdown 文件处理方式不同。

可以先使用浏览器 File API 读取用户选择的文件:

const markdownString = await file.text();

然后使用 FS.writeFile() 将字符串写入 VFS,并按照前面的 Markdown 字符串转换流程进行处理。

Q:可以直接预览生成的 HTML,而不是下载文件吗?

A:可以。先从 VFS 中读取生成的 HTML,并对返回的字节数据进行解码:

const htmlBytes = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const html = new TextDecoder('utf-8').decode(htmlBytes);

得到 HTML 字符串后,可以通过 iframe 显示:

<iframe
  title="HTML Preview"
  srcDoc={html}
/>

安全提示: 如果 Markdown 内容来自不受信任的用户或外部来源,应同样将生成的 HTML 视为不受信任内容。在生产环境中渲染之前,应对其进行安全过滤或采用隔离方式展示。

Q:将 Markdown 转换为 HTML 是否需要后端?

A:不需要。在上述示例中,文档处理通过 WebAssembly 直接在浏览器中完成,源 Markdown 和生成的 HTML 均通过客户端虚拟文件系统进行处理。

不过,如果应用需要存储生成的文件、读取受保护的源内容,或执行其他服务器端操作,仍然可能需要后端服务配合。

总结

本文介绍了如何在 React 中使用 JavaScript 将 Markdown 转换为 HTML,包括 Markdown 文件和 Markdown 字符串两种常见输入方式。借助 WebAssembly,可以直接在浏览器中处理来自文件、编辑器、API 或 CMS 的 Markdown 内容,并将其转换为可下载、可预览或可继续处理的 HTML。两种场景使用的是同一套核心转换逻辑,因此也便于在不同 Markdown 数据来源之间复用。

Spire.PDF for Java 12.9.0 现已正式发布。该版本新增了对 PdfGridCell 富文本的支持,以及 PdfToWordConverter 流输入接口的支持,并修复了 PDF 转图片、PDF 转 PDF/A-2B、 高版本 JDK 模块系统兼容性以及 PDF 合并等方面的问题。详情如下。

新功能:

问题修复:


获取 Spire.PDF for Java 12.9.0,请点击:

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

透视表(PivotTable)是 Excel 中用于快速汇总、分析大量数据的核心工具,通过拖拽字段即可实现数据的统计与对比。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成透视表的创建、筛选与更新操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。

本文介绍三个核心功能点:

有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。


创建透视表

创建透视表通常包括四个步骤:准备源数据、添加透视表、设置字段布局以及计算数据。下面示例在第一个工作表中写入一份产品销售记录,然后通过 PivotCaches.Add 方法基于数据区域创建缓存,使用 PivotTables.Add 方法在工作表中添加透视表,最后将字段拖拽到行区域和数据区域完成布局。

function App() {
  const createPivotTable = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 将字体载入 VFS
    await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // 创建新工作簿
    const workbook = new xlsModule.Workbook();

    // 获取第一个工作表
    const sheet = workbook.Worksheets.get(0);

    // 向单元格写入源数据
    sheet.Range.get('A1').Value = 'Product';
    sheet.Range.get('B1').Value = 'Month';
    sheet.Range.get('C1').Value = 'Count';

    sheet.Range.get('A2').Value = 'SpireDoc';
    sheet.Range.get('A3').Value = 'SpireDoc';
    sheet.Range.get('A4').Value = 'SpireXls';
    sheet.Range.get('A5').Value = 'SpireDoc';
    sheet.Range.get('A6').Value = 'SpireXls';
    sheet.Range.get('A7').Value = 'SpireXls';   

    sheet.Range.get('B2').Value = 'January';
    sheet.Range.get('B3').Value = 'February';
    sheet.Range.get('B4').Value = 'January';
    sheet.Range.get('B5').Value = 'January';
    sheet.Range.get('B6').Value = 'February';
    sheet.Range.get('B7').Value = 'February';

    sheet.Range.get('C2').Value = '10';
    sheet.Range.get('C3').Value = '15';
    sheet.Range.get('C4').Value = '9';
    sheet.Range.get('C5').Value = '7';
    sheet.Range.get('C6').Value = '8';
    sheet.Range.get('C7').Value = '10';

    // 基于数据区域创建透视表缓存
    const dataRange = sheet.Range.get('A1:C7');
    const cache = workbook.PivotCaches.Add({ range: dataRange });

    // 添加透视表
    const pt = sheet.PivotTables.Add('Pivot Table', sheet.Range.get({ row: 10, column: 5 }), cache);

    // 将字段拖入行区域
    const pf1 = pt.PivotFields.get_Item('Product');
    pf1.Axis = xlsModule.AxisTypes.Row;
    const pf2 = pt.PivotFields.get_Item('Month');
    pf2.Axis = xlsModule.AxisTypes.Row;

    // 将字段拖入数据区域
    pt.DataFields.Add(pt.PivotFields.get_Item('Count'), 'Sum of Count', xlsModule.SubtotalTypes.Sum);

    // 设置透视表样式
    pt.BuiltInStyle = xlsModule.PivotBuiltInStyles.PivotStyleMedium12;

    // 计算透视表数据
    pt.CalculateData();
    sheet.AutoFitColumn(5);
    sheet.AutoFitColumn(6);

    // 保存工作簿
    const outputFileName = 'CreatePivotTable_output.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 释放资源
    workbook.Dispose();

    // 从 VFS 读取生成的文件并触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Create Pivot Table</h1>
      <button onClick={createPivotTable}>Start</button>
    </div>
  );
}

export default App;

通过 CalculateData 方法计算后,透视表会按产品与月份汇总各产品的数量总和,并以设置的 PivotStyleMedium12 样式显示。 创建透视表


筛选透视表

当透视表包含较多数据时,可以通过在行字段上添加筛选,只保留符合条件的数据行。

function App() {
  const filterPivotTable = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 将字体和 Excel 文件载入 VFS
    await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'PivotTableExample.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // 加载工作簿
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 获取第二个工作表(PivotTable)中的第一个透视表
    const pt = workbook.Worksheets.get(1).PivotTables.get(0);

    // 获取透视表的第一个行字段
    const rowField = pt.RowFields.get(0);

    // 为行字段添加数值筛选:第一个数据字段的值小于 5300000
    rowField.AddValueFilter(xlsModule.PivotValueFilterType.LessThan, pt.DataFields.get(0), window.spire.Double.Create(5300000), new window.spire.SpireObject(0));

    // 重新计算透视表数据
    pt.CalculateData();

    // 保存工作簿
    const outputFileName = 'FilterPivotTable_output.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 释放资源
    workbook.Dispose();

    // 从 VFS 读取生成的文件并触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Filter Pivot Table</h1>
      <button onClick={filterPivotTable}>Start</button>
    </div>
  );
}

export default App;

原透视表数据 原透视表数据 筛选完成后,透视表的行区域只保留满足筛选条件的数据,便于聚焦分析特定范围的数据。 筛选完成后


更新数据源并刷新透视表

当透视表的基础数据发生变化时,需要更新数据源并刷新透视表缓存,才能让透视表反映最新的汇总结果。

function App() {
  const updateDataSource = async () => {
    // 获取 Spire.XLS WASM 模块
    const xlsModule = window.wasmModule?.spirexls;

    // 检查模块是否就绪
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // 将字体和 Excel 文件载入 VFS
    await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'PivotTableExample.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // 加载工作簿
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 获取数据源工作表并修改其中的单元格值
    const data = workbook.Worksheets.get('Data');
    data.Range.get('A2').Text = 'NewValue';
    data.Range.get('D2').NumberValue = 28000;

    // 获取透视表所在的工作表
    const sheet = workbook.Worksheets.get({ sheetName: 'PivotTable' });

    // 获取工作表上的第一个透视表
    const pt = sheet.PivotTables.get(0);

    // 刷新透视表缓存
    pt.Cache.IsRefreshOnLoad = true;

    // 计算并更新透视表数据
    pt.CalculateData();

    // 保存工作簿
    const outputFileName = 'UpdateDataSource_output.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // 释放资源
    workbook.Dispose();

    // 从 VFS 读取生成的文件并触发下载
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Update Pivot Table Data Source</h1>
      <button onClick={updateDataSource}>Start</button>
    </div>
  );
}

export default App;

数据源更新并刷新后,透视表中对应的汇总结果会同步更新。 更新数据源并刷新透视表


常见问题

创建透视表后没有显示汇总数据

原因:透视表添加字段后未调用 CalculateData 方法,或数据字段未正确添加到数据区域。

解决:完成字段布局后调用 pt.CalculateData() 重新计算透视表,并确保通过 DataFields.Add 方法将数值字段添加到数据区域。

添加筛选后透视表数据没有变化

原因:添加标签或数值筛选后未调用 CalculateData 方法重新计算,或筛选添加到了错误的字段上。

解决:调用 pt.CalculateData() 重新计算透视表,并确认使用 pt.RowFields.get(0) 等属性获取正确的字段后再添加筛选。

更新数据源后透视表数据未变化

原因:修改数据源后未刷新透视表缓存,导致透视表仍保留旧的数据。

解决:修改数据源后,将 pt.Cache.IsRefreshOnLoad 设置为 true 并调用 pt.CalculateData(),使透视表基于最新的数据源重新计算。


获取免费许可证

如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。

Spire.Office 11.8.0 已正式发布。该版本新增了一些功能,如Spire.XLS 新增了对 TEXTSPLIT 公式的支持;Spire.Barcode 同步了 BarcodeSettings 枚举设置到 NETStandard 平台。除此之外,一些在操作Word、Excel、PDF和PPT文档时出现的问题也已成功被修复。更多新功能及问题修复详情如下。

该版本涵盖了最新版的Spire.Doc、Spire.PDF、Spire.XLS、Spire.Presentation、Spire.DataExport、Spire.Barcode、Spire.DocViewer、Spire.PDFViewer、Spire.OfficeViewer、Spire.Email。

版本信息如下:


获取Spire.Office 11.8.0,请点击:

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

Spire.Doc

问题修复:

Spire.XLS

新功能:

问题修复:

Spire.Presentation

问题修复:

Spire.PDF

调整:

问题修复:

Spire.Barcode

新功能:

问题修复:

Spire.Office for Java 11.8.0 已上线。在该版本中,Spire.Doc for Java 增强了 Word 到 PDF 和 SVG 的转换功能;Spire.XLS for Java 修复了 Vaadin 25 + Java 21 环境下项目打包问题;Spire.PDF for Python 优化 PDF 转 Word 转换功能;Spire.Presentation for Java 增强了 PPT 到图片的转换效果。此外,本次更新还成功修复了多个已知问题。更多详情如下。


获取 Spire.Office for Java 11.8.0,请点击:

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

Spire.Doc for Java

问题修复:

Spire.XLS for Java

问题修复:

Spire.Presentation for Java

问题修复:

Spire.PDF for Java

问题修复:

Spire.XLS for Java 16.8.4 现已发布。该版本修复了在 Vaadin 25 + Java 21 环境下打包项目时,因内部类继承 final 类导致构建失败的问题。详情如下。

问题修复:


获取 Spire.XLS for Java 16.8.4 请点击:

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

我们很高兴地宣布 12.8.20 版本正式发布。本次更新重点修复 PDF、OFD 转 Word 文档过程中出现的各类缺陷,程序运行稳定性与版式还原精准度均得到提升。详细更新内容如下:

问题修复:


获取 Spire.PDF for Java 12.8.20 请点击:

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

Spire.Presentation for Java 11.8.3 已发布。该版本主要修复了一个在将 PPT 转换为图片时出现的问题。详情请查看以下内容。

问题修复:


获取Spire.Presentation for Java 11.8.3请点击:

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