QuickJS 开发指南¶
1. 简介¶
QuickJS 是一款轻量级可嵌入的 JavaScript 引擎,支持 ES2020 规范(包括模块、异步生成器等),并扩展了大整数、大浮点数等数学功能。
Sifli 基于官方版本适配了 RT-Thread 和 LVGL,支持通过 JavaScript 开发表盘、应用及 AOD(息屏显示),沿用 C 应用框架的调度逻辑。
2. 核心框架说明¶
2.1 应用框架支持¶
Sifli 具备明确的应用框架,提供应用 / 表盘 / AOD 的注册接口。系统启动时自动扫描 qjs 目录,按类型识别子目录:
JA_xxx: JS应用目录,主程序是目录中
JA_xxx_main.js, 需定义与目录名一致的类并注册到全局变量JW_xxx: JS 表盘目录,主程序为
JW_xxx_main.js,需定义与目录名一致的类并注册到全局变量AOD_xxx: JS 息屏应用目录,主程序为
AOD_xxx_main.js,需定义与目录名一致的类并注册到全局变量
所有应用按类型注册到对应 C 框架,由 C 框架统一调度执行。
2.2 LVGL的支持¶
LVGL 支持通过三种形式提供给 JS 调用:
obj class 封装
lv_obj_xxx函数,输出lvobj类,每个方法对应相应的C函数obj extension 封装
lv_class_xxx函数,与生成的class.js配合输出具体控件类(如label.js对应`label类),使用时通过 import label from “/support_script/qjs/label.js” 导入functions 封装LVGL中不属于上述两类的函数,归属于
lv模块,调用方式如 lv.gui_app_run(app) 注意入参和返回值类型非
int/bool/color16_t/string/object的函数无法自动生成lv_obj_add_event_cb 因涉及函数指针,通过
lvobj模块的 set_event_cb 方法实现事件传递
3.快速上手¶
quickjs支持板级/模拟器运行,步骤如下:
打开HCPU工程/SIMU工程quickjs依赖宏

勾选预置qjs脚本和应用

勾选编译选项JS应用,开始编译

demo源码位于\solution\examples_dynamic_app\qjs目录,各应用功能如下:
应用 |
说明 |
|---|---|
JA_app1 |
条形码,二维码,文件IO操作,task使用,多页面功能 |
JA_app2 |
按键,旋钮功能 |
JA_app3 |
数据存储和读取功能 |
JA_app4 |
图表功能,可以修改chart_type显示不同风格 |
JA_app5 |
多实例动画 |
JW_wf1 |
模拟表盘功能 |
JW_wf2 |
序列帧功能 |
JW_wf4 |
GIF功能 |
JW_wf5 |
ezipa功能 (需硬件支持,不支持模拟器) |
JW_wf6 |
数据订阅功能(模拟器无数据) |
AOD_wf1 |
熄屏显示功能 |
提示
仅修改JS应用代码时,单独编译烧录JS应用即可
4. 目录结构¶
4.1 框架代码¶
QJS 框架代码位于qjs_framework目录,包含应用框架、页面调度、LVGL 模块等

4.1.1 生成代码¶
QJS c映射代码位于qjs_generated目录:
lv_qjs_ext_obj.cobj extension封装集合lv_qjs_function.cfunctions封装集合lv_qjs_obj.cobj class封装集合lv_qjs_generated.c文件包含和一些编译打桩函数

4.1.2 类代码¶
js 类文件是obj externsion的封装,代码位于如下路径,需通过butterfli预置到文件系统使用。

4.1.3 应用代码¶
应用代码目录结构如图

5. 接口生成¶
QJS 接口生成支持自动生成和手动添加两种方式。建议优先使用自动生成,减少内存泄露风险。新增接口建议统一放在lv_qjs_generated.c/h 中。
5.1 自动生成¶
适用于简单接口,需满足:
参数和返回值类型仅限
int,bool,lv_color_t,string,lv_obj_t*接口名以
lv_开头入参个数最大支持8
避免编译非LVGL相关文件
5.1.1 特殊处理¶
继承规则: 若
obj_extension接口父类非lv_obj,需在inherit_list.py中指定父类。字符串参数: C 接口参数类型为 void* 但实际为字符串时,在 string_list.py 中声明
5.1.2 相关脚本¶
脚本 |
目录 |
说明 |
|---|---|---|
sol_gen.sh |
sdk\external\micropython\lib\lv_bindings |
linux系统使用,生成json中间件 |
qjs_gen_blacklist.bat |
solution\components\quickjs\script |
windows系统使用,生成black_list.py |
qjs_gen_js_class.bat |
solution\components\quickjs\script |
windows系统使用,生成ext obj对应的.js |
qjs_gen_lv_ext_obj.bat |
solution\components\quickjs\script |
windows系统使用,生成对ext obj的C支持 |
qjs_gen_lv_functions.bat |
solution\components\quickjs\script |
windows系统使用,生成对function的C支持 |
qjs_gen_lv_obj.bat |
solution\components\quickjs\script |
windows系统使用,生成对lv obj的C支持 |
inherit_list.py |
solution\components\quickjs\script |
指明生成JS class继承的模块 |
string_list.py |
solution\components\quickjs\script |
指定接口参数为字符串 |
5.1.3 执行步骤¶
将新增接口实现放入
lv_qjs_generated.c,声明放入lv_qjs_generated.h(ext obj 类型直接在头文件中 include)Linux系统:
安装 Python 2.7(建议 Ubuntu 18.04.6 LTS)
进入
/sdk/external/micropython/lib/lv_bindings目录执行带参脚本,如
./sol_gen.sh nand 16 qjs生成中间件
Windows系统:
进入
solution/components/quickjs/script目录执行
qjs_gen_blacklist.bat生成blacklist.py(黑名单中的函数不生成)根据接口类型执行相应脚本更新代码:
lv obj类型:
qjs_gen_lv_obj.bat(更新lv_qjs_obj.c)function 类型:
qjs_gen_lv_functions.bat(更新lv_qjs_functions.c)obj extension 类型
qjs_gen_lv_ext_obj.bat(更新lv_qjs_ext_obj.c)+qjs_gen_js_class.bat(更新 JS 类文件) 注意
脚本执行报错可能因文件格式(非 Unix 格式)或编码问题导致
黑名单中的函数不会生成
不支持的接口会在生成的 .c 文件中提示,可搜索查看原因
JS类文件位于
solution/components/support_script/qjs目录
5.2 手动添加¶
适用于对 QuickJS 有一定了解的开发者,可直接修改对应 C 文件添加接口。
5.2.1 类型对应表¶
类型 |
文件 |
枚举定义表 |
函数格式表 |
函数列表 |
回调接口 |
|---|---|---|---|---|---|
lvobj |
lv_qjs_obj.c |
JS_lv_obj_methods_enum |
lv_obj_protos |
js_lv_obj_methods |
lv_obj_call_method |
ext obj |
lv_qjs_ext_obj.c |
JS_lv_ext_funcs_enum |
lv_ext_funcs_proto |
js_lv_ext_funcs |
lv_ext_call_func |
functions |
lv_qjs_functions.c |
JS_lv_funcs_enum |
lv_funcs_proto |
js_lv_funcs |
lv_obj_call_method |
5.2.2 实现步骤¶
定义枚举值:
functions 和 obj extension 类型:
LVFUNC+ 去掉lv_前缀的函数名(如lv_version_major->LVFUNC_version_major)lvobj类型:
LVOBJ+ 去掉lv_obj_前缀的函数名(如lv_obj_clean->LVOBJ_clean)
添加数据格式:
在函数格式表中按**枚举顺序**添加,包含 name(函数名)、param_type(参数类型数组,根据函数如参顺序依次填入类型)、return_type(返回值类型)添加函数列表:
按**枚举顺序**添加 JS_CFUNC_MAGIC_DEF 定义,参数需与格式表匹配(param1 函数名, param2 函数参数个数,和步骤2中param_type的个数匹配,param3 函数回调接口, param4 是步骤1中的枚举值)实现回调函数:
入参通过
param[0]、param[1]等获取(lvobj 类型第一个参数为s->lv_obj)返回值处理:
int/lv_obj_t*:JS_NewInt32bool:JS_NewBool字符串:
JS_NewStringlv_color_t: 先lv_color_to32转换,再JS_NewInt32
5.2.3 类型定义¶
enum {
LVTYPE_none=0, // 无类型
LVTYPE_int, // 整数
LVTYPE_bool, // 布尔值
LVTYPE_func, // 函数指针
LVTYPE_object, // 对象
LVTYPE_color, // 颜色
LVTYPE_string, // 字符串
};
5.2.4 示例代码¶
//枚举定义
typedef enum
{
...,
LVFUNC_version_info,
LVFUNC_version_major,
LVFUNC_version_minor,
LVFUNC_version_patch,
}JS_lv_funcs_enum;
//函数格式表
const JS_lv_protos lv_funcs_proto[]=
{
....,
//顺序要和枚举中的顺序保持对应
{
.name = "version_info",
.return_type = LVTYPE_string
},
{
.name = "version_major",
.return_type = LVTYPE_int
},
{
.name = "version_minor",
.return_type = LVTYPE_int
},
{
.name = "version_patch",
.return_type = LVTYPE_int
},
};
//函数列表
const JSCFunctionListEntry js_lv_funcs[] =
{
...,
//顺序要和枚举中的顺序保持对应
JS_CFUNC_MAGIC_DEF("version_info", 0, js_lv_func, LVFUNC_version_info),
JS_CFUNC_MAGIC_DEF("version_major", 0, js_lv_func, LVFUNC_version_major),
JS_CFUNC_MAGIC_DEF("version_minor", 0, js_lv_func, LVFUNC_version_minor),
JS_CFUNC_MAGIC_DEF("version_patch", 0, js_lv_func, LVFUNC_version_patch),
};
//回调实现
static JSValue lv_call_func(JSContext *ctx, int magic, JSValueConst param[]) =
{
JSValue r = JS_UNDEFINED;
switch(magic)
{
...,
case LVFUNC_version_info:
{
char *r_in = (char *)lv_version_info();
r = JS_NewString(ctx, r_in);
break;
}
case LVFUNC_version_major:
{
int r_in = lv_version_major();
r = JS_NewInt32(ctx, r_in);
break;
}
case LVFUNC_version_minor:
{
int r_in = lv_version_minor();
r = JS_NewInt32(ctx, r_in);
break;
}
case LVFUNC_version_patch:
{
int r_in = lv_version_patch();
r = JS_NewInt32(ctx, r_in);
break;
}
}
return r;
}
lv obj类型和ext obj类型添加方式类似。
5.2.5 JS文件添加(obj extension类型)¶
在 support_script/qjs/ 目录添加对应 JS 类文件,示例(lvsfbarcode.js)
import * as lv from "lv"; //lv模块
import * as lvext from "lvext"; //lvext模块
import {img} from "/support_script/qjs/img.js"; //img模块
export class lvsfbarcode extends img { //继承自img,需要和C代码控件class变量中的base_class保持一致
constructor(parent,parentobj=undefined) {
var nativeobj=parentobj;
if(nativeobj==undefined) {
nativeobj=lvext.lvsfbarcode_create(parent);
}
super(parent,nativeobj);
this.nativeobj=nativeobj;
this.set_obj(this.nativeobj);
}
set_text(text){
return lvext.lvsfbarcode_set_text(this.nativeobj, text);
}
set_line_color(index){
return lvext.lvsfbarcode_set_line_color(this.nativeobj, index);
}
set_parse(parse){
return lvext.lvsfbarcode_set_parse(this.nativeobj, parse);
}
set_dir(dir){
return lvext.lvsfbarcode_set_dir(this.nativeobj, dir);
}
//其他方法...
}
注意
建议通过统一接口封装同类功能(如通过枚举值实现通用 get/set 方法),减少生成依赖和 ROM 占用。
6. 功能支持¶
6.1 数据订阅¶
JS 控件可通过 lvobj 模块的 bind 方法订阅数据,数据更新时由 C 端通知:
label = new label(this.root);
// 回调函数:id(字符串)、type(整数)、val(可选数据)
function callback(id, type, val){
//do something
}
//id 字符串类型,id为NULL时,type必须为唯一值
//type 整形
//回调函数
label.bind(id, type, callback);
建议
每个控件建议只订阅一种类型数据,简化回调处理
可封装 get 接口在回调中直接获取数据,无需关心 val 类型
控件取消订阅由框架自动管理,无需手动处理
示例参考JA_app1
6.2 编码器(旋钮)¶
lvapp 模块的 wheel() 方法用于注册 / 反注册旋钮回调,通常在 resume() 中注册,pause() 中反注册:
wheel_handler(key) {
// key:17(上),18(下),见lv_enums.js
}
resume() {
this.wheel( //传入参数时表示注册
function (key) {
this.wheel_handler(key);
}
);
}
pause(){
this.wheel(); //没有参数表示反注册
}
示例参考JA_app2
6.3 按键¶
lvapp 模块的 keypad() 方法用于注册 / 反注册按键回调:
keypad_handler(key, state) {
//key 按键,state:1(按下),0(松手)
if(key == lv_enums.KEY_HOME && state == 1){
return 1; //返回1不执行按键默认功能
}
return 0; //返回0执行按键默认功能
}
resume() {
this.keypad( //传入参数时表示注册
function (key, state) {
return this.keypad_handler(key, state);
}
);
}
pause(){
this.keypad(); //没有参数表示反注册
}
注意
按键回调需返回值,框架根据返回值决定是否执行默认功能
示例参考JA_app2
6.4 数据存储¶
nvm 模块通过文件系统实现数据存储(序列化 / 反序列化为 JSON):
import * as nvm from "nvm" //头文件引入
//示例数据
var user = {
id:1,
name:"Bob",
scores:[90,85]
};
//存储
var str_data = JSON.stringify(user)
nvm.write('user.json', str_data);
// 读取
var read_string = nvm.read('user.json');
var conv_obj = JSON.parse(read_string);
注意: 需处理异常场景(文件不存在、格式错误等)
使用示例参考JA_app3
6.5 多语言¶
通过 Excel 表转换生成的 JS 文件实现多语言支持:
导入接口:
import {app_get_str} from "./JA_xxx_language.js", 如import {app_get_str} from "./JA_app1_language.js"获取字符串: app_get_str(“key”,“default_string”); 注意 应用标题需要显示调用以避免被工具移除
globalThis.JA_app1 = JA_app1;
app_get_str("key_qjs_name","key_test"); // 保留应用名多语言条目
6.6 文件操作¶
os 模块提供文件操作接口:
/*Open a file. Return a handle or < 0 if error.
Supported flags:
O_RDONLY
O_WRONLY
O_RDWR
O_APPEND
O_CREAT
O_EXCL
O_TRUNC
*/
open(filename, flags, mode = 0o666)
//Seek in the file. Use std.SEEK_* for whence. offset is either a number or a BigInt.
//If offset is a BigInt, a BigInt is returned too
seek(fd, offset, whence)
//Read length bytes from the file handle fd to the ArrayBuffer buffer at byte position offset.
//Return the number of read bytes or < 0 if error
read(fd, buffer, offset, length)
//Write length bytes to the file handle fd from the ArrayBuffer buffer at byte position offset.
//Return the number of written bytes or < 0 if error.
write(fd, buffer, offset, length)
//Return [str, err] where str is the current working directory and err the error code.
getcwd()
//Change the current directory. Return 0 if OK or -errno.
chdir(path)
//Create a directory at path. Return 0 if OK or -errno.
mkdir(path, mode = 0o777)
//Return [array, err] where array is an array of strings containing the filenames of the directory path.
//err is the error code. array contains at least "." and ".." if successful.
readdir(path)
//Close the file handle fd
close(fd)
注意
使用示例参考JA_app1
6.7 动画¶
anim 模块支持多实例动画,支持接口参考solution\components\quickjs\qjs_framework\lvgl_anim_qjs.c 示例:
import * as lv from "lv"
import { app } from "lvapp"
import { anim } from "anim" //anim 模块
class ja_app extends app {
constructor() {
super();
this.anim = undefined;
}
start() {
print("start");
this.anim = new anim();
this.anim.set_values(0, 200); // 动画范围
this.anim.set_path(this.anim.PATH_LINEAR) // 动画曲线
this.anim.set_time(1000); // 动画时长(ms)
this.anim.set_delay(2000); // 动画延时(ms)
this.anim.set_start_cb(function(anim){ // 开始回调
print("anim start");
});
this.anim.set_ready_cb(function(anim){ //结束回调
print("anim ready");
});
this.anim.set_exec_cb(function(val){ // 执行回调
print(val);
});
this.anim.start();
}
resume() {
print("resume");
}
pause(){
print("pause");
}
stop(){
print("stop");
this.anim.del(); // 销毁动画,避免循环引用
}
}
globalThis.JA_app5 = {
root:ja_app
};
app_get_str("key_qjs_name","ja_app5");
注意 动画实例数量会影响页面帧率,退出时需销毁避免内存泄露
anim使用demo参考JA_app5
6.8 SENSOR¶
全局 sensor 模块提供传感器数据获取(仅支持 getter),支持接口参考solution\components\quickjs\qjs_framework\lvgl_sensor_qjs.c:
var level = sensor.BatLevel; // 获取电池电量
7. 应用开发¶
7.1 基础规范¶
需创建继承自 lvapp 的类,并实现核心方法使应用可被框架调度。
7.1.1 父类方法¶
父类 class app 提供了以下可使用的方法,子类可根据需求进行实现或调用:
方法名 |
功能描述 |
|---|---|
|
应用初始化(必实现),创建页面、初始化数据 |
|
应用恢复(必实现),一般用以开启任务 |
|
应用暂停(必实现),一般用以暂停任务 |
|
应用销毁(必实现),一般用以释放自定义控件数据 |
|
获取父控件,新控件需基于此创建 |
|
获取应用路径,用于拼接资源路径 |
|
注册 / 反注册按键回调 |
|
注册 / 反注册编码器回调 |
|
创建 / 销毁任务(一般在 resume/pause 中调用) |
7.1.2 任务(Task)示例¶
pause(){
this.task(); // 销毁
}
resume(){
this.task(){
function(){
//do something; //处理
},
1000 //刷新间隔
};
}
注意
禁止空方法(无逻辑时需添加占位代码如 print)。
禁止使用 LVGL 对象的 user_data(框架占用)
任务避免频繁刷新和复杂计算,建议将处理逻辑交给 C 层
7.2 注册接口¶
应用需通过全局唯一对象注册接口:
主页面(如JA_app1_main.js):
// 注册主页面,变量名需与目录名一致
globalThis.JA_app1 = {
root : app_root,
};
子页面(如JA_app1_page1.js)
class page1 extends app { ... }
// 追加子页面,属性名需与文件名后半部一致
globalThis.JA_app1.page1 = app_page1;
8. 开发示例¶
8.1 应用(APP)示例¶
主页面
xxx_main.js(如JA_app1_main.js):
import * as lv from "lv" //lv obj module
import * as os from "os" //os模块
import * as std from "std" //std模块
import {app} from "lvapp" //app模块
import * as lv_enums from "/support_script/qjs/lv_enums.js" //枚举模块
import {qrcode} from "/support_script/qjs/qrcode.js" //qrcode控件
import {lvsfbarcode} from "/support_script/qjs/lvsfbarcode.js" //barcode 控件
import {app_get_str} from "./JA_app1_language.js" //引入多语言接口
//arraybuffer转字符串
function arrayBufferToString(buffer){
return String.fromCharCode.apply(null, new Uint16Array(buffer));
}
//字符串转arraybuffer
function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length * 2);
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
var string = "0705632441974";
var txt = "0123456-ABC-abcd";
class JA_app1 extends app{ //继承父类app, class 名需要和目录名相同
constructor() {
super(); //构造函数中调用父类app的构造函数
this.count = 0; //初始化变量
}
refresh() {
this.count++;
print("count ", this.count);
}
start() {
// Demo for QRcode
this.qrcode = new qrcode(this.root()); //this.root() 获取当前parent
this.qrcode.setparam(200, lv.color_make(0xc0,0xc0,0xc0), lv.color_make(0xFF,0xFF,0xFF));
this.qrcode.set_text(txt, txt.length);
this.qrcode.align(lv_enums.ALIGN_TOP_MID, 0, 0);
this.qrcode.set_event_cb( //set_event_cb是固定控件回调处理
function(event){
if (event==lv_enums.EVENT_SHORT_CLICKED){
print("qrcode event ", event);
lv.gui_app_self_exit(); //退出应用
}
}
);
// Demo for Barcode
this.barcode = new lvsfbarcode(this.root());
this.barcode.set_size(300, 100);
this.barcode.set_text(string, 66);
this.barcode.align(lv_enums.ALIGN_BOTTOM_MID, 0, 0);
this.barcode.set_event_cb(
function(event){
if(event == lv_enums.EVENT_SHORT_CLICKED){
print("barcode event ", event);
lv.qjs_app_page_create("page1"); //创建子页面page1
}
}
);
print("Started\n");
}
resume() {
// Demo for OS file access
this.f=os.open("/a.txt", os.O_RDWR | os.O_CREAT | os.O_TRUNC); //打开文件
print("f=",this.f);
if(this.f > 0){
const buffer1 = stringToArrayBuffer('Hello, QuickJS File Operations!');
os.write(this.f, buffer1, 0, buffer1.byteLength) //写入数据
print("write:", arrayBufferToString(buffer1));
os.seek(this.f, std.SEEK_SET, 0);
const buffer = new ArrayBuffer(buffer1.byteLength);
os.read(this.f,buffer,0, buffer1.byteLength); //读取数据
print("read:", arrayBufferToString(buffer));
os.close(this.f); //关闭文件
}
// Demo for OS directory
os.chdir("/support_script/qjs"); //切换目录
print(os.getcwd()); //获取当前路径
var local_files=os.readdir("/"); //读取目录
print(local_files[0].length);
for (var i=0;i<local_files[0].length;i++)
{
print(local_files[0][i]);
}
// Demo for task
this.task(
function() {
this.refresh(); //刷新实现
}
, 1000 //刷新间隔
);
}
pause(){
this.task(); //销毁task
}
stop(){
print("stop"); //stop没有实际执行内容,增加打印。
}
}
//初始化赋值
globalThis.JA_app1 = {
root : JA_app1,
};
app_get_str("key_qjs_name","key_test"); //应用标题申明
子页面
应用名_页面名.js(如JA_app1_page1.js)
import * as lv from "lv"
import * as os from "os"
import * as lv_enums from "/support_script/qjs/lv_enums.js"
import {app} from "lvapp"
import {label} from "/support_script/qjs/label.js"
class page1 extends app{
constructor() {
super();
}
start(){
this.label = new label(this.root());
this.label.set_local_font(lv_enums.FONT_SUPER, lv.color_make(0xff,0xff,0xff));
this.label.set_text("subpage 1");
this.label.align(lv_enums.ALIGN_CENTER, 0, 0);
this.label1 = new label(this.root());
this.label1.set_local_font(lv_enums.FONT_TITLE, lv.color_make(0xff,0xff,0xff));
this.label1.set_text("click to subpage 2");
this.label1.align(lv_enums.ALIGN_CENTER, 0, 60);
this.label1.add_flag(lv_enums.FLAG_CLICKABLE);
this.label1.set_event_cb(
function(event){
if(event == lv_enums.EVENT_SHORT_CLICKED)
lv.qjs_app_page_create("page2");
}
);
}
resume(){
print("subpage resume");
}
pause(){
print("subpage pause");
}
stop(){
print("subpage stop");
}
}
globalThis.JA_app1.page1 = page1;
8.2 表盘(WF)示例¶
import * as lv from "lv"
import {app} from "lvapp"
import {analogclk} from "/support_script/qjs/analogclk.js"
class JW_wf1 extends app{ //继承父类app, class 名需要和目录名相同
constructor() {
super();
}
start() {
this.anaclk=new analogclk(this.root());
this.anaclk.pos_off(10,10,105);
this.anaclk.img(this.path() + "bg.bin", this.path() + "hour.bin", this.path() +
"minute.bin", this.path() + "second.bin"); //this.path()获取当前路径
this.rate = 30;
}
pause() {
this.anaclk.refr_inteval(0);//暂停模拟表盘
}
resume() {
this.anaclk.refr_inteval(30);//刷新模拟表盘
}
}
globalThis.JW_wf1 = {
root : JW_wf1,
};
8.3 AOD示例¶
import * as lv from "lv"
import {app} from "lvapp"
import * as lv_enums from "/support_script/qjs/lv_enums.js"
import {analogclk} from "/support_script/qjs/analogclk.js"
class AOD_wf1 extends app{
constructor() {
super();
}
start() {
this.anaclk=new analogclk(this.root());
this.anaclk.pos_off(10,10,105);
this.anaclk.img(this.path() + "bg.bin", this.path() + "hour.bin", this.path() + "minute.bin", this.path() + "second.bin");
this.rate = 30;
}
pause() {
this.anaclk.refr_inteval(0);
}
resume() {
this.anaclk.refr_inteval(this.rate);
}
}
globalThis.AOD_wf1 = {
root : AOD_wf1,
};
9. 开发建议¶
枚举类型 JS 文件按类型拆分,避免过大影响解释效率
变量名精简,减少内存占用
复杂计算逻辑建议在 C 层实现,JS 仅负责调用接口