跳转至

JS 语法与生命周期

语法

HML语法参考

HML(HarmonyOS Markup Language,鸿蒙标识语言)是一套类HTML(Hypertext Markup Language,超文本标记语言)的标记语言,通过组件、事件构建出页面的内容。页面具备数据绑定、事件绑定、列表渲染、条件渲染等高级能力。

页面结构

<!-- xxx.hml -->
<div class="item-container">
  <text class="item-title">Image Show</text>
  <div class="item-content">
    <image src="/common/xxx.png" class="image"></image>
  </div>
</div>

数据绑定

<!-- xxx.hml -->
<div onclick="changeText">
  <text> {{content[1]}} </text>
</div>
// xxx.js
export default {
    data: {
        content: ['Hello World!', 'Welcome to my world!']
    },
    changeText: function() {
        this.content.splice(1, 1, this.content[0]);
    }
}

说明:

  • 针对数组内的数据修改,请使用splice方法生效数据绑定变更。
  • hml文件中的js表达式不支持ES6语法。

事件绑定

事件通过'on'或者'@'绑定在组件上,当组件触发事件时会执行JS文件中对应的事件处理函数。

事件支持的写法如下:

  • "funcName":funcName为事件回调函数名(在JS文件中定义相应的函数实现)。
  • "funcName(a,b)":函数参数例如a、b(可以为常量),或是在JS文件中的data中定义的变量(前面不用写this)。
  • 示例

     <!-- xxx.hml -->
     <div class="container">
         <text class="title">{{count}}</text>
         <div class="box">
             <input type="button" class="btn" value="increase" onclick="increase" />
             <input type="button" class="btn" value="decrease" @click="decrease" />
             <!-- 传递额外参数 -->
             <input type="button" class="btn" value="double" @click="multiply(2)" />
             <input type="button" class="btn" value="decuple" @click="multiply(10)" />
             <input type="button" class="btn" value="square" @click="multiply(count)" />
         </div>
     </div>
    /* xxx.js */
     export default {
         data: {
             count: 0
         },
         increase() {
             this.count++;
         },
         decrease() {
             this.count--;
         },
         multiply(multiplier) {
             this.count = multiplier * this.count;
         }
     };
    /* xxx.css */
     .container {
         display: flex;
         flex-direction: column;
         justify-content: center;
         align-items: center;
         left: 0px;
         top: 0px;
         width: 454px;
         height: 454px;
     }
     .title {
         font-size: 30px;
         text-align: center;
         width: 200px;
         height: 100px;
     }
     .box {
         width: 454px;
         height: 200px;
         justify-content: center;
         align-items: center;
         flex-wrap: wrap;
     }
     .btn {
         width: 200px;
         border-radius: 0;
         margin-top: 10px;
         margin-left: 10px;
     }
    

列表渲染

<!-- xxx.hml -->
<div class="array-container">
  <!-- div列表渲染 -->
  <!-- 默认$item代表数组中的元素, $idx代表数组中的元素索引 -->
  <div class="div_item1" for="{{array}}" tid="id" onclick="changeText">
    <text>{{$idx}}.{{$item.name}}</text>
  </div>
  <!-- 自定义元素变量名称 -->
  <div class="div_item2" for="{{value in array}}" tid="id" onclick="changeText">
    <text>{{$idx}}.{{value.name}}</text>
  </div>
  <!-- 自定义元素变量、索引名称 -->
  <div class="div_item3" for="{{(index, value) in array}}" tid="id" onclick="changeText">
    <text>{{index}}.{{value.name}}</text>
  </div>
</div>

// xxx.js
export default {
    data: {
        array: [
            {id: 1, name: 'jack', age: 18},
            {id: 2, name: 'tony', age: 18},
        ],
    },
    changeText: function() {
        if (this.array[1].name === "tony"){
            this.array.splice(1, 1, {id:2, name: 'Isabella', age: 18});
        } else {
            this.array.splice(2, 1, {id:3, name: 'Bary', age: 18});
        }
    },
}
/** css **/
.array-container{
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: white;
}
.div_item1{
    width: 100px;
    height: 200px;
    flex-direction: column;
    background-color: blue;
}

