本文深入解析JavaScript应用中的数据共享与传递机制。内容涵盖UI、Page及App三级作用域的定义,详细阐述do_Global内存共享、全局变量、SQLite内存模式及文件共享的实现方式,并重点介绍基于消息机制和openPage/closePage的跨作用域数据传递方法,帮助开发者构建高效稳定的应用架构。
数据共享与传递概述
数据共享与数据传递是相辅相成的两个概念,本文将对此进行详细探讨。首先需要明确的是,无论是共享还是传递,都受到作用域的限制。所谓作用域,即数据生效的范围。在同一个作用域内,数据可以实现共享;一旦超出该范围,即涉及跨作用域的数据传递。
作用域层级解析
作用域
1. UI作用域
每个UI文件默认对应一个ui.js文件,二者构成一个封闭的作用域。在ui.js中,可以通过UI文件中定义的组件ID来获取对应的UI对象。不同的UI文件可以定义相同ID的组件。需要注意的是,在ui.js中定义的变量仅能在该JS文件内部访问。
2. Page作用域
每次调用openPage方法都会打开一个新的Page,新Page会覆盖在旧Page之上;当调用closePage关闭当前Page后,之前被覆盖的旧Page会重新显示。每个Page中除了主UI文件外,还可以包含其他多个UI文件,这些UI文件共同处于同一个Page作用域内。当Page关闭时,该Page内构建的所有对象都会被释放。
3. App作用域
这是最大的作用域,只要App未退出,该作用域就一直有效。
app.js属于App作用域,因为它不属于任何特定的Page。
综上所述,App作用域包含多个Page作用域,而每个Page作用域又包含多个UI作用域。
内存共享机制
内存共享
与文件和数据库相比,内存操作的速度要快得多,因此适用于数据量较小的操作场景。其主要缺点是App关闭后数据会被释放。DeviceOne提供了以下几种方式来共享内存。
1. do_Global的memory操作(App作用域)
这是App作用域下的数据共享方式。这块内存本质上是一个键值对结构,一个key对应一个value。因此需要注意,如果对同一个key重新赋值,之前的value将被覆盖。使用方法非常简单,参考以下示例,读取和写入操作分别在不同的Page中进行。
//在index.ui.js里设置值,可以设置为任何json对象,函数对象例外。
global.setMemory("key1", 1);
global.setMemory("key2", "value1");
global.setMemory("key3", [ "a", "b", "c" ]);
global.setMemory("key4", {
"k1" : "v1",
"k2" : "v2",
"k3" : "v3",
"k4" : "v4"
});
var label = ui("do_Label_2");
// 在memory/index.ui.js里获取值,可直接返回json对象
var global = sm("do_Global");
var content = {};
content.key1 = global.getMemory("key1");
content.key2 = global.getMemory("key2");
content.key3_2 = global.getMemory("key3")[1];
content.key4_k3 = global.getMemory("key4")["k3"];
label.text = JSON.stringify(content, null, 2);// 格式化
2. JavaScript的全局变量(Page作用域)
利用JavaScript自身的特性定义全局变量,通常可以实现同一Page下不同UI文件之间的数据共享。参考以下示例,读取和写入操作分别在不同的UI文件中进行,但处于同一个Page作用域内。使用方法也非常简单,主要有两种方式:
虽然这种方式非常便捷,但并不推荐使用。因为使用过于随意,在协作开发或复杂项目中,如果遇到bug,将很难定位和调试。
// 在test1.ui.js里设置js的全局变量,二种方式。
// 1.不要加var前缀的变量定义,
key1 = "value1";
// 2. 把全局变量定义在deviceone对象上
deviceone.key2 = {
"k1" : "v1",
"k2" : "v2",
"k3" : "v3",
"k4" : "v4"
}
// 在test2.ui.js里获取test1.ui.js里定义的全局变量,二种方式。
var content = {};
content.key1 = key1;
content.key2_k3 = deviceone.key2["k3"];
3. JavaScript的变量(UI作用域)
这无需过多解释,即正常的JS变量定义,仅在当前ui.js作用域内有效。
var key1 = "value1";
4. SQLite的内存模式
SQLite通常以文件模式运行,但有一种特殊情况可以直接在内存中使用SQLite。这种方式适用于数据结构较为复杂、文本操作繁琐的场景,利用SQL语句进行操作会更加灵活。
内存模式只能有一个,且名称固定为:memory:。
关于SQLite数据库的详细介绍将在后续章节展开。
文件共享机制
文件共享
这一点大家很容易理解。文件共享属于App作用域,且App重启后仍可访问。可以通过do_Storage组件在App的任何位置将内容写入文件,然后在另一个位置读取该文件的内容。参考以下示例,读取和写入操作分别在不同的Page中进行。需要注意的是,文件读写通常是异步的,必须确保内容已完全写入后,才能进行读取操作。
// 在index.ui.js里写文件file1和file2,可以直接写json对象
var key1 = "value1";
storage.writeFile("data://file1", key1, function(data, e) {
// 回调到这里才真正把内容写完,如果在执行到这里之前去读文件有可能读不到数据
})
var key2 = {
"k1" : "v1",
"k2" : "v2",
"k3" : "v3",
"k4" : "v4"
};
storage.writeFile("data://file2", key2, function(data, e) {
// 回调到这里才真正把内容写完,如果在执行到这里之前去读文件有可能读不到数据
})
// 在datacache/index.ui.js里获取值,可直接返回json对象
var datacache = sm("do_DataCache");
var content = {};
content.key1 = datacache.loadData("key1");
content.key2_3 = datacache.loadData("key2")["k3"];
label.text = "datacache/index.ui.js里获取值,可直接返回json对象 \n"
+ JSON.stringify(content, null, 2);// 格式化
SQLite数据库访问
do_SQLite组件访问数据库数据
该组件是一个MM组件,意味着可以创建多个实例。所有MM组件默认属于Page作用域,也可以设置为App作用域。创建MM组件时的第三个参数用于指定作用域。
需要注意的是,SQLite的读写通常是异步的,必须确保内容已完全写入后,才能进行读取操作。
1. App作用域:
// 创建一个app作用域的sqlite对象,第二个参数是这个对象的标示,第三个参数标示作用域是app
var sqlite_app = mm("do_SQLite", "sqlite_app_id1", "app")
function test_sqlite() {
// 在index.ui.js里利用这个对象创建一个数据库test.db
sqlite_app.open("data://test.db");
var stu_table = "drop table if exists stu_table"
// 同步执行一个SQL语句
sqlite_app.executeSync(stu_table);
// 创建表SQL语句
stu_table = "create table stu_table(_id integer primary key autoincrement,sname text,snumber text)";
// 同步执行一个SQL语句
sqlite_app.executeSync(stu_table);
var stu_sql = "insert into stu_table(sname,snumber) values('xiaoming','01005');"
+ "insert into stu_table(sname,snumber) values('xiaohong','01006');"
+ "insert into stu_table(sname,snumber) values('xiaoliu','01007')";
// 异步执行一个SQL语句
sqlite_app.execute(stu_sql, function(data, e) {
// 回调到这里才真正把数据插入完,如果在执行到这里之前去查询数据有可能读不到数据
deviceone.print("insert finished!")
})
// 根据"sqlite_app_id1"这个id获取一个app作用域的sqlite对象,第二个参数是这个对象的标示,第三个参数标示作用域是app
var sqlite_app = mm("do_SQLite", "sqlite_app_id1", "app")
// 在sqlite/index.ui.js里利用这个对象查询test.db,因为这个对象已经打开了数据库,所以不需要再open了
// 创建查询SQL语句
var stu_query = "select * from stu_table";
// 同步执行一个查询语句
var result = sqlite_app.querySync(stu_query);
label.text = "在sqlite/index.ui.js里利用这个对象查询test.db里的stu_table表的第二条数据\n"
+ JSON.stringify(result[1], null, 2);
2. Page作用域:
// 创建一个page作用域的sqlite对象,唯一的id标示是memory_db_id1
var sqlite_app = mm("do_SQLite", "memory_db_id1", "page");
// 在test1.ui.js里利用这个对象创建一个内存数据库,这个名字必须写死是:memory:
sqlite_app.open(":memory:");
// 创建表SQL语句
var stu_table = "drop table if exists stu_table;"
// 内存数据库执行速度快,可以尝试都用同步
// 同步执行一个SQL语句
sqlite_app.executeSync(stu_table);
stu_table = "create table stu_table(_id integer primary key autoincrement,sname text,snumber text)";
// 同步执行一个SQL语句
sqlite_app.executeSync(stu_table);
var stu_sql = "insert into stu_table(sname,snumber) values('laoming','1');"
+ "insert into stu_table(sname,snumber) values('laohong','2');"
+ "insert into stu_table(sname,snumber) values('laoliu','3')";
// 同步执行一个SQL语句
sqlite_app.executeSync(stu_sql);
// 在test2.ui.js里查询在test1.ui.js里创建的数据库表
// 根据memory_db_id1这个标示来获取已经创建好的sqlite对象
var sqlite_app = mm("do_SQLite", "memory_db_id1", "page");
// 创建查询SQL语句
var stu_query = "select * from stu_table";
// 同步执行一个查询语句
var result = sqlite_app.querySync(stu_query);
label.text = "在test2.ui.js里查询在test1.ui.js里创建的内存数据库表的第三条记录\n"
+ JSON.stringify(result[2], null, 2)
数据传递方式
数据传递
数据传递涉及跨作用域的场景,例如不同UI文件之间的数据传递,或不同Page之间的数据传递。
其中最重要且最常用的方式是消息机制。
1. 消息机制
这一环节我们将在文档中详细介绍。
总之,消息机制可以实现跨UI作用域的数据传递,也可以实现跨Page作用域的数据传递。
2. 通过openPage和closePage传递数据。
这种数据传递方式适用于跨Page作用域,但仅限于相隔两层的Page之间。例如,在Page1的基础上打开Page2,Page1可以将一些数据传递给Page2;当Page2关闭自身并露出Page1时,又可以将数据传递回Page1。数据传递可以是任何JSON对象。这是一种常规且良好的方式,建议采用此方法使用。
// 在index.ui.js里openPage页面open_close_page/index.ui,传递数据
var d = {
"k1" : "v1",
"k2" : "v2",
"k3" : "v3",
"k4" : "v4"
};
app.openPage({
source : "source://view/open_close_page/index.ui",
data : d,
statusBarState : "transparent"
});
}
// 接受页面open_close_page/index.ui 关闭的时候传递回来的数据
page.on("result", function(data) {
if (data)
nf.alert(JSON.stringify(data, null, 2));
})
// 从index.ui.js传递过来的数据通过getData获取值,可直接返回json对象
var data = page.getData();
label.text = "从index.ui.js传递过来的数据通过getData获取值,可直接返回json对象 \n"
+ JSON.stringify(data, null, 2);// 格式化
function close_me() {
// 关闭自身,把数据传递回下一层page
app.closePage("我是从open_close_page/index.ui关闭的时候传递过来的数据");
}
关于本文介绍的JavaScript数据共享和数据传递的相关知识就介绍到这里,希望对大家有所帮助!