Skip to main content

NeutralinoJS 中的数据修改

NeutralinoJS 是一个现代桌面应用框架。NeutralinoJS 应用将平台原生浏览器工具与静态 Web 服务器配对。

¥NeutralinoJS is a modern desktop app framework. NeutralinoJS apps pair platform-native browser tools with a static web server.

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

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

该演示使用 NeutralinoJS 和 SheetJS 从电子表格中提取数据并在应用中显示数据。我们将探索如何在 NeutralinoJS 应用中加载 SheetJS 并使用原生功能来读取和写入文件。

¥This demo uses NeutralinoJS and SheetJS to pull data from a spreadsheet and display the data in the app. We'll explore how to load SheetJS in a NeutralinoJS app and use native features to read and write files.

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

¥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 独立脚本 添加到 index.html 入口点。

¥The SheetJS Standalone scripts can be added to the index.html entry point.

对于在窗口中运行的代码,必须在 NeutralinoJS neutralino.conf.json 设置文件 [^1] 中显式启用原生方法。

¥For code running in the window, native methods must be explicitly enabled in the NeutralinoJS neutralino.conf.json settings file[^1].

  • os.* 启用打开和保存对话框方法。

    ¥os.* enables the open and save dialog methods.

  • filesystem.* 允许读取和写入文件数据。

    ¥filesystem.* enables reading and writing file data.

入门应用启用 os.*,因此通常必须添加一行:

¥The starter app enables os.* so typically one line must be added:

neutralino.config.json
  "nativeAllowList": [
"app.*",
"os.*",
"filesystem.*",
"debug.log"
],

读取文件

¥Reading Files

读取文件分为三个步骤:

¥There are three steps to reading files:

  1. 显示带有 Neutralino.os.showOpenDialog[^2] 的打开文件对话框。此方法解析为选定的路径。

    ¥Show an open file dialog with Neutralino.os.showOpenDialog[^2]. This method resolves to the selected path.

  2. 从带有 Neutralino.filesystem.readBinaryFile[^3] 的文件中读取原始数据。此方法解析为标准 ArrayBuffer

    ¥Read raw data from the file with Neutralino.filesystem.readBinaryFile[^3]. This method resolves to a standard ArrayBuffer.

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

    ¥Parse the data with the SheetJS read method[^4]. 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:

const filters = [
{name: "Excel Binary Workbook", extensions: ["xls", "xlsb"]},
{name: "Excel Workbook", extensions: ["xls", "xlsx"]},
]

async function openFile() {
/* show open file dialog */
const [filename] = await Neutralino.os.showOpenDialog(
'Open a spreadsheet',
{ filters, multiSelections: false }
);

/* read data into an ArrayBuffer */
const ab = await Neutralino.filesystem.readBinaryFile(filename);

/* parse with SheetJS */
const wb = XLSX.read(ab);
return wb;
}

此时,标准 SheetJS 实用函数 [^5] 可以从工作簿对象中提取数据。该演示包含一个调用 sheet_to_html[^6] 的按钮来生成 HTML TABLE 并添加到 DOM:

¥At this point, standard SheetJS utility functions[^5] can extract data from the workbook object. The demo includes a button that calls sheet_to_html[^6] to generate an HTML TABLE and add to the DOM:

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

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

/* get data from the first worksheet */
const html = XLSX.utils.sheet_to_html(ws);

/* display table */
document.getElementById('info').innerHTML = html;
};

写入文件

¥Writing Files

读取文件分为三个步骤:

¥There are three steps to reading files:

  1. 显示带有 Neutralino.os.showSaveDialog[^7] 的文件对话框。此方法解析为选定的路径。

    ¥Show a file dialog with Neutralino.os.showSaveDialog[^7]. This method resolves to the selected path.

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

    ¥Write the data with the SheetJS write method[^8]. The output book type can be inferred from the selected file path. Using the buffer output type[^9], the method returns a Uint8Array object that plays nice with NeutralinoJS.

  3. Neutralino.filesystem.writeBinaryFile[^10] 写入文件。

    ¥Write to file with Neutralino.filesystem.writeBinaryFile[^10].

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

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

const filters = [
{name: "Excel Binary Workbook", extensions: ["xls", "xlsb"]},
{name: "Excel Workbook", extensions: ["xls", "xlsx"]},
]

async function saveFile(wb) {
/* show save file dialog */
const filename = await Neutralino.os.showSaveDialog(
'Save to file',
{ filters }
);

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

/* save data to file */
await Neutralino.filesystem.writeBinaryFile(filename, data);
}

该演示包括一个调用 table_to_book[^11] 从 HTML 表生成工作簿对象的按钮:

¥The demo includes a button that calls table_to_book[^11] to generate a workbook object from the HTML table:

const save_button_callback = async() => {
/* get the table */
const tbl = document.getElementById('info').querySelector('table');

/* generate workbook from the table */
const wb = XLSX.utils.table_to_book(tbl);

await saveFile(wb);
}

完整示例

¥Complete Example

测试部署

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

¥This demo was tested in the following environments:

操作系统和版本架构服务器客户日期
macOS 14.4darwin-x645.0.05.0.12024-03-15
macOS 14.5darwin-arm5.1.05.1.02024-05-25
Windows 10win10-x645.1.05.1.02024-03-24
视窗 11win11-arm5.1.05.1.12024-05-28
Linux(全息操作系统)linux-x645.0.05.0.12024-03-21
Linux(Debian)linux-arm5.1.05.1.12024-05-28

win11-arm 上,Electron 运行器是一个正确的 ARM64 二进制文件,但 Electron Forge 生成的二进制文件是 x64。x64 二进制文件在 ARM 上的 Windows 中运行。

¥On win11-arm, the Electron runner is a proper ARM64 binary but the binaries generated by Electron Forge are x64. The x64 binaries run in Windows on ARM.

应用核心状态将是 HTML 表。读取文件会将表格添加到窗口中。写入文件会将表格解析为电子表格。

¥The app core state will be the HTML table. Reading files will add the table to the window. Writing files will parse the table into a spreadsheet.

Installation Notes (click to show)

NeutralinoJS uses portable-file-dialogs[^12] to show open and save dialogs. On Linux, Zenity or KDialog are require.

The last Debian test was run on a system using LXDE. KDialog is supported but must be explicitly installed:

sudo apt-get install kdialog

NeutralinoJS requires libwekit2gtk. On Arch Linux-based platforms including the Steam Deck, webkit2gtk can be installed through the package manager:

sudo pacman -Syu webkit2gtk
  1. 创建一个新的 NeutralinoJS 应用:

    ¥Create a new NeutralinoJS app:

npx @neutralinojs/neu create sheetjs-neu
cd sheetjs-neu
  1. 下载 SheetJS Standalone 脚本并移至 sheetjs-neu 文件夹中的 resources/js/ 子目录:

    ¥Download the SheetJS Standalone script and move to the resources/js/ subdirectory in the sheetjs-neu folder:

curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
  1. 将高亮的行添加到 nativeAllowList 中的 neutralino.config.json

    ¥Add the highlighted line to neutralino.config.json in nativeAllowList:

neutralino.config.json (add highlighted line)
  "nativeAllowList": [
"app.*",
"os.*",
"filesystem.*",
"debug.log"
],

配置文件中可能有多个 nativeAllowList 块。该行必须添加到第一个块。

¥There may be multiple nativeAllowList blocks in the configuration file. The line must be added to the first block.

  1. resources/index.html 的内容替换为以下代码:

    ¥Replace the contents of resources/index.html with the following code:

resources/index.html
<!DOCTYPE html>
<html>


<head>
<meta charset="UTF-8">
<title>SheetJS + NeutralinoJS</title>
<link rel="stylesheet" href="styles.css">
</head>


<body>
<div id="neutralinoapp">
<h1>SheetJS × NeutralinoJS</h1>
<button onclick="importData()">Import Data</button>
<button onclick="exportData()">Export Data</button>
<div id="info"></div>
</div>
<script src="js/neutralino.js"></script>
<!-- Load the browser build and make XLSX available to main.js -->
<script src="js/xlsx.full.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
  1. 将以下代码附加到 resources/styles.css 以使表格居中:

    ¥Append the following code to resources/styles.css to center the table:

resources/styles.css (add to end)
#info {
width:100%;
text-align: unset;
}
table {
margin: 0 auto;
}
  1. resources/js/main.jsshowInfo 方法中打印版本号:

    ¥Print the version number in the showInfo method of resources/js/main.js:

resources/js/main.js (add highlighted lines)
function showInfo() {
document.getElementById('info').innerHTML = `
${NL_APPID} is running on port ${NL_PORT} inside ${NL_OS}
<br/><br/>
<span>server: v${NL_VERSION} . client: v${NL_CVERSION}</span>
<br/><br/>
<span>SheetJS version ${XLSX.version}</span>
`;
}
  1. 运行应用:

    ¥Run the app:

npx @neutralinojs/neu run

The app should print SheetJS Version 0.20.3

  1. resources/js/main.js 的底部添加以下代码:

    ¥Add the following code to the bottom of resources/js/main.js:

resources/js/main.js (add to end)
(async() => {
const ab = await (await fetch("https://xlsx.nodejs.cn/pres.numbers")).arrayBuffer();
const wb = XLSX.read(ab);
const ws = wb.Sheets[wb.SheetNames[0]];
document.getElementById('info').innerHTML = XLSX.utils.sheet_to_html(ws);
})();
  1. 关闭应用。再次运行应用:

    ¥Close the app. Run the app again:

npx @neutralinojs/neu run

应用加载时,主屏幕中应显示一个表格。

¥When the app loads, a table should show in the main screen.

  1. importFileexportFile 添加到 resources/js/main.js 的底部:

    ¥Add importFile and exportFile to the bottom of resources/js/main.js:

resources/js/main.js (add to end)
async function importData() {
/* show open dialog */
const [filename] = await Neutralino.os.showOpenDialog('Open a spreadsheet');

/* read data */
const ab = await Neutralino.filesystem.readBinaryFile(filename);
const wb = XLSX.read(ab);

/* make table */
const ws = wb.Sheets[wb.SheetNames[0]];
document.getElementById('info').innerHTML = XLSX.utils.sheet_to_html(ws);
}

async function exportData() {
/* show save dialog */
const filename = await Neutralino.os.showSaveDialog('Save to file');

/* make workbook */
const tbl = document.getElementById('info').querySelector("table");
const wb = XLSX.utils.table_to_book(tbl);

/* make file */
const bookType = filename.slice(filename.lastIndexOf(".") + 1);
const data = XLSX.write(wb, { bookType, type: "buffer" });
await Neutralino.filesystem.writeBinaryFile(filename, data);
}
  1. 关闭应用。再次运行应用:

    ¥Close the app. Run the app again:

npx @neutralinojs/neu run

应用加载后,单击 "导入文件" 按钮并选择电子表格以查看内容。

¥When the app loads, click the "Import File" button and select a spreadsheet to see the contents.

如果没有显示对话框,请参阅 "安装注意事项" 了解更多详细信息。在 Linux ARM64 上,必须安装 KDialog 或 Zenity。

¥If no dialog is displayed, see the "Installation Notes" for more details. On Linux ARM64, KDialog or Zenity must be installed.

点击 "导出文件",输入 SheetJSNeu.xlsx,写入新文件。

¥Click "Export File" and enter SheetJSNeu.xlsx to write a new file.

保存文件时,必须包含实际的文件扩展名。尝试另存为 SheetJSNeu 不会自动添加 .xlsx 扩展名!

¥When saving the file, the actual file extension must be included. Attempting to save as SheetJSNeu will not automatically add the .xlsx extension!

  1. 构建生产应用:

    ¥Build production apps:

npx @neutralinojs/neu build

将在 dist 文件夹中创建特定于平台的程序:

¥Platform-specific programs will be created in the dist folder:

平台二进制文件路径
darwin-arm./dist/sheetjs-neu/sheetjs-neu-mac_arm64
win11-arm.\dist\sheetjs-neu\sheetjs-neu-win_x64.exe
linux-arm.\dist\sheetjs-neu\sheetjs-neu-linux_arm64

运行生成的应用并确认显示总统数据。

¥Run the generated app and confirm that Presidential data is displayed.

[^1]: 请参阅 NeutralinoJS 文档中的 nativeAllowList

¥See nativeAllowList in the NeutralinoJS documentation

[^2]: 请参阅 NeutralinoJS 文档中的 os.showOpenDialog

¥See os.showOpenDialog in the NeutralinoJS documentation

[^3]: 请参阅 NeutralinoJS 文档中的 filesystem.readBinaryFile

¥See filesystem.readBinaryFile in the NeutralinoJS documentation

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

¥See read in "Reading Files"

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

¥See "Utility Functions"

[^6]: 见 "HTML 表格输出" 于 "实用函数"

¥See "HTML Table Output" in "Utility Functions"

[^7]: 请参阅 NeutralinoJS 文档中的 os.showSaveDialog

¥See os.showSaveDialog in the NeutralinoJS documentation

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

¥See write in "Writing Files"

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

¥See "Supported Output Formats"

[^10]: 请参阅 NeutralinoJS 文档中的 filesystem.writeBinaryFile

¥See filesystem.writeBinaryFile in the NeutralinoJS documentation

[^11]: 见 "HTML 表格输入" 于 "实用函数"

¥See "HTML Table Input" in "Utility Functions"

[^12]: 参见【支持的 portable-file-dialogs 列表】(https://github.com/samhocevar/portable-file-dialogs#status

¥See [the list of supported portable-file-dialogs] (https://github.com/samhocevar/portable-file-dialogs#status)