Skip to main content

Tauri 应用中的数据整理

Tauri 是一个用于构建桌面应用的现代工具包。Tauri 应用利用平台原生浏览器引擎来构建轻量级程序。

¥Tauri is a modern toolkit for building desktop apps. Tauri apps leverage platform-native browser engines to build lightweight programs.

SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。

¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.

该演示使用 Tauri 和 SheetJS 从电子表格中提取数据并在应用中显示数据。我们将探索如何在 Tauri 应用中加载 SheetJS 并在 JavaScript 前端和 Rust 后端之间交换文件数据。

¥This demo uses Tauri and SheetJS to pull data from a spreadsheet and display the data in the app. We'll explore how to load SheetJS in a Tauri app and exchange file data between the JavaScript frontend and Rust backend.

"完整示例" 部分涵盖了用于读取和写入工作簿的完整桌面应用。该应用将如下图所示:

¥The "Complete Example" section covers a complete desktop app to read and write workbooks. The app will look like the screenshots below:

WindowsmacOSLinux

Windows screenshot

macOS screenshot

Linux screenshot

集成详情

¥Integration Details

SheetJS NodeJS 模块 可以从 JavaScript 代码安装和导入。

¥The SheetJS NodeJS Module can be installed and imported from JavaScript code.

Tauri 目前不提供相当于 NodeJS fs 的模块。示例中使用的原始 @tauri-apps/api 方法预计不会改变。

¥Tauri currently does not provide the equivalent of NodeJS fs module. The raw @tauri-apps/api methods used in the examples are not expected to change.

出于安全原因,Tauri 应用必须显式启用系统功能。[^1] 它们在配置的 tauri 部分的 allowlist 小节中的 src-tauri/tauri.conf.json 中启用。

¥For security reasons, Tauri apps must explicitly enable system features.[^1] They are enabled in src-tauri/tauri.conf.json in the allowlist subsection of the tauri section of the config.

  • fs 权利 [^2] 允许读取和写入文件数据。

    ¥The fs entitlement[^2] enables reading and writing file data.

