Skip to main content

Quasar Apps 中的数据

Quasar 是一个 VueJS 框架,用于使用 Cordova 平台构建 iOS 和 Android 应用。

¥Quasar is a VueJS framework for building iOS and Android apps with the Cordova platform.

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

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

该演示使用 Quasar 和 SheetJS 来处理数据并生成电子表格。我们将探讨如何在 Quasar 应用中加载 SheetJS,并使用 Quasar 和 Cordova 功能从设备上的电子表格中提取数据并向其中写入数据。

¥This demo uses Quasar and SheetJS to process data and generate spreadsheets. We'll explore how to load SheetJS in an Quasar app and use Quasar and Cordova features to extract data from, and write data to, spreadsheets on the device.

"演示" 创建一个应用,如下图所示:

¥The "Demo" creates an app that looks like the screenshots below:

iOSAndroid

iOS screenshot

Android screenshot

测试部署

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

¥This demo was tested in the following environments:

真实设备

¥Real Devices

OS设备Quasar日期
安卓 30英伟达盾2.16.42024-06-09
iOS 15.1iPad Pro2.16.42024-06-09

模拟器

¥Simulators

OS设备Quasar开发平台日期
安卓 34像素 3a2.16.4darwin-arm2024-06-09
iOS 17.5iPhone SE(第 3 代)2.16.4darwin-arm2024-06-09
Android 35像素 3a2.16.9win11-x642024-08-20

集成详情

¥Integration Details

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

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

该演示将使用 Quasar ViteJS 入门项目以及 VueJS 和 Cordova。启动器将支持的 Cordova 项目放置在 src-cordova 文件夹中。

¥This demo will use the Quasar ViteJS starter project with VueJS and Cordova. The starter places the backing Cordova project in the src-cordova folder.

完整的解决方案使用 cordova-plugin-file 进行文件操作。可以从 Cordova 文件夹安装:

¥The complete solution uses cordova-plugin-file for file operations. It can be installed from the Cordova folder:

cd src-cordova
cordova plugin add cordova-plugin-file
cd ..

读取数据

¥Reading data

QFile[^1] 组件提供了一个让人想起文件输入元素的 API:

¥The QFile[^1] component presents an API reminiscent of File Input elements:

<q-file label="Load File" filled label-color="orange" @input="updateFile"/>

绑定到 input 元素时,回调会接收 Event 对象。使用标准 DOM 操作,可以将文件数据拉入 ArrayBuffer 并使用 SheetJS read 方法 [^2] 进行解析。read 返回一个 workbook[^3] 对象,该对象保存每个工作表的数据和元数据。

¥When binding to the input element, the callback receives an Event object. Using standard DOM operations, the file data can be pulled into an ArrayBuffer and parsed using the SheetJS read method[^2]. read returns a workbook[^3] object that holds data and metadata for each worksheet.

此代码片段读取工作簿,提取第一个工作表,使用 SheetJS sheet_to_json[^4] 方法生成对象数组,并更新状态:

¥This snippet reads a workbook, pulls the first worksheet, generates an array of objects using the SheetJS sheet_to_json[^4] method, and updates state:

import { read } from 'xlsx';

// assuming `todos` is a standard VueJS `ref`
async function updateFile(v) { try {
// `v.target.files[0]` is the desired file object
const files = (v.target as HTMLInputElement).files;
if(!files || files.length == 0) return;

// read first file
const wb = read(await files[0].arrayBuffer());

// get data of first worksheet as an array of objects
const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);

// update state
todos.value = data.map(row => ({id: row.Index, content: row.Name}));

} catch(e) { console.log(e); } }

写入数据

¥Writing data

SheetJS json_to_sheet 方法 [^5] 从对象数组开始生成一个 SheetJS 工作表对象。book_append_sheetbook_new 辅助函数 [^6] 创建一个可以导出的 SheetJS 工作簿对象:

¥Starting from an array of objects, the SheetJS json_to_sheet method[^5] generates a SheetJS worksheet object. The book_append_sheet and book_new helper functions[^6] create a SheetJS workbook object that can be exported:

import { utils } from 'xlsx';

// assuming `todos` is a VueJS ref whose value is an array of objects
const ws = utils.json_to_sheet(todos.value);
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "SheetJSQuasar");

带有选项 type: "buffer" 的 SheetJS write 函数 [^7] 将生成可以转换为 blob 并导出的 Uint8Array 对象:

¥The SheetJS write function[^7] with the option type: "buffer" will generate Uint8Array objects that can be converted to blobs and exported:

import { write } from 'xlsx';

// on iOS and android, `XLSX.write` with type "buffer" returns a `Uint8Array`
const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"});

cordova-plugin-file API 将数据写入文件系统。该代码使用文件和目录条目 API[^8]:

¥The cordova-plugin-file API writes the data to the filesystem. The code uses the File and Directory Entries API[^8]:

// Request filesystem access for persistent storage
window.requestFileSystem(window.PERSISTENT, 0, function(fs) {
// Request a handle to "SheetJSQuasar.xlsx", making a new file if necessary
fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => {
// Request a FileWriter for writing data
entry.createWriter(writer => {
// The FileWriter API needs an actual Blob
const data = new Blob([u8], {type: "application/vnd.ms-excel"});
// This callback is called if the write is successful
writer.onwriteend = () => {
// TODO: show a dialog
};
// writer.onerror will be invoked if there is an error in writing

// write the data
writer.write(data);
});
});
});

演示

¥Demo

该演示取自 ViteJS 示例。假定熟悉 VueJS 和 TypeScript。

¥The demo draws from the ViteJS example. Familiarity with VueJS and TypeScript is assumed.

  1. 确保所有依赖均已安装。全局安装 CLI:

    ¥Ensure all of the dependencies are installed. Install the CLI globally:

npm i -g @quasar/cli cordova

(如果存在权限问题,可能需要运行 sudo npm i -g

¥(you may need to run sudo npm i -g if there are permission issues)

Installation Notes (click to show)

Quasar requires Java 17

  1. 创建一个新应用:

    ¥Create a new app:

npm init quasar

提示时:

¥When prompted:

  • "你想构建什么?":App with Quasar CLI, let's go!

    ¥"What would you like to build?": App with Quasar CLI, let's go!

  • "项目文件夹":SheetJSQuasar

    ¥"Project folder": SheetJSQuasar

  • "选择 Quasar 版本":Quasar v2 (Vue 3 | latest and greatest)

    ¥"Pick Quasar version": Quasar v2 (Vue 3 | latest and greatest)

  • "选择脚本类型":Typescript

    ¥"Pick script type": Typescript

  • "选择 Quasar App CLI 变体":Quasar App CLI with Vite 2 (stable | v1)

    ¥"Pick Quasar App CLI variant": Quasar App CLI with Vite 2 (stable | v1)

  • "包名字":(按 Enter,它将使用默认的 sheetjsquasar

    ¥"Package name": (press Enter, it will use the default sheetjsquasar)

  • "项目产品名称":SheetJSQuasar

    ¥"Project product name": SheetJSQuasar

  • "项目介绍":SheetJS + Quasar

    ¥"Project description": SheetJS + Quasar

  • "作者":(按 Enter,它将使用你的 git 配置设置)

    ¥"Author": (press Enter, it will use your git config settings)

  • "选择 Vue 组件样式":Composition API

    ¥"Pick a Vue component style": Composition API

  • "选择你的 CSS 预处理器":None

    ¥"Pick your CSS preprocessor": None

  • "检查你的项目所需的功能":取消选择所有内容(向下滚动到每个选定的项目并按 Space

    ¥"Check the features needed for your project": Deselect everything (scroll down to each selected item and press Space)

  • "安装项目依赖":Yes, use npm

    ¥"Install project dependencies": Yes, use npm

  1. 安装依赖:

    ¥Install dependencies:

cd SheetJSQuasar
npm i
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
  1. 设置科尔多瓦:

    ¥Set up Cordova:

npx cordova telemetry off
npx quasar mode add cordova

出现提示时,输入应用 ID org.sheetjs.quasar

¥When prompted, enter the app id org.sheetjs.quasar.

它将创建一个新的 src-cordova 文件夹。在该文件夹中继续:

¥It will create a new src-cordova folder. Continue in that folder:

cd src-cordova
npx cordova platform add ios
npx cordova plugin add cordova-plugin-wkwebview-engine
npx cordova plugin add cordova-plugin-file

如果出现错误 Could not load API for iOS project,则需要重置:

¥If there is an error Could not load API for iOS project, it needs to be reset:

npx cordova platform rm ios
npx cordova platform add ios
npx cordova plugin add cordova-plugin-file

返回项目目录:

¥Return to the project directory:

cd ..
  1. 启用文件共享并使文档文件夹在 iOS 应用中可见。必须将以下行添加到 src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist

    ¥Enable file sharing and make the documents folder visible in the iOS app. The following lines must be added to src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist:

src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist (add to file)
<plist version="1.0">
<dict>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>CFBundleDevelopmentRegion</key>

(文档的根元素是 plist,它包含一个 dict 子元素)

¥(The root element of the document is plist and it contains one dict child)

  1. 启动开发服务器:

    ¥Start the development server:

npx quasar dev -m ios

如果提示选择外部 IP,请按 Enter

¥If prompted to select an external IP, press Enter.

如果应用为空白或不刷新,请删除该应用并关闭模拟器,然后重新启动开发过程。

¥If the app is blank or not refreshing, delete the app and close the simulator, then restart the development process.

  1. 将 Dialog 插件添加到 quasar.config.js

    ¥Add the Dialog plugin to quasar.config.js:

quasar.config.js (add highlighted line)
    framework: {
config: {},
// ...
// Quasar plugins
plugins: ['Dialog']
},
  1. src/pages/IndexPage.vue 的模板部分中,将示例替换为表格、保存按钮和加载文件选择器组件:

    ¥In the template section of src/pages/IndexPage.vue, replace the example with a Table, Save button and Load file picker component:

src/pages/IndexPage.vue (change highlighted lines)
<template>
<q-page class="row items-center justify-evenly">
<q-table :rows="todos" />
<q-btn-group>
<q-file label="Load File" filled label-color="orange" @input="updateFile"/>
<q-btn label="Save File" @click="saveFile" />
</q-btn-group>
</q-page>
</template>

这使用了两个应添加到组件脚本中的函数:

¥This uses two functions that should be added to the component script:

src/pages/IndexPage.vue (add highlighted lines)
    const meta = ref<Meta>({
totalCount: 1200
});
function saveFile() {
}
async function updateFile(v: Event) {
}
return { todos, meta, saveFile, updateFile };
}
});

