华为鸿蒙应用程序开发13JavaScriptUI之HML,CSS,JS语法介绍
本章内容HML语法CSS语法JavaScript
HML、CSS、JavaScript在前面的章节中一直在用,现在就来专门介绍它们。一 HML语法
HML(HarmonyOS Markup Language)是一套类HTML的标记语言,通过组件,事件构建出页面的内容。页面具备数据绑定、事件绑定、列表渲染、条件渲染和逻辑控制等高级能力。
关于页面结构我们这里就不再介绍了,前面我们一直在用组件构建页面。数据绑定我们也在前面章节中用到了很多次,现在我们就来看看。
1 数据绑定
通过在HML页面中用双大括号语法来声明数据,然后在JS文件中通过data对象进行赋值,下面是典型示例 {{content[1]}} // xxx.js export default { data: { content: ["Hello World!", "Welcome to my world!"] }, changeText: function() { this.content.splice(1, 1, this.content[0]); } }
2 事件
通过‘on"或者‘@’将事件绑定在组件上,当组件触发事件时会执行JS文件中对应的事件处理函数。事件绑定的典型示例: {{count}} // xxx.js export default { data: { count: 0 }, increase() { this.count++; }, multiply(multiplier) { this.count = multiplier * this.count; } };
HML组件还支持冒泡事件绑定。冒泡事件绑定包括:绑定冒泡事件:on:{event}.bubble。on:{event}等价于on:{event}.bubble。绑定并阻止冒泡事件向上冒泡:grab:{event}.bubble。grab:{event}等价于grab:{event}.bubble。
典型示例如下: // xxx.js export default { clickfunc: function(e) { console.log(e); }, touchstartfuc: function(e) { console.log(e); }, }
Touch触摸类事件支持捕获,捕获阶段位于冒泡阶段之前,捕获事件先到达父组件然后达到子组件。
捕获事件绑定包括:绑定捕获事件:on:{event}.capture。绑定并阻止事件向下传递:grab:{event}.capture。
示例如下: // xxx.js export default { touchstartfuc: function(e) { console.log(e); }, }
3 列表渲染
在「华为鸿蒙应用程序开发 12」JavaScript UI常用基础组件Image这个章节中,我们显示多张图片时有用到列表渲染。列表渲染就是通过组件的for属性,循环构建组件,示例如下: {{$idx}}.{{$item.name}} {{$idx}}.{{value.name}} {{index}}.{{value.name}} // 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}); } }, }
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不支持表达式。
HML中的条件渲染分为2种:if/elif/else和show。两种写法的区别在于:第一种写法里if为false时,组件不会在vdom中构建,也不会渲染,而第二种写法里show为false时虽然也不渲染,但会在vdom中构建;另外,当使用if/elif/else写法时,节点必须是兄弟节点,否则编译无法通过。实例如下: Hello-TV Hello-Wearable Hello-World /* xxx.css */ .container{ flex-direction: column; align-items: center; } .btn{ width: 280px; font-size: 26px; margin: 10px 0; }// xxx.js export default { data: { visible: false, display: true, }, toggleShow: function() { this.visible = !this.visible; }, toggleDisplay: function() { this.display = !this.display; } }
渲染优化:show方法。当show为true时,节点正常渲染;当为false时,仅仅设置display样式为none。示例如下: Hello World /* xxx.css */ .container{ flex-direction: column; align-items: center; } .btn{ width: 280px; font-size: 26px; margin: 10px 0; }// xxx.js export default { data: { visible: false, }, toggle: function() { this.visible = !this.visible; }, }
说明
禁止在同一个元素上同时设置for和if属性
4 逻辑控制块
它使得循环渲染和条件渲染变得更加灵活;block在构建时不会被当作真实的节点编译。注意block标签只支持for和if属性。示例: {{$item.name}} {{$item.age}}
// xxx.js export default { data: { glasses: [ {name:"sunglasses", kinds:[{name:"XXX",color:"XXX"},{name:"XXX",color:"XXX"}]}, {name:"nearsightedness mirror", kinds:[{name:"XXX",color:"XXX"}]}, ], }, }
5 模板引用
HML可以通过element引用模板文件,在自定义组件时会很有用。示例: Name: {{name}} Age: {{age}} 二 CSS语法
CSS是描述HML页面结构的样式语言。所有组件均存在系统默认样式,也可在页面CSS样式文件中对组件、页面自定义不同的样式。
1 尺寸单位逻辑像素px(文档中以表示): 默认屏幕具有的逻辑宽度为720px(配置见配置文件中的window小节),实际显示时会将页面布局缩放至屏幕实际宽度,如100px在实际宽度为1440物理像素的屏幕上,实际渲染为200物理像素(从720px向1440物理像素,所有尺寸放大2倍)。 额外配置autoDesignWidth为true时(配置见配置文件中的window小节),逻辑像素px将按照屏幕密度进行缩放,如100px在屏幕密度为3的设备上,实际渲染为300物理像素。应用需要适配多种设备时,建议采用此方法。百分比(文档中以表示):表示该组件占父组件尺寸的百分比,如组件的width设置为50%,代表其宽度为父组件的50%。
2 样式导入
为了模块化管理和代码复用,CSS样式文件支持 @import 语句,导入css文件。
3 声明样式
每个页面目录下存在一个与布局hml文件同名的css文件,用来描述该hml页面中组件的样式,决定组件应该如何显示。
(1)内部样式,支持使用style、class属性来控制组件的样式。例如: Hello World /* index.css */ .container { justify-content: center; }
(2)文件导入,合并外部样式文件。例如,在common目录中定义样式文件style.css,并在index.css文件首行中进行导入:/* style.css */ .title { font-size: 50px; }/* index.css */ @import "../../common/style.css"; .container { justify-content: center; }
4 选择器
css选择器用于选择需要添加样式的元素,支持的选择器如下表所示:
选择器
样例
样例描述
.class
.container
用于选择class="container"的组件。
#id
#titleId
用于选择id="titleId"的组件。
tag
text
用于选择text组件。
,
.title, .content
用于选择class="title"和class="content"的组件。
#id .class tag
#containerId .content text
非严格父子关系的后代选择器,选择具有id="containerId"作为祖先元素,class="content"作为次级祖先元素的所有text组件。如需使用严格的父子关系,可以使用">"代替空格,如:#containerId>.content。
示例: 标题 内容 /* 页面样式xxx.css */ /* 对所有p组件设置样式 */ p { flex-direction: column; } /* 对class="title"的组件设置样式 */ .title { font-size: 30px; } /* 对id="contentId"的组件设置样式 */ #contentId { font-size: 20px; } /* 对所有class="title"以及class="content"的组件都设置padding为5px */ .title, .content { padding: 5px; } /* 对class="container"的组件下的所有text设置样式 */ .container text { color: #007dff; } /* 对class="container"的组件下的直接后代text设置样式 */ .container > text { color: #fa2a2d; }
5 选择器优先级
选择器的优先级计算规则与w3c规则保持一致(只支持:内联样式,id,class,tag,后代和直接后代),其中内联样式为在元素style属性中声明的样式。
当多条选择器声明匹配到同一元素时,各类选择器优先级由高到低顺序为:内联样式 > id > class > tag。
6 伪类
css伪类是选择器中的关键字,用于指定要选择元素的特殊状态。例如,:disabled状态可以用来设置元素的disabled属性变为true时的样式。
除了单个伪类之外,还支持伪类的组合,例如,:focus:checked状态可以用来设置元素的focus属性和checked属性同时为true时的样式。支持的单个伪类如下表所示,按照优先级降序排列:
名称
支持组件
描述
:disabled
支持disabled属性的组件
表示disabled属性变为true时的元素(不支持动画样式的设置)。
:focus
支持focusable属性的组件
表示获取focus时的元素(不支持动画样式的设置)。
:active
支持click事件的组件
表示被用户激活的元素,如:被用户按下的按钮、被激活的tab-bar页签(不支持动画样式的设置)。
:waiting
button
表示waiting属性为true的元素(不支持动画样式的设置)。
:checked
input[type="checkbox"、type="radio"]、 switch
表示checked属性为true的元素(不支持动画样式的设置)。
:hover6+
支持mouseover事件的组件
表示鼠标悬浮时的元素。
伪类示例如下,设置按钮的:active伪类可以控制被用户按下时的样式: /* index.css */ .button:active { background-color: #888888;/*按钮被激活时,背景颜色变为#888888 */ }说明
针对弹窗类组件及其子元素不支持伪类效果,包括popup、dialog、menu、option、picker
7 样式预编译
预编译提供了利用特有语法生成css的程序,可以提供变量、运算等功能,令开发者更便捷地定义组件样式,目前支持less、sass和scss的预编译。使用样式预编译时,需要将原css文件后缀改为less、sass或scss,如index.css改为index.less、index.sass或index.scss。
(1)当前文件使用样式预编译,例如将原index.css改为index.less:/* index.less */ /* 定义变量 */ @colorBackground: #000000; .container { background-color: @colorBackground; /* 使用当前less文件中定义的变量 */ }
(2)引用预编译文件,例如common中存在style.scss文件,将原index.css改为index.scss,并引入style.scss:/* style.scss */ /* 定义变量 */ $colorBackground: #000000;
在index.scss中引用:/* index.scss */ /* 引入外部scss文件 */ @import "../../common/style.scss"; .container { background-color: $colorBackground; /* 使用style.scss中定义的变量 */ }说明
引用的预编译文件建议放在common目录进行管理。
8 CSS样式继承
css样式继承提供了子节点继承父节点样式的能力,继承下来的样式在多选择器样式匹配的场景下,优先级排最低,当前支持以下样式的继承:font-familyfont-weightfont-sizefont-styletext-alignline-heightletter-spacingcolorvisibility三 JavaScript语法
JS文件用来定义HML页面的业务逻辑,支持ECMA规范的JavaScript语言。基于JavaScript语言的动态化能力,可以使应用更加富有表现力,具备更加灵活的设计能力。下面讲述JS文件的编译和运行的支持情况。
1 语法
支持ES6(EMACScript 6)语法。模块声明
使用import方法引入功能模块:import router from "@system.router";代码引用
使用import方法导入js代码:import utils from "../../common/utils.js";
2 对象
(1)应用对象$def
使用this.$app.$def获取在app.js中暴露的对象。说明
应用对象不支持数据绑定,需主动触发UI更新。
示例代码// app.js export default { onCreate() { console.info("AceApplication onCreate"); }, onDestroy() { console.info("AceApplication onDestroy"); }, globalData: { appData: "appData", appVersion: "2.0", }, globalMethod() { console.info("This is a global method!"); this.globalData.appVersion = "3.0"; } };// index.js页面逻辑代码 export default { data: { appData: "localData", appVersion:"1.0", }, onInit() { this.appData = this.$app.$def.globalData.appData; this.appVersion = this.$app.$def.globalData.appVersion; }, invokeGlobalMethod() { this.$app.$def.globalMethod(); }, getAppVersion() { this.appVersion = this.$app.$def.globalData.appVersion; } }
(2)页面对象
属性
类型
描述
data
Object/Function页面的数据模型,类型是对象或者函数,如果类型是函数,返回值必须是对象。属性名不能以$或_开头,不要使用保留字for, if, show, tid。
data与private和public不能重合使用。
$refs
Object
持有注册过ref 属性的DOM元素或子组件实例的对象。示例见获取DOM元素。
private
Object
页面的数据模型,private下的数据属性只能由当前页面修改。
public
Object
页面的数据模型,public下的数据属性的行为与data保持一致。
props
Array/Object
props用于组件之间的通信,可以通过方式传递给组件;props名称必须用小写,不能以$或_开头,不要使用保留字for, if, show, tid。目前props的数据类型不支持Function。示例见自定义组件。
computed
Object
用于在读取或设置进行预先处理,计算属性的结果会被缓存。计算属性名不能以$或_开头,不要使用保留字。示例见自定义组件。
其中data对象我们在前面章节的例子中用到过很多次。
3 方法
(1)数据方法
方法
参数
描述
$set
key: string, value: any添加新的数据属性或者修改已有数据属性。
用法:
this.$set("key",value):添加数据属性。
$delete
key: string删除数据属性。
用法:
this.$delete("key"):删除数据属性。
示例代码:// index.js export default { data: { keyMap: { OS: "HarmonyOS", Version: "2.0", }, }, getAppVersion() { this.$set("keyMap.Version", "3.0"); console.info("keyMap.Version = " + this.keyMap.Version); // keyMap.Version = 3.0 this.$delete("keyMap"); console.info("keyMap.Version = " + this.keyMap); // log print: keyMap.Version = undefined } }
(2)公共方法
方法
参数
描述
$element
id: string获得指定id的组件对象,如果无指定id,则返回根组件对象。示例见获取DOM元素。
用法:
this.$element("xxx"):获得id为xxx的组件对象。this.$element():获得根组件对象。
$rootElement
无获取根组件对象。
用法:this.$rootElement().scrollTo({ duration: 500, position: 300 }), 页面在500ms内滚动300px。
$root
无
获得顶级ViewModel实例。获取ViewModel示例。
$parent
无
获得父级ViewModel实例。获取ViewModel示例。
$child
id: string获得指定id的子级自定义组件的ViewModel实例。获取ViewModel示例。
用法:
this.$child("xxx") :获取id为xxx的子级自定义组件的ViewModel实例。
(3)事件方法
方法
参数
描述
$watch
data: string, callback: string | Function观察data中的属性变化,如果属性值改变,触发绑定的事件。示例见自定义组件。
用法:
this.$watch("key", callback)
(4)页面方法
方法
参数
描述
scrollTo
scrollPageParam: ScrollPageParam
将页面滚动到目标位置,可以通过ID选择器指定或者滚动距离指定。
scrollPageParam有如下取值
名称
类型
默认值
描述
position
number
-
指定滚动位置。
id
string
-
指定需要滚动到的元素id。
duration
number
300
指定滚动时长,单位为毫秒。
timingFunction
string
ease指定滚动动画曲线,可选值参考
animation-timing-function。
complete
() => void
-
指定滚动完成后需要执行的回调函数。
示例:this.$rootElement.scrollTo({position: 0}); this.$rootElement.scrollTo({ id: "id", duration: 200, timingFunction: "ease-in", complete: ()=>void });
(5)获取DOM元素通过$refs获取DOM元素 // 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(); } }, };通过$element获取DOM元素,这在前面的章节已经用到过。示例: // index.js export default { data: { images: [ { src: "/common/frame1.png" }, { src: "/common/frame2.png" }, { src: "/common/frame3.png" }, ], }, handleClick() { const animator = this.$element("animator"); // 获取id属性为animator的DOM元素 const state = animator.getState(); if (state === "paused") { animator.resume(); } else if (state === "stopped") { animator.start(); } else { animator.pause(); } }, };
(6)获取ViewMode
根节点所在页面: {{text}} // root.js export default { data: { text: "I am root!", },
自定义parent组件: parent component click hello parent component! // parent.js export default { data: { show: false, text: "I am parent component!", }, parentClicked () { this.show = !this.show; console.info("parent component get parent text"); console.info(`${this.$parent().text}`); console.info("parent component get child function"); console.info(`${this.$child("selfDefineChild").childClicked()}`); }, }
自定义child组件: child component clicked hello child component // child.js export default { data: { show: false, text: "I am child component!", }, childClicked () { this.show = !this.show; console.info("child component get parent text"); console.info("${this.$parent().text}"); console.info("child component get root text"); console.info("${this.$root().text}"); }, }
至此,关于华为鸿蒙应用开发中HML、CSS、JavaScript语法部分的介绍就讲完了,本章尽量用实例对每个知识点进行了直观地呈现,大家可以先都熟悉下,然后在以后的开发中不记得的可以回过头查看。
最后,老规矩,敲黑板:多动手,多思考!代码一定要亲自动手敲出来![呲牙][比心]
族人往国外发展,修家谱会受影响吗?家谱家谱记录了一个家族的发展过程,家谱中记录的每一个名字,都对家族的发展有着极其重要的影响。随着大家的生活提高,很多人都往国外发展,这种现象对家谱的传承有影响吗?现实的结果还真的是
女儿能否作为家族的传承者?家谱对于一个家庭来说,子女不但是血脉的传承,更是一个家族维持兴旺的香火。但是对于很多有家谱的家族来说,女儿妻子能否入家谱?这种尖锐的问题却一直存在。其实作为一个记录家族发展的史书,
大家族的家谱都秘不示人,公开是有原因的家庭家是大家口中最温馨的港湾,之所以每次提到家都会感觉温暖,最大的原因还是因为家对于每个人来说,并不是一个物质上的空间,而是一种精神的支撑,一种信仰的力量。家谱作为一个家族历史发展
名门修谱失谱的族系该如何修谱?族谱早期发布过一条有家谱,不愿意修,说出理由很现实的文章,发出之后很多网友也纷纷给出了自己对修谱的认识。其中有一些对谱牒文化颇有研究的老师,针对那些因为失谱而不愿修的人,给出了一些
朋友圈圣诞节摄影大赛开始,快快带着华为P20系列出发吧!随着街道商店电商平台的各种圣诞元素扑面而来,今年圣诞节的序幕即将打开。虽然北方仍处于相当寒冷的天气中,但挡不住人们想要外出感受圣诞氛围的愿望。特别是单身的朋友,如果选择此时约会上心
华为Mate20系列双十二开抢3999起售价诚意十足虽然很多消费者在双十一期间已经剁了手,但他们的购物热情却似乎没有丝毫衰减。不知不觉双十二马上就要来了,消费者在计划这新一轮的剁手。除了消费者在忙着挑选双十二期间要购买的宝贝外,商家
名门修谱用手机修家谱,传统行业又一次被更新修家谱中国是一个拥有5000年悠久历史的文化古国,在历史的长河中,很多传统文化一直保留至今。很多文化想要被传承,就要跟上时代的步伐。家谱作为中国传统文化中的重要血脉,在如今这个信息
名门修谱海南人喜欢家谱,私藏胜于公藏传统家谱一卷卷虫蛀泛黄的线装古册,一部部重修新印的当代书本,这些在海南民间从未停止修订的家谱或族谱,记载的不仅是一个个姓氏的繁衍信息,纵向地寻根溯源,还可知道海南岛民的来源,横向地
名门修谱家谱里的南洋踪影侨乡海南与广东福建一道,是我国的三大侨乡。究竟海南人是什么时候开始出洋的?历来在正式出版的书籍中并没有详细记载,好在还有家族谱牒资料,弥补了这一遗憾。文昌是海南著名的侨乡,侨居海外
名门修谱修家谱正确的打开方式传统家谱对于以前的人来说,想要编修一本完整的家谱,要通过开丁校对排版印刷装订等各种繁琐的流程组成。其中,收集本族人的人丁信息,数最为复杂。在这个过程中,需要了解家族每个人的姓名字号
华为返场送福利麒麟990徕卡多摄,Mate30P40最佳入手时虽然618年中大促已经过去,但各家厂商似乎还没有结束的意思譬如华为提供了618促销返场活动,优惠继续!6月19日20日期间,不仅有华为Mate30系列等爆款旗舰机型享受24期分期免
本轮房地产调控的一点认识过去几轮房地产调控主要是由房价上涨过快引发的调控,调控的手段多采用限购提高首付比例和按揭利率等措施,主要调控对象是购买端。调控政策放松主要是由于经济处于下行周期而逐步放开。本轮调控
恒大地产更换董事长,恒大汽车遭高管减持昨日许家印辞去恒大地产集团董事长的消息引起了不小的波动。根据公告信息,许家印不再担任恒大集团旗下的恒大地产集团董事长,柯鹏不再担任总经理法人等职务,信任董事长总经理法人为赵长龙。恒
科比布莱恩特,惊涛骇浪短暂的一生!17岁进入NBA,因年龄太小,科比的所有程序和合同,财政,都是父母负责。1996科比加盟湖人,新秀合同3年350万,签约阿迪达斯,6年4800万,1999年科比续约湖人6年7800
清明时节雨纷纷,一键除湿不求人CiaoBello,我是老房。冬天刚刚过去,转眼间清明已经临近。清明时节雨纷纷,每天下雨烦死人。魔都的潮湿天气从清明节左右就已经开始了。想到再过两三个月就是梅雨季,每天淅淅沥沥的雨
宅家办公,如何打造整洁桌面?CiaoBello,我是老房。突如其来的疫情,给足了咱们宅在家里的时间,终于能静下心来好好收拾一下杂乱了许久的桌面。首先来看下老房家里书桌的大致情况。书桌为宜家BEKANT贝肯特右
聊聊Jmeter如何并发执行Python脚本来源AirPython作者星安果1。前言大家好,我是安果!最近有小伙伴后台给我留言,说自己用Django写了一个大文件上传的Api接口,现在想本地检验一下接口并发的稳定性,问我有没
聊聊Jmeter如何并发执行Python脚本来源AirPython作者星安果1。前言大家好,我是安果!最近有小伙伴后台给我留言,说自己用Django写了一个大文件上传的Api接口,现在想本地检验一下接口并发的稳定性,问我有没
用Python帮小伙伴找到头上一片绿的证据公众号Python技术作者派森酱这周末有个小伙伴找到派森酱,说他女票这几天整天都在上网,也不知道浏览什么内容,只要这个小伙伴凑上去瞧瞧就只看见了桌面,查看浏览器历史记录也被删除的一
用Python带你看豆瓣上征婚交友的小姐姐们作者某某白米饭来源Python技术派森酱在刷豆瓣的时候发现,豆瓣上居然还有一个叫我被豆油表白了的交友话题,阅读量居然高达8087734次,拥有1000篇话题,几乎每篇平均被阅读了8
败了,苹果彻底败了文章首发于微信公众号非著名程序员,欢迎大家关注。大家好,我是校长。苹果又败诉了,可谓是开发者的福音。01hrEpicGames案备受瞩目的EpicGames诉苹果一案今天达成判决,
苹果这是打造了一个产学研销为一体的生态平台啊文章首发于微信公众号非著名程序员,欢迎大家关注。大家好,我是校长。今天聊一聊昨天苹果的一个大事件吧。昨天,苹果宣布为小学生与教育工作者推出全新资源,包括新的人人能编程早期学习者活动