Skip to main content

使用 Lynx 以原生速度运行 Sheets

Lynx 是一个现代的跨平台框架。它构建使用 JavaScript 描述布局和事件的 iOS、Android 和 Web 应用。

¥Lynx is a modern cross-platform framework. It builds iOS, Android and Web apps that use JavaScript for describing layouts and events.

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

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

Lynx 支持仍处于实验阶段。

Lynx 相对较新,目前还没有一个深入的社区。

¥Lynx is relatively new and does not currently have a deep community.

任何问题都应报告给 Lynx 项目以进行进一步诊断。

¥Any issues should be reported to the Lynx project for further diagnosis.

此演示使用 React(使用 ReactLynx)和 SheetJS 来处理和生成电子表格。我们将探讨如何在以下场景中在 Lynx 应用中加载 SheetJS:

¥This demo uses React (using ReactLynx) and SheetJS to process and generate spreadsheets. We'll explore how to load SheetJS in Lynx apps in the following scenarios:

"获取远程数据" 示例创建了一个如下屏幕截图所示的应用:

¥The "Fetching Remote Data" example creates an app that looks like the screenshots below:

iOSAndroid

iOS screenshot

Android screenshot

在测试此演示之前,请遵循官方的 React Lynx 指南![^1]

¥Before testing this demo, follow the official React Lynx Guide![^1]

请按照 iOS(需要 macOS)和 Android 的说明进行操作。它们将涵盖安装和系统配置。你应该能够在 Android 和 iOS(如果适用)模拟器中构建并运行示例应用。

¥Follow the instructions for iOS (requires macOS) and for Android. They will cover installation and system configuration. You should be able to build and run a sample app in the Android and the iOS (if applicable) simulators.

Lynx 开发需要使用 Apple Silicon 芯片的 Macintosh!

¥Lynx development requires an Apple Silicon-powered Macintosh!

目前不支持 X64 系统。

¥X64 is currently unsupported.

集成详情

¥Integration Details

SheetJS NodeJS 模块 可以从应用中的任何组件或脚本导入。

¥The SheetJS NodeJS Module can be imported from any component or script in the app.

内部状态

¥Internal State

为简单起见,该演示使用 "数组的数组"[^2] 作为内部状态。

¥For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state.

SpreadsheetArray of Arrays

pres.xlsx data

[
["Name", "Index"],
["Bill Clinton", 42],
["GeorgeW Bush", 43],
["Barack Obama", 44],
["Donald Trump", 45],
["Joseph Biden", 46]
]

每个数组代表表中的一行。

¥Each array represents a row in the table.

该演示还以单个数字数组的形式跟踪列宽。显示组件使用宽度。

¥This demo also keeps track of the column widths as a single array of numbers. The widths are used by the display component.

State variables
const [data, setData] = useState<any[]>([
"SheetJS".split(""),
[5, 4, 3, 3, 7, 9, 5],
[8, 6, 7, 5, 3, 0, 9]
]);
const [widths, setWidths] = useState<number[]>(Array.from({ length: 7 }, () => 20));

更新状态

¥Updating State

从 SheetJS 工作表对象开始,带有 header 选项的 sheet_to_json[^3] 可以生成数组的数组:

¥Starting from a SheetJS worksheet object, sheet_to_json[^3] with the header option can generate an array of arrays:

Updating state from a workbook
/* assuming `wb` is a SheetJS workbook */
function update_state(wb) {
/* convert first worksheet to AOA */
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = utils.sheet_to_json(ws, {header:1});

/* update state */
setData(data);

/* update column widths */
setWidths(make_width(data));
}

计算列宽

¥Calculating Column Widths

可以通过遍历每列并计算最大数据宽度来计算列宽度。使用数组的数组:

¥Column widths can be calculated by walking each column and calculating the max data width. Using the array of arrays:

Calculating column widths
/* this function takes an array of arrays and generates widths */
function make_width(aoa) {
/* walk each row */
aoa.forEach((r) => {
/* walk each column */
r.forEach((c, C) => {
/* update column width based on the length of the cell contents */
res[C] = Math.max(res[C]||60, String(c).length * 10);
});
});
/* use a default value for columns with no data */
for(let C = 0; C < res.length; ++C) if(!res[C]) res[C] = 60;
return res;
}

显示数据

¥Displaying Data

Lynx 不附带用于显示表格数据的组件。

¥Lynx does not ship with a component for displaying tabular data.

该演示程序使用 Lynx <view/><text/> 元素来显示表格数据:

¥The demo uses Lynx <view/> and <text/> elements to display tabular data:

Example JSX for displaying data
{/* Table container */}
<view className='Table'>
{/* Map through each row in the data array */}
{data.map((row, rowIndex) => (
<view key={`row-${rowIndex}`} className="Row">
{/* Map through each cell in the current row */}
{Array.isArray(row) && row.map((cell, cellIndex) => (
{/* Cell with dynamic width based on content */}
<view
key={`cell-${rowIndex}-${cellIndex}`} className="Cell"
style={{ width: `${widths[cellIndex]}px` }}>
{/* Display cell content as text */}
<text>{String(cell)}</text>
</view>
))}
</view>
))}
</view>

获取远程数据

¥Fetching Remote Data

此代码片段下载并解析 https://xlsx.nodejs.cn/pres.xlsx

¥This snippet downloads and parses https://xlsx.nodejs.cn/pres.xlsx:

/* fetch data into an ArrayBuffer */
const ab = await (await fetch("https://xlsx.nodejs.cn/pres.xlsx")).arrayBuffer();
/* parse data */
const wb = XLSX.read(ab);

获取演示

¥Fetch Demo

测试部署

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

¥This demo was tested in the following environments:

模拟器

¥Simulators

OS设备LynxLynxExplorer开发平台日期
Android 35像素 3a0.8.63.2.0-rc.1darwin-arm2025-03-26
iOS 18.3iPhone 16 Pro0.8.63.2.0-rc.1darwin-arm2025-03-26
真实设备

上次测试此演示时,没有关于在真实设备上运行 Lynx 应用的简单独立指南。

¥When this demo was last tested, there was no simple standalone guide for running Lynx apps on real devices.

首先按照指南 [^1] 安装 Lynx。

¥First install Lynx by following the Guide![^1].

继续之前,请确保你可以在模拟器上运行一个基本的测试应用!

¥Make sure you can run a basic test app on your simulator before continuing!

  1. 安装 Lynx 依赖

    ¥Install Lynx dependencies

  2. 创建项目:

    ¥Create project:

npm create rspeedy@0.8.6 -- -d SheetJSLynxFetch -t react-ts --tools biome
  1. 安装共享依赖:

    ¥Install shared dependencies:

cd SheetJSLynxFetch
curl -o ./src/assets/SheetJS-logo.png https://xlsx.nodejs.cn/logo.png
npm i
npm i -S https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
  1. App.tsx 下载到 src 文件夹:

    ¥Download App.tsx into the src folder:

curl -o ./src/App.tsx https://xlsx.nodejs.cn/lynx/App.tsx
  1. App.css 下载到 src 文件夹:

    ¥Download App.css into the src folder:

curl -o ./src/App.css https://xlsx.nodejs.cn/lynx/App.css
  1. 启动开发服务器:

    ¥Start the development server:

npm run dev

保持窗户打开。

¥Keep the window open.

安卓

¥Android

  1. 启动 Android 模拟器:

    ¥Start the Android emulator:

在 Android Studio 中,单击 "更多操作" > "虚拟设备管理器"。在列表中查找模拟设备,然后单击 ▶ 按钮进行播放。

¥In Android Studio, click "More actions" > "Virtual Device Manager". Look for the emulated device in the list and click the ▶ button to play.

  1. 下载 LynxExplorer[^4] APK。

    ¥Download the LynxExplorer[^4] APK.

最新测试使用了 LynxExplorer-noasan-release.apk for version 3.2.0-rc.1

¥The latest test used LynxExplorer-noasan-release.apk for version 3.2.0-rc.1.

  1. 将 APK 拖放到 Android 模拟器窗口中。

    ¥Drag and drop the APK into the Android emulator window.

模拟器将安装 LynxExplorer。

¥The emulator will install LynxExplorer.

  1. 步骤 5 的终端窗口中,复制 HTTP 链接。它将打印在二维码下方,如下图所示:

    ¥In the terminal window from step 5, copy the HTTP link. It will be printed below the QR code, as shown in the following screenshot:

lynx live server link

  1. 在模拟器中,打开 "LynxExplorer" 应用。

    ¥In the emulator, open the "LynxExplorer" app.

  2. 在“输入卡片 URL”输入字段中,粘贴链接。点击“开始”。

    ¥In the Enter Card URL input field, paste the link. Tap Go.

视图将会刷新。应用应如 "之前" 屏幕截图所示:

¥The view will refresh. The app should look like the "Before" screenshot:

BeforeAfter

before screenshot

after screenshot

  1. 点击 "从电子表格导入数据" 并确认应用显示新数据。应用应如 "之后" 屏幕截图所示。

    ¥Tap "Import data from a spreadsheet" and verify that the app shows new data. The app should look like the "After" screenshot.

iOS 测试

¥iOS Testing

iOS 测试只能在运行 macOS 的 Apple 硬件上执行!

¥iOS testing can only be performed on Apple hardware running macOS!

Xcode 和 iOS 模拟器在 Windows 或 Linux 上不可用。

¥Xcode and iOS simulators are not available on Windows or Linux.

  1. 下载 LynxExplorer[^4] 应用包。

    ¥Download the LynxExplorer[^4] app tarball.

最新测试使用了 LynxExplorer-arm64.app.tar.gz for version 3.2.0-rc.1

¥The latest test used LynxExplorer-arm64.app.tar.gz for version 3.2.0-rc.1.

  1. 使用 Finder 打开 LynxExplorer-arm64.app.tar.gz

    ¥Open LynxExplorer-arm64.app.tar.gz using Finder.

tarball 包含一个名为 LynxExplorer-arm64 的应用。

¥The tarball contains an app named LynxExplorer-arm64 .

  1. 启动 iOS 模拟器。

    ¥Launch the iOS Simulator.

  2. 点击 LynxExplorer-arm64 并将其拖到模拟器窗口中。

    ¥Click and drag LynxExplorer-arm64 into the Simulator window.

模拟器将安装 "LynxExplorer" 应用。

¥The simulator will install the "LynxExplorer" app.

  1. 步骤 5 中的终端窗口复制 HTTP 链接。

    ¥Copy the HTTP link from the terminal window in step 5.

lynx live server link

  1. 点击模拟器中的 "LynxExplorer" 图标启动应用。

    ¥Tap the "LynxExplorer" icon in the simulator to launch the app.

  2. 点击“输入卡片 URL”输入框并粘贴链接。点击“开始”。

    ¥Tap the Enter Card URL input field and paste the link. Tap Go.

视图将会刷新。应用应如 "之前" 屏幕截图所示:

¥The view will refresh. The app should look like the "Before" screenshot:

BeforeAfter

before screenshot

after screenshot

  1. 点击 "从电子表格导入数据" 并确认应用显示新数据。应用应如 "之后" 屏幕截图所示。

    ¥Tap "Import data from a spreadsheet" and verify that the app shows new data. The app should look like the "After" screenshot.

[^1]: 按照 Lynx 文档中的 "快速开始" 操作,并选择合适的 "Lynx Explorer 沙盒"。

¥Follow "Quick Start" in the Lynx documentation and select the appropriate "Lynx Explorer sandbox"

[^2]: 见 API 参考中的 "数组的数组"

¥See "Array of Arrays" in the API reference

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

¥See "Array Output" in "Utility Functions"

[^4]: 见 "LynxExplorer 沙盒"

¥See "LynxExplorer sandbox"