该应用现在应在底部显示两个按钮:

¥The app should now show two buttons at the bottom:

Quasar Step 6

如果应用为空白或不刷新,请删除该应用并关闭模拟器,然后重新启动开发过程。

¥If the app is blank or not refreshing, delete the app and close the simulator, then restart the development process.

  1. 连接 updateFile 功能:

    ¥Wire up the updateFile function:

src/pages/IndexPage.vue (add highlighted lines)
import { defineComponent, ref } from 'vue';
import { read, write, utils } from 'xlsx';
import { useQuasar } from 'quasar';

export default defineComponent({
// ...
const $q = useQuasar();
function dialogerr(e: Error) { $q.dialog({title: "Error!", message: e.message || String(e)}); }
function saveFile() {
}
async function updateFile(v: Event) {
try {
const files = (v.target as HTMLInputElement).files;
if(!files || files.length == 0) return;

const wb = read(await files[0].arrayBuffer());

const data = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]]);
todos.value = data.map(row => ({id: row.Index, content: row.Name}));
} catch(e) { dialogerr(e); }
}

要测试阅读是否有效:

¥To test that reading works:

  • 下载 https://xlsx.nodejs.cn/pres.numbers

    ¥Download https://xlsx.nodejs.cn/pres.numbers

  • 在模拟器中,单击“主页”图标返回主屏幕

    ¥In the simulator, click the Home icon to return to the home screen

  • 单击 "文件" 图标

    ¥Click on the "Files" icon

  • 单击 pres.numbers 并将其从 Finder 窗口拖动到模拟器中。

    ¥Click and drag pres.numbers from a Finder window into the simulator.

Quasar Step 7 save file

  • 确保高亮 "在我的 iPhone 上" 并选择 "保存"

    ¥Make sure "On My iPhone" is highlighted and select "Save"

  • 再次单击主页图标,然后选择 SheetJSQuasar 应用

    ¥Click the Home icon again then select the SheetJSQuasar app

  • 单击 "加载" 按钮,然后选择 "选择文件",然后选择 pres

    ¥Click the "Load" button, then select "Choose File" and select pres:

Quasar Step 7 load file

选择后,屏幕应刷新并显示新内容。

¥Once selected, the screen should refresh with new contents.

  1. 连接 saveFile 功能:

    ¥Wire up the saveFile function:

src/pages/IndexPage.vue (add highlighted lines)
    function saveFile() {
/* generate workbook from state */
const ws = utils.json_to_sheet(todos.value);
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "SheetJSQuasar");
const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"});
const dir: string = $q.cordova.file.documentsDirectory || $q.cordova.file.externalApplicationStorageDirectory;

/* save to file */
window.requestFileSystem(window.PERSISTENT, 0, function(fs) {
try {
fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => {
const msg = `File stored at ${dir} ${entry.fullPath}`;
entry.createWriter(writer => {
try {
const data = new Blob([u8], {type: "application/vnd.ms-excel"});
writer.onwriteend = () => {
try {
$q.dialog({title: "Success!", message: msg});
} catch(e) { dialogerr(e); }
};
writer.onerror = dialogerr;
writer.write(data);
} catch(e) { dialogerr(e); }
}, dialogerr);
}, dialogerr);
} catch(e) { dialogerr(e) }
}, dialogerr);
}

该页面应恢复为旧内容。

¥The page should revert to the old contents.

要测试写作是否有效:

¥To test that writing works:

  • 单击 "保存存档"。你将看到一个带有位置的弹出窗口:

    ¥Click "Save File". You will see a popup with a location:

Quasar Step 8

  • 找到该文件并验证内容是否正确。在新终端中运行:

    ¥Find the file and verify the contents are correct. Run in a new terminal:

find ~/Library/Developer/CoreSimulator -name SheetJSQuasar.xlsx |
while read x; do echo "$x"; npx xlsx-cli "$x"; done

由于内容已恢复,你应该看到

¥Since the contents reverted, you should see

SheetJSQuasar
id,content
1,ct1
2,ct2
3,ct3
4,ct4
5,ct5
  • 使用 "加载文件" 再次选择 pres.numbers。等待应用刷新。

    ¥Use "Load File" to select pres.numbers again. Wait for the app to refresh.

  • 单击 "保存存档",然后重新运行命令:

    ¥Click "Save File", then re-run the command:

find ~/Library/Developer/CoreSimulator -name SheetJSQuasar.xlsx |
while read x; do echo "$x"; npx xlsx-cli "$x"; done

pres.numbers 的内容现在应该显示,并带有一个新的标题行:

¥The contents from pres.numbers should show up now, with a new header row:

SheetJSQuasar
id,content
42,Bill Clinton
43,GeorgeW Bush
44,Barack Obama
45,Donald Trump
46,Joseph Biden

安卓

¥Android

  1. 创建 Android 项目:

    ¥Create the Android project:

cd src-cordova
cordova platform add android
cd ..
  1. 启动模拟器:

    ¥Start the simulator:

quasar dev -m android

如果提示选择外部 IP,请按 Enter

¥If prompted to select an external IP, press Enter.

如果应用为空白或不刷新,请删除该应用并关闭模拟器,然后重新启动开发过程。

¥If the app is blank or not refreshing, delete the app and close the simulator, then restart the development process.

在 Windows 上,命令失败并出现 Gradle 错误

¥On Windows, the command failed with a Gradle error

Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle
in your path, or install Android Studio

必须提取 Gradle(完整版本),并且必须将 bin 文件夹添加到用户 PATH 变量中。添加到 PATH 后,启动新的 PowerShell 或 CMD 窗口并运行命令。

¥Gradle (the complete version) must be extracted and the bin folder must be added to the user PATH variable. After adding to PATH, launch a new PowerShell or CMD window and run the command.

要测试阅读是否有效:

¥To test that reading works:

  • 单击 pres.numbers 并将其从 Finder 窗口拖动到模拟器中。

    ¥Click and drag pres.numbers from a Finder window into the simulator.

  • 点击 "加载",点击 图标,点击 "下载",然后选择 pres.numbers

    ¥Tap "Load", tap the icon, tap "Downloads" and select pres.numbers.

要测试写作是否有效:

¥To test that writing works:

  • 点击 "保存存档"。你将看到一个带有位置的弹出窗口。

    ¥Tap "Save File". You will see a popup with a location.

  • 从模拟器中提取文件并验证内容:

    ¥Pull the file from the simulator and verify the contents:

adb exec-out run-as org.sheetjs.quasar cat files/files/SheetJSQuasar.xlsx > /tmp/SheetJSQuasar.xlsx
npx xlsx-cli /tmp/SheetJSQuasar.xlsx

iOS 设备

¥iOS Device

  1. 关闭所有打开的模拟器和模拟器。

    ¥Close all open emulators and simulators.

  2. 断开连接到计算机的所有 iOS 或 Android 设备的连接。

    ¥Disconnect any iOS or Android devices connected to the computer.

  3. 将 iOS 设备连接到计算机。

    ¥Connect the iOS device to the computer.

  4. 打开 Xcode 项目:

    ¥Open the Xcode project:

open src-cordova/platforms/ios/SheetJSQuasar.xcodeproj

在导航器中选择 "SheetJSQuasar"。在主窗格中,选择 "签名和能力" 并确保选择了团队。保存并关闭项目。