.div_item2{
    width: 100px;
    height: 200px;
    flex-direction: column;
    background-color: gray;
}

.div_item3{
    width: 100px;
    height: 200px;
    flex-direction: column;
    background-color: red;
}

.text_item{
    color: black;
    width: 100px;
    height: 300px;
    text-align: left;
    font-size: 30px;
}

tid属性主要用来加速for循环的重渲染,旨在列表中的数据有变更时,提高重新渲染的效率。tid属性是用来指定数组中每个元素的唯一标识,如果未指定,数组中每个元素的索引为该元素的唯一id。例如上述“tid="id"”表示数组中的每个元素的id属性为该元素的唯一标识。for循环支持的写法如下:

  • for="array":其中array为数组对象,array的元素变量默认为$item。
  • for="v in array":其中v为自定义的元素变量,元素索引默认为$idx。
  • for="(i, v) in array":其中元素索引为i,元素变量为v,遍历数组对象array。

须知:

  • 数组中的每个元素必须存在tid指定的数据属性,否则运行时可能会导致异常。
  • 数组中被tid指定的属性要保证唯一性,如果不是则会造成性能损耗。比如,示例中只有id和name可以作为tid字段,因为它们属于唯一字段。
  • tid不支持表达式。

条件渲染

条件渲染分为2种:if/elif/else和show。两种写法的区别在于:第一种写法里if为false时,组件不会在vdom中构建,也不会渲染,而第二种写法里show为false时虽然也不渲染,但会在vdom中构建;另外,当使用if/elif/else写法时,节点必须是兄弟节点,否则编译无法通过。实例如下:

<!-- xxx.hml -->
<div class="container">
  <input class="btn" type="button" value="toggleShow" onclick="toggleShow"/>
  <input class="btn" type="button" value="toggleDisplay" onclick="toggleDisplay"/>
  <text class="title" if="{{visible}}"> Hello-TV </text>
  <text class="title" elif="{{display}}"> Hello-Wearable </text>
  <text class="title" else> Hello-World </text>
</div>
/* xxx.css */
.container{
    width: 100%;
    height: 100%;
    flex-direction: column;
    align-items: center;
    background-color: white;
    justify-content: center;
}
.btn{
    width: 280px;
    font-size: 26px;
    margin: 10px;
}
.title {
    width: 300px;
    height: 36px;
    color: black;
    font-size: 30px;
}
// xxx.js
export default {
    data: {
        visible: false,
        display: true,
    },
    toggleShow: function() {
        this.visible = !this.visible;
    },
    toggleDisplay: function() {
        this.display = !this.display;
    }
}

优化渲染优化:show方法。

  • 当show为true时,节点正常渲染。
  • 当show为false时,仅仅设置display样式为none。
<!-- xxx.hml -->
<div class="container">
  <input class="btn" type="button" value="toggle" onclick="toggle"/>
  <text style="color: red;" show="{{visible}}" > Hello World </text>
</div>
/* xxx.css */
.container{
    width: 100%;
    height: 100%;
    flex-direction: column;
    align-items: center;
    background-color: white;
    justify-content: center;
}
.btn{
    width: 280px;
    font-size: 26px;
    margin: 10px;
}
// xxx.js
export default {
    data: {
        visible: false,
    },
    toggle: function() {
        this.visible = !this.visible;
    },
}

说明: 禁止在同一个元素上同时设置for和if属性。

CSS语法参考

CSS是描述HML页面结构的样式语言。所有组件均存在系统默认样式,也可在页面CSS样式文件中对组件、页面自定义不同的样式。

样式导入

为了模块化管理和代码复用,CSS样式文件支持“@import”语句导入css文件。

声明样式

