Skip to main content

电子表格驱动的 Wails 应用

Wails 是一个用于构建桌面应用的现代工具包。Wails 应用将 Go 驱动的后端与 JavaScript 驱动的前端配对 [^1]。

¥Wails is a modern toolkit for building desktop apps. Wails apps pair a Go-powered backend with a JavaScript-powered frontend[^1].

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

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

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

¥This demo uses Wails and SheetJS to pull data from a spreadsheet and display the data in the app. We'll explore how to load SheetJS in a Wails app and exchange file data between the JavaScript frontend and Go 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

此演示假设你熟悉 Go 编程语言。

¥This demo assumes familiarity with the Go programming language.

对于纯 JavaScript 解决方案,Electron 平台提供了许多开箱即用的原生功能。

¥For a pure JavaScript solution, the Electron platform provides many native features out of the box.

集成详情

¥Integration Details

SheetJS NodeJS 模块 可以安装在 frontend 文件夹中并在前端脚本中导入。

¥The SheetJS NodeJS Module can be installed in the frontend folder and imported in frontend scripts.

Wails 目前不提供相当于 NodeJS fs 的模块。

¥Wails currently does not provide the equivalent of NodeJS fs module.

原始文件数据的读写必须用原生 Go 代码实现。

¥Reading and writing raw file data must be implemented in native Go code.

该演示包含用于显示对话框以及读写文件的原生 Go 代码。在 Go 和 JavaScript 代码之间发送数据时,原始文件被编码为 Base64 字符串。

¥This demo includes native Go code for showing dialogs and reading and writing files. When sending data between Go and JavaScript code, the raw files are encoded as Base64 strings.

读取文件

¥Reading Files

当用户点击 "导入文件" 按钮时,前端告诉 Go 后端读取数据。用户将看到一个文件选择器来选择要读取的文件。Go 后端将读取数据,编码为 Base64 字符串,并将结果发送到前端。

¥When the user clicks the "Import File" button, the frontend tells the Go backend to read data. The user will be presented with a file picker to select a file to read. The Go backend will read the data, encode as a Base64 string, and send the result to the frontend.

前端将使用 SheetJS read 方法 [^2] 解析数据,使用 sheet_to_html[^3] 生成 HTML 表格,并将表格显示在前端。

¥The frontend will parse the data using the SheetJS read method[^2], generate HTML tables with sheet_to_html[^3], and display the tables on the frontend.

下图总结了这些步骤:

¥The following diagram summarizes the steps:

Go

Wails 运行时提供跨平台 OpenFileDialog 函数 [^4] 来显示文件选择器。Go 标准库提供了从所选文件 [^5] 读取数据并编码为 Base64 字符串 [^6] 的方法

¥The Wails runtime provides the cross-platform OpenFileDialog function[^4] to show a file picker. The Go standard library provides methods for reading data from the selected file[^5] and encoding in a Base64 string[^6]

import (
"context"
"encoding/base64"
"os"
"github.com/wailsapp/wails/v2/pkg/runtime"
)

type App struct {
ctx context.Context
}

// ReadFile shows an open file dialog and returns the data as Base64 string
func (a *App) ReadFile() string {
selection, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Select File",
Filters: []runtime.FileFilter{
{ DisplayName: "Excel Workbooks (*.xlsx)", Pattern: "*.xlsx", },
// ... more filters for more file types
},
})
if err != nil { return "" } // The demo app shows an error message
data, err := os.ReadFile(selection)
if err != nil { return "" } // The demo app shows an error message
return base64.StdEncoding.EncodeToString(data)
}

JS

Wails 会自动创建在 JS 中使用的绑定。App 绑定模块将导出函数 ReadFile

¥Wails will automatically create bindings for use in JS. The App binding module will export the function ReadFile.

以下示例使用 SvelteJS 框架:

¥The following example uses the SvelteJS framework:

frontend/src/App.svelte
import { read, utils } from 'xlsx';
import { ReadFile } from '../wailsjs/go/main/App';

async function importFile(evt) {
/* call the native Go function and receive a base64 string */
const b64 = await ReadFile();
/* parse the base64 string with SheetJS */
const wb = read(b64, { type: "base64" });

const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
return utils.sheet_to_html(ws); // generate HTML table
}