¥Select "SheetJSQuasar" in the Navigator. In the main pane, select "Signing & Capabilities" and ensure a Team is selected. Save and close the project.

  1. 启动开发过程:

    ¥Start the dev process:

quasar dev -m ios

如果提示选择外部 IP,请按 Enter

¥If prompted to select an external IP, press Enter.

  1. 测试应用:

    ¥Test the application:

  • 按下 Home 按钮(或用一根手指向上滑动)并切换到 Safari。

    ¥Press the Home button (or swipe up with one finger) and switch to Safari.

  • 下载 https://xlsx.nodejs.cn/pres.numbers

    ¥Download https://xlsx.nodejs.cn/pres.numbers

  • 按下 Home 按钮(或用一根手指向上滑动)并选择 SheetJSQuasar 应用

    ¥Press the Home button (or swipe up with one finger) and select the SheetJSQuasar app

  • 点击 "加载" 按钮,然后选择 "选择文件" 并选择下载的 pres.numbers

    ¥Tap the "Load" button, then select "Choose File" and select the downloaded pres.numbers

表格将使用新数据进行更新。

¥The table will update with new data.

  • 点击 "保存存档"

    ¥Tap "Save File"

  • 按下 Home 按钮(或用一根手指向上滑动)并切换到文件。

    ¥Press the Home button (or swipe up with one finger) and switch to Files.

  • 点击 < 直到显示主 "浏览" 窗口,然后选择 "在我的 iPhone 上"

    ¥Tap < until the main "Browse" window is displayed, then select "On My iPhone"

  • 查找 "SheetJSQuasar" 文件夹并点击 SheetJSQuasar.xlsx

    ¥Look for the "SheetJSQuasar" folder and tap SheetJSQuasar.xlsx.

如果设备上安装了 Numbers,它将显示新文件的内容。

¥If Numbers is installed on the device, it will display the contents of the new file.

安卓设备

¥Android Device

  1. 关闭所有打开的模拟器和模拟器。

    ¥Close all open emulators and simulators.

  2. 断开连接到计算机的所有 iOS 或 Android 设备的连接。

    ¥Disconnect any iOS or Android devices connected to the computer.

  3. 将 Android 设备连接到计算机。

    ¥Connect the Android device to the computer.

  4. 启动开发过程:

    ¥Start the dev process:

quasar dev -m android

如果提示选择外部 IP,请按 Enter

¥If prompted to select an external IP, press Enter.

  1. 测试应用:

    ¥Test the application:

  • 按下 Home 按钮(或用一根手指向上滑动)并切换到浏览器。

    ¥Press the Home button (or swipe up with one finger) and switch to Browser.

  • 下载 https://xlsx.nodejs.cn/pres.numbers

    ¥Download https://xlsx.nodejs.cn/pres.numbers

  • 按下 Home 按钮(或用一根手指向上滑动)并选择 SheetJSQuasar 应用

    ¥Press the Home button (or swipe up with one finger) and select the SheetJSQuasar app

  • 点击 "加载" 按钮,然后选择 "选择文件" 并选择下载的 pres.numbers

    ¥Tap the "Load" button, then select "Choose File" and select the downloaded pres.numbers

表格将使用新数据进行更新。

¥The table will update with new data.

"保存存档" 进程将写入文件。但是,Android 30+ 需要 Quasar 中未实现的特殊方法 ("存储访问框架")。

¥The "Save File" process will write files. However, Android 30+ requires special methods ("Storage Access Framework") that are not implemented in Quasar.

[^1]: 请参阅 Quasar 文档中的 "文件选择器"

¥See "File Picker" in the Quasar documentation.

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

¥See read in "Reading Files"

[^3]: 有关工作簿、工作表和其他概念的更多详细信息,请参阅 "SheetJS 数据模型"

¥See "SheetJS Data Model" for more details on workbooks, worksheets, and other concepts.

[^4]: 见 sheet_to_json 于 "实用工具"

¥See sheet_to_json in "Utilities"

[^5]: 见 json_to_sheet 于 "实用工具"

¥See json_to_sheet in "Utilities"

[^6]: 有关 book_newbook_append_sheet 的详细信息,请参阅 "工作簿助手" 于 "实用工具"

¥See "Workbook Helpers" in "Utilities" for details on book_new and book_append_sheet.

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

¥See write in "Writing Files"

[^8]: 有关更多详细信息,请参阅 MDN Web 文档中的 requestFileSystem

¥See requestFileSystem in the MDN Web Docs for more details.