每个页面目录下存在一个与布局hml文件同名的css文件用来描述该hml页面中组件的样式,决定组件应该如何显示。

  1. 内部样式,支持使用style、class属性来控制组件的样式。例如:

    <!-- index.hml -->
     <div class="container">
       <text style="color: red">Hello World</text>
     </div>
    /* index.css */
     .container {
         width: 100%;
         height: 100%;
         align-items: center;
         background-color: white;
         flex-direction:column;
         justify-content: center;
     }
    
  2. 导入外部样式文件。例如,在common目录中定义样式文件“style.css”,并在“index.css”文件首行中进行导入:

    /* style.css */
     .title {
         font-size: 38px;
     }
    /* index.css */
     @import '../../common/style.css';
    .container {
         width: 100%;
         height: 100%;
         align-items: center;
         background-color: white;
         flex-direction:column;
         justify-content: center;
     }
    
    <!-- index.hml -->
    <div class="container">
       <text class="title" style="color: red">Hello World</text>
     </div>
    

选择器

CSS选择器用于选择需要添加样式的元素,支持的选择器如表1所示。

表 1 CSS选择器

选择器

样例

样例说明

.class

.container

用于选择class="container"的组件。

#id

#titleId

用于选择id="titleId"的组件。

,

.title, .content

用于选择class="title"和class="content"的组件。

示例:

<!-- 页面布局xxx.hml -->
<div id="containerId" class="container">
  <text id="titleId" class="title">标题</text>
  <div class="content">
    <text id="contentId">内容</text>
  </div>
</div>
/* 页面样式xxx.css */
/* 对class="title"的组件设置样式 */
.title {
    width: 150px;
    height: 70px;
    color: black;
    font-size: 38px;
}
/* 对id="contentId"的组件设置样式 */
#contentId {
    width: 150px;
    height: 70px;
    color: black;
    font-size: 38px;
}
.content{
    width: 150px;
    height: 70px;
    background-color: white;
}
/* 对所有class="title"以及class="content"的组件都设置padding为5px */
.title, .content {
    padding: 5px;
}
#containerId{
    width: 100%;
    height: 100%;
    background-color: white;
}
#titleId{
    color: green;
}
.container {
    width: 100%;
    height: 100%;
    align-items: center;
    flex-direction:column;
    justify-content: center;
}

伪类

CSS伪类是选择器中的关键字如表2所示,用于指定要选择元素的特殊状态。

表 2 CSS伪类

名称

支持组件

说明

:active

input[type="button"]

表示被用户激活的元素,如:被用户按下的按钮。轻量级智能穿戴上伪类选择器上仅支持background-color 和background-image的样式设置。

:checked

input[type="checkbox"、type="radio"]

表示checked属性为true的元素。轻量级智能穿戴上伪类选择器上仅支持background-image的样式设置。

设置按钮的“:active”伪类可以控制被用户按下时的样式,伪类示例如下:

<!-- index.hml -->
<div class="container">
  <input type="button" class="button" value="Button"></input>
</div>
/* index.css */
.container{
    width: 100%;
    height: 100%;
    align-items: center;
    justify-content: center;
}
.button:active {
    background-color: #888888;/*按钮被激活时,背景颜色变为#888888 */
}

JS语法参考

JS文件用来定义HML页面的业务逻辑,支持ECMA(European Computer Manufacturers Association,欧洲计算机制造商协会)规范的JavaScript语言。基于JavaScript语言的动态化能力,可以使应用更加富有表现力,具备更加灵活的设计能力。下面讲述JS文件的编译和运行的支持情况。

语法

支持ES6语法。轻量级智能穿戴支持的ES6语法有限,仅支持以下ES6语法:let/const、arrow functions、class、default value、destructuring assignment、destructuring binding pattern、enhanced object initializer、for-of、rest parameter、template strings。

  • 模块声明

    使用import方法引入功能模块:import router from '@system.router';

  • 代码引用

    使用import方法导入js代码:import utils from '../../common/utils.js';

对象

表 1 页面对象

属性

类型

说明

data

Object/Function

页面的数据模型,类型是对象或者函数,如果类型是函数,返回值必须是对象。属性名不能以$或_开头,不要使用保留字for、if、show、tid。

$refs

Object

持有注册过ref属性的DOM元素或子组件实例的对象。示例请参见“获取DOM元素”。

获取DOM元素