src-tauri/tauri.conf.json
  "tauri": {
"allowlist": {
"fs": {
"all": true
}
  • dialog 权利 [^3] 启用打开和保存对话框方法。

    ¥The dialog entitlement[^3] enables the open and save dialog methods.

src-tauri/tauri.conf.json
  "tauri": {
"allowlist": {
"dialog": {
"all": true
}
  • http 权利 [^4] 允许下载文件。请注意,在本地文件系统中读取或写入文件不需要 http

    ¥The http entitlement[^4] enables downloading files. Note that http is not needed for reading or writing files in the local filesystem.

src-tauri/tauri.conf.json
  "tauri": {
"allowlist": {
"http": {
"all": true,
"request": true,
"scope": ["https://**"]
}

读取文件

¥Reading Files

读取文件分为三个步骤:

¥There are three steps to reading files:

  1. 显示打开文件对话框以允许用户选择路径。@tauri-apps/api/dialog[^5] 中的 open 方法简化了这个过程。

    ¥Show an open file dialog to allow users to select a path. The open method in @tauri-apps/api/dialog[^5] simplifies this process.

  2. 使用 @tauri-apps/api/fs[^6] 中的 readBinaryFile 方法从所选文件中读取原始数据。此方法解析为标准 Uint8Array

    ¥Read raw data from the selected file using the readBinaryFile method in @tauri-apps/api/fs[^6]. This method resolves to a standard Uint8Array

  3. 使用 SheetJS read 方法 [^7] 解析数据。此方法返回一个 SheetJS 工作簿对象。

    ¥Parse the data with the SheetJS read method[^7]. This method returns a SheetJS workbook object.

以下代码示例定义了一个函数 openFile,该函数执行所有三个步骤并返回 SheetJS 工作簿对象:

¥The following code example defines a single function openFile that performs all three steps and returns a SheetJS workbook object:

import { read } from 'xlsx';
import { open } from '@tauri-apps/api/dialog';
import { readBinaryFile } from '@tauri-apps/api/fs';

const filters = [
{name: "Excel Binary Workbook", extensions: ["xlsb"]},
{name: "Excel Workbook", extensions: ["xlsx"]},
{name: "Excel 97-2004 Workbook", extensions: ["xls"]},
// ... other desired formats ...
];

async function openFile() {
/* show open file dialog */
const selected = await open({
title: "Open Spreadsheet",
multiple: false,
directory: false,
filters
});

/* read data into a Uint8Array */
const d = await readBinaryFile(selected);

/* parse with SheetJS */
const wb = read(d);
return wb;
}

此时,标准 SheetJS 实用函数 [^8] 可以从工作簿对象中提取数据。该演示包括一个调用 sheet_to_json[^9] 的按钮来生成数据数组的数组。

¥At this point, standard SheetJS utility functions[^8] can extract data from the workbook object. The demo includes a button that calls sheet_to_json[^9] to generate an array of arrays of data.

以下代码片段显示了一个简单的 Kaioponent:

¥The following snippet shows a simple Kaioponent:

Kaioponent for importing data
import { utils } from 'xlsx';
import { useState } from 'kaioken';

function SheetJSImportKaioponent() {
const [data, setData] = useState<any[][]>([]);

const open_callback = async() => {
const wb = await openFile();

/* get the first worksheet */
const ws = wb.Sheets[wb.SheetNames[0]];

/* get data from the first worksheet */
const array = utils.sheet_to_json(ws, { header: 1 });
setData(array);
};

return ( <>
<button type="button" onclick={open_callback}>Load Data</button>


<table>

<tbody>{data.map((row) =>
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
)}</tbody>

</table>


</> );
}

写入文件

¥Writing Files

写入文件分为三个步骤:

¥There are three steps to writing files:

  1. 显示保存文件对话框以允许用户选择路径。@tauri-apps/api/dialog[^10] 中的 save 方法简化了这个过程。

    ¥Show a save file dialog to allow users to select a path. The save method in @tauri-apps/api/dialog[^10] simplifies this process.

  2. 使用 SheetJS write 方法 [^11] 写入数据。可以从选定的文件路径推断输出的书籍类型。使用 buffer 输出类型 [^12],该方法将返回一个与 Tauri 配合良好的 Uint8Array 对象。

    ¥Write the data with the SheetJS write method[^11]. The output book type can be inferred from the selected file path. Using the buffer output type[^12], the method will return a Uint8Array object that plays nice with Tauri.

  3. 使用 writeBinaryFile 将数据写入 @tauri-apps/api/fs[^13] 中。

    ¥Write the data using writeBinaryFile in @tauri-apps/api/fs[^13].

以下代码示例定义了一个函数 saveFile,该函数从 SheetJS 工作簿对象开始执行所有三个步骤:

¥The following code example defines a single function saveFile that performs all three steps starting from a SheetJS workbook object:

import { write } from 'xlsx';
import { save } from '@tauri-apps/api/dialog';
import { writeBinaryFile } from '@tauri-apps/api/fs';

const filters = [
{name: "Excel Binary Workbook", extensions: ["xlsb"]},
{name: "Excel Workbook", extensions: ["xlsx"]},
{name: "Excel 97-2004 Workbook", extensions: ["xls"]},
// ... other desired formats ...
];

async function saveFile(wb) {
/* show save file dialog */
const selected = await save({
title: "Save to Spreadsheet",
filters
});
if(!selected) return;

/* Generate workbook */
const bookType = selected.slice(selected.lastIndexOf(".") + 1);
const d = write(wb, {type: "buffer", bookType});

/* save data to file */
await writeBinaryFile(selected, d);
}

该演示包括一个按钮,该按钮调用 aoa_to_sheet[^14] 从数据数组生成一个工作表。使用 book_newbook_append_sheet[^15] 构建工作簿。

¥The demo includes a button that calls aoa_to_sheet[^14] to generate a sheet from array of arrays of data. A workbook is constructed using book_new and book_append_sheet[^15].

以下代码片段显示了一个简单的 Kaioponent:

¥The following snippet shows a simple Kaioponent:

Kaioponent for exporting data
import { utils } from 'xlsx';
import { useState } from 'kaioken';

function SheetJSExportKaioponent() {
const [data, setData] = useState<any[][]>(["SheetJS".split(""), "Kaioken".split("")]);

const save_callback = async() => {
/* generate worksheet from the data */
const ws = utils.aoa_to_sheet(data);

/* create a new workbook object */
const wb = utils.book_new();

/* append the worksheet to the workbook using the sheet name "SheetJSTauri" */
utils.book_append_sheet(wb, ws, "SheetJSTauri");

await saveFile(wb);
}

return ( <button type="button" onclick={save_callback}>Save Data</button> );
}

完整示例

¥Complete Example

测试部署

本 demo 在以下环境下进行了测试:

¥This demo was tested in the following environments:

操作系统和版本架构Tauri日期
macOS 14.4darwin-x64v1.5.112024-04-20
macOS 14.5darwin-armv1.5.142024-05-26
Windows 10win10-x64v1.5.112024-03-24
视窗 11win11-armv1.5.142024-05-28
Linux(全息操作系统)linux-x64v1.5.112024-03-21
Linux(Debian)linux-armv1.5.142024-05-28
  1. 阅读 Tauri "入门" 指南并安装先决条件.[^16]

    ¥Read Tauri "Getting Started" guide and install prerequisites.[^16]

Installation Notes (click to show)

At a high level, the following software is required for building Tauri apps:

  • a native platform-specific C/C++ compiler (for example, macOS requires Xcode)
  • a browser engine integration (for example, linux requires webkit2gtk)
  • Rust

The platform configuration can be verified by running:

npx @tauri-apps/cli info

If required dependencies are installed, the output will show a checkmark next to "Environment". The output from the most recent macOS test is shown below:

[✔] Environment - OS: Mac OS 14.4.1 X64 Xcode Command Line Tools: installed rustc: 1.77.2 (25ef9e3d8 2024-04-09) cargo: 1.77.2 (e52e36006 2024-03-26) rustup: 1.27.0 (bbb9276d2 2024-03-08) Rust toolchain: stable-x86_64-apple-darwin (default) - node: 20.12.1 - npm: 10.5.0 - bun: 1.1.4

When the demo was last tested on ARM64 macOS, the output mentioned X64. The build step will correctly detect the platform architecture.

  1. 创建一个新的 Tauri 应用:

    ¥Create a new Tauri app:

没有官方的 Tauri Kaioken 模板。该演示从普通 TypeScript 模板开始并手动连接 Kaioken

¥There is no official Tauri Kaioken template. This demo starts from the vanilla TypeScript template and manually wires Kaioken

npm create tauri-app@latest -- -m npm -t vanilla-ts SheetJSTauri -y
  1. 进入目录并安装依赖:

    ¥Enter the directory and install dependencies:

cd SheetJSTauri
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
npm i --save @tauri-apps/api
npm i --save-dev @tauri-apps/cli

安装 Kaioken 依赖:

¥Install the Kaioken dependencies:

npm add kaioken --save
npm add vite-plugin-kaioken -D --save
  1. 将高亮的行添加到 tauri.allowlist 部分中的 src-tauri/tauri.conf.json

    ¥Add the highlighted lines to src-tauri/tauri.conf.json in the tauri.allowlist section:

src-tauri/tauri.conf.json (add highlighted lines)
  "tauri": {
"allowlist": {
"http": {
"all": true,
"request": true,
"scope": ["https://**"]
},
"dialog": {
"all": true
},
"fs": {
"all": true
},

在同一文件中,查找 "title" 并将值更改为 SheetJS x Tauri

¥In the same file, look for "title" and change the value to SheetJS x Tauri:

src-tauri/tauri.conf.json (edit highlighted line)
      {
"title": "SheetJS x Tauri",
"width": 800,

在同一文件中,查找 "identifier" 并将值更改为 com.sheetjs.tauri

¥In the same file, look for "identifier" and change the value to com.sheetjs.tauri:

src-tauri/tauri.conf.json (edit highlighted line)
      "targets": "all",
"identifier": "com.sheetjs.tauri",
"icon": [
  1. 将 Kaioken 连接到 Tauri 应用:

    ¥Wire up Kaioken to the Tauri app:

  • 将高亮的行添加到 vite.config.ts

    ¥Add the highlighted lines to vite.config.ts:

vite.config.ts (add highlighted lines)
import { defineConfig } from "vite";
import kaioken from "vite-plugin-kaioken";

// https://vitejs.dev/config/
export default defineConfig(async () => ({
plugins: [kaioken()],
  • 编辑 tsconfig.json。在 compilerOptions 中添加选项 "jsx": "preserve"

    ¥Edit tsconfig.json. In compilerOptions add the option "jsx": "preserve":

tsconfig.json (add highlighted line)
{
"compilerOptions": {
"jsx": "preserve",
  • index.html 替换为以下代码块:

    ¥Replace index.html with the following codeblock:

index.html
<!doctype html>
<html lang="en">


<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="/src/styles.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SheetJS x Tauri</title>
<script type="module" src="/src/main.ts" defer></script>
</head>



<body>
<div id="container" class="container"></div>
</body>
</html>
  • 将以下行添加到 src/styles.css

    ¥Add the following lines to src/styles.css:

src/styles.css (add to end)
.logo {
padding: 0px;
height: 64px; width: 64px;
vertical-align: middle;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.centre { text-align: center; }
table.center {
margin-left: auto;
margin-right: auto;
}
  • src/main.ts 替换为以下代码块:

    ¥Replace src/main.ts with the following codeblock:

src/main.ts
import { mount } from "kaioken";
import App from "./App";

const root = document.getElementById("container");
mount(App, root!);
  • 下载 App.tsx 并保存到 src/App.tsx

    ¥Download App.tsx and save to src/App.tsx:

curl -o src/App.tsx https://xlsx.nodejs.cn/tauri/App.tsx
  1. 构建应用

    ¥Build the app with

npm run tauri build

最后,它将打印生成的安装程序的路径。

¥At the end, it will print the path to the generated installer.

如果构建失败,请参阅 "故障排除" 了解更多详细信息。

¥If the build fails, see "Troubleshooting" for more details.

  1. 运行程序。

    ¥Run the program.

根据 Tauri 的版本,命令可能是

¥Depending on the version of Tauri, the command may be

./src-tauri/target/release/SheetJSTauri

or

./src-tauri/target/release/sheet-js-tauri

or

./src-tauri/target/release/sheetjstauri

应手动验证以下功能:

¥The following features should be manually verified:

  • 加载后,应用将下载 https://xlsx.nodejs.cn/pres.numbers 并将数据显示在表格中。

    ¥When it is loaded, the app will download https://xlsx.nodejs.cn/pres.numbers and display the data in a table.

  • 单击 "保存数据" 将显示保存对话框。选择路径和名称后,应用将写入一个文件。该文件可以在电子表格编辑器中打开。

    ¥Clicking "Save Data" will show a save dialog. After selecting a path and name, the app will write a file. That file can be opened in a spreadsheet editor.

  • 在电子表格编辑器中编辑文件,然后单击 "加载数据" 并选择编辑后的文件。该表将刷新为新内容。

    ¥Edit the file in a spreadsheet editor, then click "Load Data" and select the edited file. The table will refresh with new contents.

故障排除

¥Troubleshooting

在上次 Linux ARM64 测试中,构建无法创建 AppImage:

¥During the last Linux ARM64 test, the build failed to create an AppImage:

        Error [tauri-cli-node] failed to bundle project: error running appimage.sh

这是一个已知的 Tauri AppImage 打包错误。由于实际应用和 .deb 可分发文件已创建,因此可以忽略该错误。

¥This is a known Tauri AppImage packaging bug. Since the actual application and the .deb distributable are created, the error can be ignored.

在上次 Linux x64 测试期间,构建失败并显示错误消息:

¥During the last Linux x64 test, the build failed with the error message:

'openssl/opensslv.h' file not found

必须安装 OpenSSL。在 Arch Linux 和 HoloOS (Steam Deck) 上:

¥OpenSSL must be installed. On Arch Linux and HoloOS (Steam Deck):

sudo pacman -S openssl

在某些 macOS 测试中,构建失败并显示以下错误消息:

¥In some macOS tests, the build failed with the following error message:

       Error failed to bundle project: error running bundle_dmg.sh

可以通过运行发现错误的根本原因

¥The root cause of the error can be discovered by running

npm run tauri build -- --verbose

最近的测试失败并显示一条消息:

¥The most recent test failed with a message:

execution error: Not authorized to send Apple events to Finder

通过允许终端控制 Finder 解决了此错误。

¥This error was resolved by allowing Terminal to control Finder.

在 "系统设置" 应用中,在左栏中选择 "隐私与安全",然后在正文中选择 "自动化"。查找 "终端",展开该部分,然后启用 "发现者"。

¥In the "System Settings" app, select "Privacy & Security" in the left column and select "Automation" in the body. Look for "Terminal", expand the section, and enable "Finder".

在一些测试中,字体与屏幕截图不匹配。

¥In some tests, the fonts did not match the screenshots.

必须手动下载并安装 Inter 字体静态 TTF。[^17]

¥The Inter font static TTFs must be manually downloaded and installed.[^17]

[^1]: 请参阅 Tauri 文档中的 "安全"

¥See "Security" in the Tauri documentation

[^2]: 请参阅 Tauri 文档中的 FsAllowlistConfig

¥See FsAllowlistConfig in the Tauri documentation

[^3]: 请参阅 Tauri 文档中的 DialogAllowlistConfig

¥See DialogAllowlistConfig in the Tauri documentation

[^4]: 请参阅 Tauri 文档中的 HttpAllowlistConfig

¥See HttpAllowlistConfig in the Tauri documentation

[^5]: 请参阅 Tauri 文档中的 dialog

¥See dialog in the Tauri documentation

[^6]: 请参阅 Tauri 文档中的 fs

¥See fs in the Tauri documentation

[^7]: 见 read 于 "读取文件"

¥See read in "Reading Files"

[^8]: 见 "实用函数"

¥See "Utility Functions"

[^9]: 见 "数组输出" 于 "实用函数"

¥See "Array Output" in "Utility Functions"

[^10]: 请参阅 Tauri 文档中的 dialog

¥See dialog in the Tauri documentation

[^11]: 见 write 于 "写入文件"

¥See write in "Writing Files"

[^12]: 见 "支持的输出格式"

¥See "Supported Output Formats"

[^13]: 请参阅 Tauri 文档中的 fs

¥See fs in the Tauri documentation

[^14]: 见 "数组的数组输入" 于 "实用函数"

¥See "Array of Arrays Input" in "Utility Functions"

[^15]: 见 "工作簿助手" 于 "实用函数"

¥See "Workbook Helpers" in "Utility Functions"

[^16]: 请参阅 Tauri 文档中的 "先决条件"

¥See "Prerequisites" in the Tauri documentation

[^17]: 单击 Inter Google 字体列表 中的 "获取字体"

¥Click "Get font" in the Inter Google Fonts listing