写入文件

¥Writing Files

SheetJS write 方法 [^7] 可以以多种格式 [^8] 编写电子表格,包括 XLSX、XLSB、XLS 和 NUMBERS。它需要 bookType 选项。这意味着前端在创建文件之前需要知道输出文件名。

¥The SheetJS write method[^7] can write spreadsheets in a number of formats[^8] including XLSX, XLSB, XLS, and NUMBERS. It expects a bookType option. This means the frontend needs to know the output file name before creating the file.

当用户单击 "导出文件" 按钮时,前端会向 Go 后端询问输出文件名和路径。用户将看到一个文件选择器来选择输出文件夹和工作簿类型。后端会将名称发送到前端。

¥When the user clicks the "Export File" button, the frontend asks the Go backend for the output filename and path. The user will be presented with a file picker to select the output folder and workbook type. The backend will send the name to the frontend.

前端将使用 SheetJS table_to_book 方法 [^9] 从表生成工作簿对象。SheetJS write 方法 [^10] 将从数据生成一个 Base64 字符串。

¥The frontend will generate a workbook object from the table using the SheetJS table_to_book method[^9]. The SheetJS write method[^10] will generate a Base64 string from the data.

前端将 Base64 字符串发送到后端。后端会将数据写入所选文件夹中的文件中。

¥The frontend will send the Base64 string to the backend. The backend will write the data to a file in the selected folder.

Go

将公开两个 Go 函数。

¥Two Go functions will be exposed.

  • SaveFile 将显示文件选择器并返回路径。它将使用跨平台 SaveFileDialog 功能 [^11]。

    ¥SaveFile will show the file picker and return the path. It will use the cross-platform SaveFileDialog function[^11].

import (
"context"
"github.com/wailsapp/wails/v2/pkg/runtime"
)

type App struct {
ctx context.Context
}

func (a *App) SaveFile() string {
selection, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
Title: "Select File",
DefaultFilename: "SheetJSWails.xlsx",
Filters: []runtime.FileFilter{
{ DisplayName: "Excel Workbooks (*.xlsx)", Pattern: "*.xlsx", },
// ... more filters for more file types
},
})
if err != nil { return "" } // The demo app shows an error message
return selection
}
  • WriteFile 在给定 Base64 字符串和文件路径的情况下执行文件写入。Go 标准库提供了解码 Base64 字符串 [^12] 并将数据写入文件系统 [^13] 的方法

    ¥WriteFile performs the file write given a Base64 string and file path. The Go standard library provides methods for decoding Base64 strings[^12] and writing data to the filesystem[^13]

import (
"context"
"encoding/base64"
"os"
)

type App struct {
ctx context.Context
}

func (a *App) WriteFile(b64 string, path string) {
buf, _ := base64.StdEncoding.DecodeString(b64);
_ = os.WriteFile(path, buf, 0644);
}

JS

Wails 会自动创建在 JS 中使用的绑定。App 绑定模块将导出函数 SaveFileWriteFile

¥Wails will automatically create bindings for use in JS. The App binding module will export the functions SaveFile and WriteFile.

以下示例使用 SvelteJS 框架:

¥The following example uses the SvelteJS framework:

frontend/src/App.svelte
import { utils, write } from 'xlsx';
import { SaveFile, WriteFile } from '../wailsjs/go/main/App';

async function exportFile(table_element) {
/* generate workbook */
const wb = utils.table_to_book(table_element);

/* show save picker and get path */
const path = await SaveFile();

/* get the file extension -> bookType */
const bookType = path.slice(path.lastIndexOf(".")+1);

/* generate base64 string */
const b64 = write(wb, { bookType: bookType, type: "base64" });

/* write to file */
await WriteFile(b64, path);
}

完整示例

¥Complete Example

测试部署

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

¥This demo was tested in the following environments:

操作系统和版本架构Wails日期
macOS 14.4darwin-x64v2.8.02024-03-15
macOS 14.5darwin-armv2.8.22024-05-28
Windows 10win10-x64v2.8.02024-03-24
视窗 11win11-armv2.8.22024-05-28
Linux(全息操作系统)linux-x64v2.8.02024-03-21
Linux(Debian)linux-armv2.8.22024-05-28
  1. 阅读 Wails "入门" 指南 [^14] 并安装依赖。

    ¥Read the Wails "Getting Started" guide[^14] and install dependencies.

Installation Notes (click to show)

Wails will require:

  • A recent version of Go.
  • The "LTS" version of NodeJS.

After installing both, run the following command to install Wails:

go install github.com/wailsapp/wails/v2/cmd/wails@latest

Once that finishes, run the following command in a new terminal window:

wails doctor

On macOS and Linux, the PATH environment variable must include ~/go/bin. If wails cannot be found, run the following command in the terminal session:

export PATH="$PATH":~/go/bin

The output will include a # Diagnosis section. It should display:

 SUCCESS  Your system is ready for Wails development!

If a required dependency is missing, it will be displayed.

None of the optional packages are required for building and running this demo.

On the Steam Deck (HoloOS), some dependencies must be reinstalled:

sudo pacman -Syu base-devel gtk3 glib2 pango harfbuzz cairo gdk-pixbuf2 atk libsoup
  1. 创建一个新的 Wails 应用:

    ¥Create a new Wails app:

wails init -n sheetjs-wails -t svelte-ts
cd sheetjs-wails
  1. 安装前端依赖:

    ¥Install front-end dependencies:

cd frontend
curl -o src/assets/logo.png https://sheetjs.com/sketch1024.png
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
cd ..
  1. 下载源文件:

    ¥Download source files:

  • 下载 app.go 并替换 app.go

    ¥Download app.go and replace app.go

  • 下载 App.svelte 并替换 frontend/src/App.svelte

    ¥Download App.svelte and replace frontend/src/App.svelte

curl -o app.go https://xlsx.nodejs.cn/wails/app.go
curl -o frontend/src/App.svelte https://xlsx.nodejs.cn/wails/App.svelte
  1. 构建应用:

    ¥Build the app:

wails build

它将打印生成的程序的路径(通常在 build/bin/ 中)。

¥It will print the path to the generated program (typically in build/bin/).

  1. 运行生成的应用。

    ¥Run the generated application.

测试

¥Testing

该程序将下载 pres.xlsx 并在表格中显示第一个工作表的内容。

¥The program will download pres.xlsx and display the contents of the first worksheet in a table.

要测试导出功能,请单击 "导出 XLSX"。该应用将询问文件名和位置。单击“保存”后,应用将导出到 XLSX。该文件可以在电子表格编辑器(例如 Excel)中打开。

¥To test export features, click "Export XLSX". The app will ask for a file name and location. After clicking Save, the app will export to XLSX. This file can be opened in a spreadsheet editor such as Excel.

[^1]: 请参阅 Wails 文档中的 "它是如何工作的?"

¥See "How does it Work?" in the Wails documentation.

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

¥See read in "Reading Files"

[^3]: 见 sheet_to_html 于 "实用工具"

¥See sheet_to_html in "Utilities"

[^4]: 请参阅 Wails 文档中的 OpenFileDialog

¥See OpenFileDialog in the Wails documentation.

[^5]: 请参阅 Go 文档中的 ReadFile

¥See ReadFile in the Go documentation

[^6]: 请参阅 Go 文档中的 EncodeToString

¥See EncodeToString in the Go documentation

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

¥See write in "Writing Files"

[^8]: 见 "写入文件" 中的 "支持的输出格式" 类型

¥See "Supported Output Formats" type in "Writing Files"

[^9]: 见 "HTML 表格输入" 于 "实用工具"

¥See "HTML Table Input" in "Utilities"

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

¥See write in "Writing Files"

[^11]: 请参阅 Wails 文档中的 SaveFileDialog

¥See SaveFileDialog in the Wails documentation.

[^12]: 请参阅 Go 文档中的 DecodeString

¥See DecodeString in the Go documentation

[^13]: 请参阅 Go 文档中的 WriteFile

¥See WriteFile in the Go documentation

[^14]: 请参阅 Wails 文档中的 "安装"

¥See "Installation" in the Wails documentation.