通过$refs获取DOM元素代码示例如下:

 <!-- index.hml -->
 <div class="container">
   <image-animator class="image-player" ref="animator" images="{{images}}" duration="1s" onclick="handleClick"></image-animator>
 </div>
// index.js
 export default {
     data: {
         images: [
             { src: '/common/frame1.png' },
             { src: '/common/frame2.png' },
             { src: '/common/frame3.png' },
         ],
     },
     handleClick() {
         const animator = this.$refs.animator; // 获取ref属性为animator的DOM元素
         const state = animator.getState();
         if (state === 'paused') {
             animator.resume();
         } else if (state === 'stopped') {
             animator.start();
         } else {
             animator.pause();
         }
     },
 };
 /** css **/
.container {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: white;
}
.image-player{
    width: 210px;
    height: 210px;
    background-color: white;
}

生命周期

应用生命周期

在app.js中可以定义如表1所示应用生命周期函数。

表 1 应用生命周期函数

属性

类型

说明

触发时机

onCreate

() => void

应用创建

当应用创建时调用。

onDestroy

() => void

应用销毁

当应用退出时触发。

页面生命周期

在页面JS文件中可以定义如表2所示页面生命周期函数。

表 2 页面生命周期函数

属性

类型

说明

触发时机

onInit

() => void

页面初始化

页面数据初始化完成时触发,只触发一次。

onReady

() => void

页面创建完成

页面创建完成时触发,只触发一次。

onShow

() => void

页面显示

页面显示时触发。

onHide

() => void

页面消失

页面消失时触发。

onDestroy

() => void

页面销毁

页面销毁时触发。

页面A的生命周期接口的调用步骤如下:

  1. 打开页面A:onInit() → onReady() → onShow()
  2. 在页面A打开页面B:onHide() → onDestroy()
  3. 从页面B返回页面A:onInit() → onReady() → onShow()
  4. 退出页面A:onHide() → onDestroy()
  5. 页面隐藏到后台运行:onHide()
  6. 页面从后台运行恢复到前台:onShow()

图 1 APP生命周期图

APP生命周期图

国际化

地区语言

语言场景资源内容

**语言场景资源内容**

在JS应用中添加语言资源

JSApp工程中i18n目录添加应用所需语言strings资源内容,并在app中引用。

json文件的命名格式可参考:zh-CN.json、en-US.json。

支持范围限制:支持的语言符合ISO 639标准2字母或3字母语言码,支持的国家符合ISO 3166标准2字母国家码。

示例:

<!-- xxx.json  -->
{
   "strings": {
     "hello": "您好",
     "world": "世界"
   }
}
<!-- xxx.hml -->
<div class="container">
     <text class="title" on:click="exit">
        {{ $t('strings.hello') }} {{ $t('strings.world') }}
     </text>
</div>

应用名与图标资源:

在entry→src→main→resources目录下,有base、en_US、zh_CN三个目录,分别代表默认、英语、中文资源,开发者可以根据不同语言、国家地区进行自定义。在其下级目录element中有“string.json”文件,修改其中value的值即可更改应用名称。其下级目录media中存储不同语言对应的图标资源文件。

地区语言

说明: 发布包默认支持中英,客户根据商用字库能力按需扩展。 扩展时,请根据多语言资源数量按需调整 MAX_RES_CONFIG_NUM,定义位置见 global_utils.c

切换语言

请在产品Settings系统设置应用中添加语言设置,调用以下C++接口切换系统语言,并设置默认字体样式。

示例:

#include "global.h"
#include "product_adapter.h"
// 中文
GLOBAL_ConfigLanguage("zh-CN");
// 英文
GLOBAL_ConfigLanguage("en-US");
// 根据语言设置对应的JS默认字体样式,参数1是字体名称,参数2是字体大小。
ACELite::ProductAdapter::SetDefaultFontStyle("FontName.ttf", 24);

说明: 语言等相关配置,需在Settings中管理持久化。在系统启动时,查询持久化配置,调用global API初始化JSApp语言和默认字体样式。

由于 HelloWorld 示例只展示了最小页面,开发实际 JS 应用时可以继续参考以下组件和接口能力,用于扩展页面布局、交互事件、系统服务调用和设备能力访问。