基于JavaUI框架
事件式编程范式
类似安卓应用开发
/
鸿蒙应用开发
\
基于JSUI框架
声明式编程范式
类似Web前端开发
创建工程时选择“Empty Feature Ability(JS)”模板。
例程:JSHello
...\JSHello\entry\src\main\js\default\i18n\zh-CN.json
{ "strings": { "hello": "您好", "world": "鸿蒙" } }
...\JSHello\entry\src\main\js\default\i18n\en-US.json
{ "strings": { "hello": "Hello", "world": "HarmonyOS" } }
运行效果如下图所示:
JSHello
|_entry \
|_src | 工程源码目录
|_main /
|_config.json - 工程配置文件
|
|_java - Java目录
| |_com \
| |_minwei | 应用包目录
| |_jshello /
| |_MainAbility.java - Ability类
| |_MyApplication.java - 应用类
|
|_js - JavaScript目录
| |_default - JavaScript实例目录
| |_app.js - JavaScript实例入口
| |
| |_common - 实例公共目录
| | |_images - 实例图像目录
| | |_bg-tv.jpg - 图像
| | |_Wallpaper.png - 图像
| |
| |_i18n - 国际化目录
| | |_en-US.json - 英文字符串
| | |_zh-CN.json - 中文字符串
| |
| |_pages - 实例页面目录
| | |_index - 页面目录
| | |_index.hml - 页面结构
| | |_index.css - 页面外观
| | |_index.js - 页面行为
| |
| |_resources - 实例资源目录
|
|_resources - 应用资源目录
|_base - 标准资源目录
| |_element - 文本资源目录
| | |_string.json - 应用字符串
| |
| |_media - 媒体资源目录
| |_icon.png - 应用图标
|
|_rawfile - 原始资源目录
Java版:
public class MainAbility extends Ability { ... }
JS版:
public class MainAbility extends AceAbility { ... }
config.json:
除了默认的default实例以外,还可以添加新的JavaScript实例,方法有二:
包名右键
New
Ability
Empty Page Ability(JS)
Page Name: SecondaryAbility
Launcher Ability: On
JS Component Name: secondary
js右键
New
JS Component
JS Component Name: tertius
在需要加载tertius实例的Ability类的onStart()方法中调用:
super.setInstanceName("tertius");
例程:Instance
...\Instance\entry\src\main\java\com\minwei\instance\SecondaryAbility.java
public class SecondaryAbility extends AceAbility { @Override public void onStart(Intent intent) { //setInstanceName("secondary"); setInstanceName("tertius"); ... } ... }
...\Instance\entry\src\main\js\default\i18n\zh-CN.json
{ "strings": { "hello": "实例:", "world": "default" } }
...\Instance\entry\src\main\js\default\i18n\en-US.json
{ "strings": { "hello": "Instance:", "world": "default" } }
...\Instance\entry\src\main\js\secondary\i18n\zh-CN.json
{ "strings": { "hello": "实例:", "world": "secondary" } }
...\Instance\entry\src\main\js\secondary\i18n\en-US.json
{ "strings": { "hello": "Instance:", "world": "secondary" } }
...\Instance\entry\src\main\js\tertius\i18n\zh-CN.json
{ "strings": { "hello": "实例:", "world": "tertius" } }
...\Instance\entry\src\main\js\tertius\i18n\en-US.json
{ "strings": { "hello": "Instance:", "world": "tertius" } }
运行效果如下图所示:
<div class="container"> <text class="title"> {{ $t('strings.hello') }} {{ title }} </text> </div>
.container { flex-direction: column; justify-content: center; align-items: center } .title { font-size: 40px; }
注意,在config.json文件有关JavaScript实例的描述中:
"js": [ { "pages": [ "pages/index/index" ], "name": "default", "window": { "designWidth": 720, - 屏幕逻辑宽度 "autoDesignWidth": true - 屏幕逻辑宽度是否有效 } } ]
若autoDesignWidth为true,即屏幕逻辑宽度有效,则页面外观描述文件(.css)和页面行为描述文件(.js)中所有关于像素(px)的数值,都指的是逻辑像素数:
设备像素数/逻辑像素数 = 屏幕设备宽度/屏幕逻辑宽度
如华为P40手机的屏幕宽度为1080像素,按照如上配置,font-size为40px的文本实际高度为40x1080/720=60像素,而在屏幕宽度为466像素的智能手表上,其实际高度则只有40x466/720=25像素。
export default { data: { title: "" }, onInit() { this.title = this.$t('strings.world'); } }
在一个JavaScript实例内添加页面:
pages右键
New
JS Page
JS Page Name: secondary
config.json:
"js": [ { "pages": [ "pages/index/index", "pages/secondary/secondary" ], "name": "default", ... } ]
import router from '@system.router';
| |
| |
| |
| |
|---------|
| index | <- 显示
|_________|
|
| router.push({uri: "pages/secondary/secondary"}); // 入栈
| router.push({uri: "pages/secondary/tertius"}); // 入栈
v
|---------|
| tertius | <- 显示
|---------|
|secondary|
|---------|
| index |
|_________|
|
| router.back(); // 出栈
v
| |
| |
|---------|
|secondary| <- 显示
|---------|
| index |
|_________|
|
| router.replace({uri: "pages/secondary/tertius"}); // 先出栈再入栈
v
| |
| |
|---------|
| tertius | <- 显示
|---------|
| index |
|_________|
|
| router.clear(); // 清除栈顶以下
v
| |
| |
| |
| |
|---------|
| tertius | <- 显示
|_________|
用户看见的永远都是栈顶页面,即当前页面。
跳转的同时还可传递参数:
route.push \
> ({uri: "pages/secondary/secondary",
route.replace / params: {param: this.string}});
| |
参数名 参数值
目标页面直接从this中获取参数:
this.string = this.param;
例程:Jump
...\Jump\entry\src\main\js\default\pages\index\index.hml
<div class="div"> <text class="txt">{{string}}</text> <button class="btn" @click="onClick">跳转</button> </div>
...\Jump\entry\src\main\js\default\pages\index\index.css
.div { flex-direction: column; justify-content: center; align-items: center } .txt { height: 66px; font-size: 22px; color: #00a2e8; } .btn { width: 120px; height: 40px; font-size: 24px; background-color: #00a2e8; color: #ffffff }
...\Jump\entry\src\main\js\default\pages\index\index.js
import router from '@system.router'; export default { data: { string: "鸿蒙初辟本无性,打破顽冥须悟空" }, onClick() { router.push({uri: "pages/secondary/secondary", params: {param: this.string}}); } }
...\Jump\entry\src\main\js\default\pages\secondary\secondary.hml
<div class="div"> <text class="txt">{{string}}</text> <button class="btn" @click="onClick">返回</button> </div>
...\Jump\entry\src\main\js\default\pages\secondary\secondary.css
.div { flex-direction: column; justify-content: center; align-items: center; background-color: #00a2e8; } .txt { height: 66px; font-size: 22px; color: #ffffff; } .btn { width: 120px; height: 40px; font-size: 24px; background-color: #ffffff; color: #00a2e8; }
...\Jump\entry\src\main\js\default\pages\secondary\secondary.js
import router from '@system.router'; export default { data: { string: "" }, onInit() { this.string = this.param; }, onClick() { router.back(); } }
运行效果如下图所示:
启动应用:
进入后台:
返回前台:
退出应用:
新页入栈:
新页出栈:
另外,还有一个onBackPress()方法,会在通过手势或点击屏底按钮返回时被调用。
例程:Life
...\Life\entry\src\main\js\default\pages\index\index.hml
<div class="div"> <text class="txt">{{string}}</text> <button class="btn" @click="onClick">跳转</button> </div>
...\Life\entry\src\main\js\default\pages\index\index.css
.div { flex-direction: column; justify-content: center; align-items: center } .txt { height: 66px; font-size: 22px; color: #22b14c; } .btn { width: 120px; height: 40px; font-size: 24px; background-color: #22b14c; color: #ffffff }
...\Life\entry\src\main\js\default\pages\index\index.js
import router from '@system.router'; export default { data: { string: "我命在我,不属天地" }, onInit() { console.log("index.onInit()"); }, onReady() { console.log("index.onReady()"); }, onShow() { console.log("index.onShow()"); }, onHide() { console.log("index.onHide()"); }, onDestroy() { console.log("index.onDestroy()"); }, onBackPress() { console.log("index.onBackPress()"); }, onClick() { router.push({uri: "pages/secondary/secondary", params: {param: this.string}}); } }
...\Life\entry\src\main\js\default\pages\secondary\secondary.hml
<div class="div"> <text class="txt">{{string}}</text> <button class="btn" @click="onClick">返回</button> </div>
.div { flex-direction: column; justify-content: center; align-items: center; background-color: #22b14c; } .txt { height: 66px; font-size: 22px; color: #ffffff; } .btn { width: 120px; height: 40px; font-size: 24px; background-color: #ffffff; color: #22b14c; }
...\Life\entry\src\main\js\default\pages\secondary\secondary.js
import router from '@system.router'; export default { data: { string: "" }, onInit() { console.log("secondary.onInit()"); this.string = this.param; }, onReady() { console.log("secondary.onReady()"); }, onShow() { console.log("secondary.onShow()"); }, onHide() { console.log("secondary.onHide()"); }, onDestroy() { console.log("secondary.onDestroy()"); }, onBackPress() { console.log("secondary.onBackPress()"); }, onClick() { router.back(); } }
运行效果如下图所示:
每个JavaScript实例都有一个app.js文件,该文件包含了JavaScript实例的生命周期方法:
在app.js中还可以定义一些为该实例所有页面共享的全局性属性和方法。在从跳转的目标页面返回时,可以借助应用对象携带必要的返回信息。
页面js通过this.$app访问这些标识符。
例程:App
...\App\entry\src\main\js\default\app.js
export default { data: { count: null }, onCreate() { console.info('AceApplication onCreate'); this.count = 0; }, onDestroy() { console.info('AceApplication onDestroy'); }, getCount() { return this.count; }, incCount() { ++this.count; } };
...\App\entry\src\main\js\default\pages\index\index.hml
<div class="div"> <button class="btn" @click="onClick">{{count}}</button> </div>
...\App\entry\src\main\js\default\pages\index\index.css
.div { flex-direction: column; justify-content: center; align-items: center } .btn { width: 150px; height: 50px; font-size: 30px; background-color: #ff7f27; color: #ffffff }
...\App\entry\src\main\js\default\pages\index\index.js
import router from '@system.router'; export default { data: { count: null }, onShow() { this.count = this.$app.getCount(); }, onClick() { router.push({uri: "pages/secondary/secondary"}); this.$app.incCount(); }, }
...\App\entry\src\main\js\default\pages\secondary\secondary.hml
<div class="div"> <button class="btn" @click="onClick">{{count}}</button> </div>
...\App\entry\src\main\js\default\pages\secondary\secondary.css
.div { flex-direction: column; justify-content: center; align-items: center; background-color: #ff7f27; } .btn { width: 150px; height: 50px; font-size: 30px; background-color: #ffffff; color: #ff7f27; }
...\App\entry\src\main\js\default\pages\secondary\secondary.js
import router from '@system.router'; export default { data: { count: null }, onInit() { this.count = this.$app.getCount(); }, onBackPress() { this.$app.incCount(); }, onClick() { router.back(); this.$app.incCount(); } }
运行效果如下图所示: