同步操作将从 OpenHarmony/docs 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
应用首页主要展示城市的空气质量概况。首页总共有两屏(可以根据需求设置多屏),每屏显示一个城市的空气质量信息:主要包括AQI指数、城市名称、污染物指数、更新时间和信息来源等数据。
从第一章节中的显示效果图分析可知,首页由三部分组成:
综上,我们可搭建一个纵向三行排列的弹性页面布局来实现首页的功能。
在hml文件中添加一个根节点div,注意每个hml文件中有且只能有一个根节点,代码如下:
<div class="container">
</div>
class="container"表示组件使用的样式,container是index.css文件中的一个样式类,代码如下:
.container {
flex-direction: column;
height: 480px;
width: 960px;
}
在这个样式类中,我们分别设置了根组件div的高度和宽度(注意在应用的开发过程中,除部分组件(text)外必须显式指定组件的高度和宽度,否则可能无法显示)、并将flex-direction属性设置为column,该属性表示div的子组件是垂直方向从上到下排列;这样就可以实现本节开头所说的纵向三行排列的弹性页面布局。
实现标题栏:标题栏包括一个退出按钮和一个标题,两个控件是横向排列;首先添加一个div,并设置flex-direction的属性为row,表示子组件是水平方向从左往右排列;然后依次添加一个image和text组件,代码如下:
<div class="container">
<div class="header" onclick="exitApp">
<image class="back" src="common/ic_back.png"></image>
<text class="title">
空气质量
</text>
</div>
</div>
设置组件的高度、边距、颜色等属性。
.header {
width: 960px;
height: 72px;
}
.back {
width: 36px;
height: 36px;
margin-left: 39px;
margin-top: 23px;
}
.title {
width: 296px;
height: 40px;
margin-top: 20px;
margin-left: 21px;
color: #e6e6e6;
}
onclick="exitApp" 设置了div组件的click事件,当在标题栏上触发点击事件时,就会执行函数exitApp,该函数位于index.js文件中,代码如下:
exitApp() {
console.log('start exit');
app.terminate();
console.log('end exit');
}
app.terminate()函数实现了程序退出功能;在使用该函数前,需要引入app模块,在js文件的最上方写如下代码:
import app from '@system.app'
代码编写完成后,在模拟器中运行项目,显示效果如下图所示:
实现城市空气质量信息的多屏左右滑动,需要使用“swiper”组件。
在根节点中添加一个子节点swiper,代码片段如下:
<div class="container">
<div class="header" onclick="exitApp">
<image class="back" src="common/ic_back.png"></image>
<text class="title">
空气质量
</text>
</div>
<swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
</swiper>
</div>
class="swiper"设置了组件的高度和宽度,代码如下:
.swiper {
height: 385px;
width: 960px;
}
index="{{swiperPage}}" duration="500" onchange="swiperChange" 这些代码用来设置组件的属性和事件。其中,duration="500" 表示设置swiper的页面滑动的动画时长为500ms。
index="{{swiperPage}}"设置了swiper子组件索引值,{{swiperPage}}这种写法表示index的值是和js代码中的swiperPage变量动态绑定的,index的值会随着swiperPage变动而改变。
onchange="swiperChange" 设置了swiper组件的change事件和函数swiperChange绑定,对应的js代码如下:
//引入router模块,用户页面跳转
import router from'@system.router'
import app from '@system.app'
export default {
//定义参数
data: {
//默认是第一页
swiperPage: 0
},
onInit () {
},
exitApp(){
console.log('start exit');
app.terminate();
console.log('end exit');
},
//swiper滑动回调事件,保存当前swiper的index值,每次滑动都会将index值保存在swiperPage变量中
swiperChange (e) {
this.swiperPage = e.index;
}
}
设置一个城市的空气质量信息为一屏,在一屏内,要展示多种信息,分别使用不同的控件进行展示。
在swiper中添加两个子组件stack(绝对布局),每个stack组件内分别添加text、image、progress等组件来显示对应的信息 ,页面结构如下:
<swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
<!--第一屏-->
<stack class="swiper">
<text></text>------空气质量
<text></text>------城市名称
<progress></progress>-----进度条
<image></image>-------云朵图片
<text></text>--------AQI数值
<text>AQI</text>------AQI
<div>--------空气指标详细信息
</div>
<div>--------更新时间和网站等信息
</div>
</stack>
<!--第二屏-->
<stack class="container">
<text></text>
<text></text>
<progress></progress>
<image></image>
<text></text>
<text></text>
<div></div>
</stack>
</swiper>
代码编写完成后,模拟器运行效果如下:
添加页面位置指示器:由于当前swiper不支持设置indicator,需要开发者自己来实现该效果。在根节点中添加一个子组件div,并设置相应样式;然后在该div中添加两个子组件div,设置两个div的border-radius,并在swiper滑动事件中动态改变对应div的背景色来实现该效果。
<div class="images">
<div class="circle-div" style="background-color: {{iconcheckedColor}};"></div>
<div class="circle-div" style="background-color: {{iconUncheckedColor}};margin-left: 36px;"></div>
</div>
所有组件设置样式、动画效果和数据动态绑定,完整代码如下所示:
<div class="container">
<div class="header" onclick="exitApp">
<image class="back" src="common/ic_back.png"></image>
<text class="title">
空气质量
</text>
</div>
<swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
<stack class="swiper">
<text class="airquality" style="color:{{textColor1}};">{{airData[0].airQuality}}
</text>
<text class="location-text">{{airData[0].location}}
</text>
<progress class="circle-progress" style="color: {{textColor1}};background-Color: {{bgColor1}};" type="arc"
percent="{{percent1}}"></progress>
<image class="image" src="{{src1}}"></image>
<text class="aqi-value">{{airData[0].detailData}}
</text>
<text class="aqi">
AQI
</text>
<div class="detail">
<div class="text-wrapper">
<text class="gas-name">
CO
</text>
<text class="gas-value">
100
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
NO2
</text>
<text class="gas-value">
90
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
PM10
</text>
<text class="gas-value">
120
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
PM2.5
</text>
<text class="gas-value">
40
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
SO2
</text>
<text class="gas-value">
150
</text>
</div>
<input class="btn" type="button" onclick="openDetail" value="历史记录"></input>
</div>
<div class="footer">
<text class="update-time">
更新时间: 10:38
</text>
<text class="info-source">
信息来源: tianqi.com
</text>
</div>
</stack>
<stack class="swiper">
<text class="airquality" style="color: {{textColor2}};">{{airData[1].airQuality}}
</text>
<text class="location-text">{{airData[1].location}}
</text>
<progress class="circle-progress" style="color: {{textColor2}};background-Color: {{bgColor2}};" type="arc"
percent="{{percent2}}"></progress>
<image class="image" src="{{src2}}"></image>
<text class="aqi-value">{{airData[1].detailData}}
</text>
<text class="aqi">
AQI
</text>
<div class="detail">
<div class="text-wrapper">
<text class="gas-name">
CO
</text>
<text class="gas-value">
10
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
NO2
</text>
<text class="gas-value">
50
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
PM10
</text>
<text class="gas-value">
60
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
PM2.5
</text>
<text class="gas-value">
40
</text>
</div>
<div class="text-wrapper">
<text class="gas-name">
SO2
</text>
<text class="gas-value">
150
</text>
</div>
<input class="btn" type="button" onclick="openDetail" value="历史记录"></input>
</div>
<div class="footer">
<text class="update-time">
更新时间: 10:38
</text>
<text class="info-source">
信息来源: tianqi.com
</text>
</div>
</stack>
</swiper>
<div class="images">
<div class="circle-div" style="background-color: {{iconcheckedColor}};"></div>
<div class="circle-div" style="background-color: {{iconUncheckedColor}};margin-left: 36px;"></div>
</div>
</div>
css文件中定义了许多class,每个class用于定义组件的位置、大小、字体、颜色、背景色等信息。同时,每一个子组件都叠加在父组件中,父组件的样式会影响子组件的呈现。
.aqi-value {
text-align: center;
font-size: 65px;
color: #f0ffff;
width: 156px;
height: 92px;
top: 134px;
left: 210px;
}
.aqi {
text-align: center;
color: #a2c4a2;
width: 156px;
height: 45px;
top: 90px;
left: 210px;
}
.airquality {
top: 222px;
text-align: center;
width: 156px;
height: 45px;
left: 210px;
}
.image {
top: 285px;
left: 274px;
width: 32px;
height: 32px;
}
.location-text {
text-align: center;
color: #ffffff;
width: 200px;
height: 52px;
font-size: 40px;
left: 380px;
top: 16px;
}
.container {
flex-direction: column;
height: 480px;
width: 960px;
}
.circle-progress {
center-x: 128px;
center-y: 128px;
radius: 128px;
startAngle: 198;
totalAngle: 320;
strokeWidth: 24px;
width: 256px;
height: 256px;
left: 160px;
top: 58px;
}
.detail {
width: 256px;
height: 265px;
left: 544px;
top: 58px;
flex-direction: column;
}
.text-wrapper {
width: 256px;
height: 35px;
margin-top: 6px;
}
.gas-name {
width: 128px;
height: 35px;
text-align: left;
}
.gas-value {
width: 128px;
height: 35px;
text-align: right;
}
.btn {
width: 180px;
height: 50px;
margin-top: 6px;
margin-left: 38px;
background-color: #1a1a1a;
color: #1085CE;
}
.footer {
top: 326px;
width: 960px;
height: 28px;
}
.header {
width: 960px;
height: 72px;
}
.back {
width: 36px;
height: 36px;
margin-left: 39px;
margin-top: 23px;
}
.title {
width: 296px;
height: 40px;
margin-top: 20px;
margin-left: 21px;
color: #e6e6e6;
}
.swiper {
height: 385px;
width: 960px;
}
.images {
width: 60px;
height: 15px;
margin-left: 450px;
}
.update-time {
width: 480px;
height: 28px;
font-size: 20px;
color: #A9A9A9;
text-align: right;
}
.info-source {
width: 450px;
height: 28px;
font-size: 20px;
color: #A9A9A9;
text-align: left;
margin-left: 24px;
}
.circle-div {
width: 12px;
height: 12px;
border-radius: 6px;
}
js文件主要用于实现App应用的逻辑交互。在本页面js文件中,需要实现如下功能:根据数值动态改变文字、进度条颜色、页面跳转。
//导入router和app模块
import router from '@system.router'
import app from '@system.app'
export default {
data: {
//页面绑定数据
textColor1: '#00ff00',
textColor2: '#00ff00',
bgColor1: '#669966',
bgColor2: '#669966',
swiperPage: 0,
percent1: 40,
percent2: 90,
iconUncheckedColor: '#262626',
iconcheckedColor: '#ffffff',
iconcheckedBR: '6px',
src1: 'common/cloud_green.png',
src2: 'common/cloud_green.png',
airData: [{
location: '东莞',
airQuality: '良',
detailData: 40
}, {
location: '深圳',
airQuality: '差',
detailData: 90
}]
},
onInit () {
//根据数值的不同,设置不同的字体、背景颜色和图片
if(this.airData[0].detailData > 100){
this.src1 = 'common/cloud_red.png';
this.textColor1 = '#ff0000';
this.bgColor1 = '#9d7462';
} else if(50 < this.airData[0].detailData && this.airData[0].detailData <= 100){
this.src1 = 'common/cloud_yellow.png';
this.textColor1 = '#ecf19a';
this.bgColor1 = '#9d9d62';
}
if(this.airData[1].detailData > 100){
this.src2 = 'common/cloud_red.png';
this.textColor2 = '#ff0000';
this.bgColor2 = '#9d7462';
} else if(50 < this.airData[1].detailData && this.airData[1].detailData <= 100){
this.src2 = 'common/cloud_yellow.png';
this.textColor2 = '#ecf19a';
this.bgColor2 = '#9d9d62';
}
if(this.selectedCityIndex){
this.swiperPage = this.selectedCityIndex;
if(this.swiperPage == 0){
this.iconcheckedColor = '#ffffff';
this.iconUncheckedColor = '#262626';
}else{
this.iconcheckedColor = '#262626';
this.iconUncheckedColor = '#ffffff';
}
}
},
//跳转到详情页面
openDetail () {
router.replace({
uri: 'pages/detail/detail',
params: {selectedCityIndex:this.swiperPage}
});
},
//退出应用
exitApp(){
console.log('start exit');
app.terminate();
console.log('end exit');
},
//页面滑动事件,滑动时改变最新的标识
swiperChange (e) {
this.swiperPage = e.index;
if(e.index == 0){
this.iconcheckedColor = '#ffffff';
this.iconUncheckedColor = '#262626';
}else{
this.iconcheckedColor = '#262626';
this.iconUncheckedColor = '#ffffff';
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。