device-camera-visual-first-page.md 19.3 KB
Newer Older
W
wenjun 已提交
1 2
# 开发首页<a name="ZH-CN_TOPIC_0000001054927705"></a>

[
[yang] 已提交
3
应用首页主要展示城市的空气质量概况。首页总共有两屏(可以根据需求设置多屏),每屏显示一个城市的空气质量信息:主要包括AQI指数、城市名称、污染物指数、更新时间和信息来源等数据。
W
wenjun 已提交
4

D
duangavin123 已提交
5
从第一章节中的[显示效果图](device-camera-visual-overview.md#fig18250512195914)分析可知,首页由三部分组成:
W
wenjun 已提交
6

[
[yang] 已提交
7 8 9 10 11 12 13
-   标题栏:位于页面正上方,位置固定,包括应用退出按钮和页面标题。
-   信息栏:主要展示城市的空气信息指标等内容;该页面根据用户需求可设置多屏,且能循环滑动。
-   页面位置指示器:主要功能是标识当前页面,位置固定在页面底部的中间。

综上,我们可搭建一个纵向三行排列的弹性页面布局来实现首页的功能。

1.  在hml文件中添加一个根节点div,注意每个hml文件中有且只能有一个根节点,代码如下:
W
wenjun 已提交
14 15

    ```
[
[yang] 已提交
16 17 18 19 20 21
    <div class="container">
    </div>
    ```

    class="container"表示组件使用的样式,container是index.css文件中的一个样式类,代码如下:

W
wenjun 已提交
22
    ```
[
[yang] 已提交
23 24 25 26 27 28 29 30
    .container {    
        flex-direction: column;
        height: 480px;
        width: 960px;
    }
    ```

    在这个样式类中,我们分别设置了根组件div的高度和宽度(注意在应用的开发过程中,除部分组件(text)外必须显式指定组件的高度和宽度,否则可能无法显示)、并将flex-direction属性设置为column,该属性表示div的子组件是垂直方向从上到下排列;这样就可以实现本节开头所说的纵向三行排列的弹性页面布局。
W
wenjun 已提交
31

[
[yang] 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
2.  实现标题栏:标题栏包括一个退出按钮和一个标题,两个控件是横向排列;首先添加一个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'
    ```

    代码编写完成后,在模拟器中运行项目,显示效果如下图所示:

    **图 1**  标题栏效果<a name="fig14273162465317"></a>  
D
duangavin123 已提交
86
    ![](figure/标题栏效果.png "标题栏效果")
[
[yang] 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

3.  实现城市空气质量信息的多屏左右滑动,需要使用“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"设置了组件的高度和宽度,代码如下:
W
wenjun 已提交
106 107

        ```
[
[yang] 已提交
108 109 110
        .swiper {
            height: 385px;
            width: 960px;
W
wenjun 已提交
111 112 113
        }
        ```

114

W
wenjun 已提交
115 116 117 118 119 120 121
    -   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'
[
[yang] 已提交
122 123
        import app from '@system.app'
        
W
wenjun 已提交
124 125 126
        export default {
            //定义参数
            data: {
N
NEEN 已提交
127 128
              //默认是第一页
              swiperPage: 0 
W
wenjun 已提交
129 130 131
            },
            onInit () {
            },
[
[yang] 已提交
132 133 134 135 136
            exitApp(){  
                console.log('start exit');  
                app.terminate();  
                console.log('end exit');
            },
W
wenjun 已提交
137 138 139 140 141 142 143
            //swiper滑动回调事件,保存当前swiper的index值,每次滑动都会将index值保存在swiperPage变量中
            swiperChange (e) {
                this.swiperPage = e.index;
            }
        }
        ```

144

[
[yang] 已提交
145
4.  设置一个城市的空气质量信息为一屏,在一屏内,要展示多种信息,分别使用不同的控件进行展示。
W
wenjun 已提交
146

[
[yang] 已提交
147
    在swiper中添加两个子组件stack(绝对布局),每个stack组件内分别添加text、image、progress等组件来显示对应的信息 ,页面结构如下:
W
wenjun 已提交
148 149

    ```
[
[yang] 已提交
150
     <swiper class="swiper" index="{{swiperPage}}" duration="500" onchange="swiperChange">
W
wenjun 已提交
151
        <!--第一屏-->
[
[yang] 已提交
152
        <stack class="swiper">
W
wenjun 已提交
153
            <text></text>------空气质量
[
[yang] 已提交
154
            <text></text>------城市名称
W
wenjun 已提交
155 156 157 158
            <progress></progress>-----进度条
            <image></image>-------云朵图片
            <text></text>--------AQI数值
            <text>AQI</text>------AQI
[
[yang] 已提交
159 160 161 162
            <div>--------空气指标详细信息
            </div>
            <div>--------更新时间和网站等信息
            </div>
W
wenjun 已提交
163 164 165 166 167 168 169 170 171
        </stack>
        <!--第二屏-->
        <stack class="container">
            <text></text>
            <text></text>
            <progress></progress>
            <image></image>
            <text></text>
            <text></text>
[
[yang] 已提交
172
            <div></div>    
W
wenjun 已提交
173 174 175 176
        </stack>
    </swiper>
    ```

[
[yang] 已提交
177 178 179
    代码编写完成后,模拟器运行效果如下:

    **图 2**  标题栏和信息栏效果<a name="fig177003454238"></a>  
D
duangavin123 已提交
180
    ![](figure/标题栏和信息栏效果.png "标题栏和信息栏效果")
[
[yang] 已提交
181 182 183 184 185 186 187 188 189 190 191

5.  添加页面位置指示器:由于当前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>
    ```

    **图 3**  页面位置指示器效果图<a name="fig767374119496"></a>  
D
duangavin123 已提交
192
    ![](figure/页面位置指示器效果图.png "页面位置指示器效果图")
[
[yang] 已提交
193 194

6.  所有组件设置样式、动画效果和数据动态绑定,完整代码如下所示:
W
wenjun 已提交
195 196 197 198

    -   **index.hml文件**

    ```
[
[yang] 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    <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>
W
wenjun 已提交
343 344 345 346
    ```

    -   **index.css文件**

[
[yang] 已提交
347 348
    css文件中定义了许多class,每个class用于定义组件的位置、大小、字体、颜色、背景色等信息。同时,每一个子组件都叠加在父组件中,父组件的样式会影响子组件的呈现。

W
wenjun 已提交
349
    ```
[
[yang] 已提交
350
    .aqi-value {
N
NEEN 已提交
351
        text-align: center;
[
[yang] 已提交
352
        font-size: 65px;
N
NEEN 已提交
353
        color: #f0ffff;
[
[yang] 已提交
354 355 356 357
        width: 156px;
        height: 92px;
        top: 134px;
        left: 210px;
W
wenjun 已提交
358
    }
[
[yang] 已提交
359
    .aqi {
N
NEEN 已提交
360 361
        text-align: center;
        color: #a2c4a2;
[
[yang] 已提交
362 363 364 365
        width: 156px;
        height: 45px;
        top: 90px;
        left: 210px;
W
wenjun 已提交
366
    }
[
[yang] 已提交
367 368
    .airquality {
        top: 222px;
N
NEEN 已提交
369
        text-align: center;
[
[yang] 已提交
370 371 372 373 374 375 376 377 378
        width: 156px;
        height: 45px;
        left: 210px;
    }
    .image {
        top: 285px;
        left: 274px;
        width: 32px;
        height: 32px;
W
wenjun 已提交
379
    }
[
[yang] 已提交
380 381 382 383 384 385 386 387
    .location-text {
        text-align: center;
        color: #ffffff;
        width: 200px;
        height: 52px;
        font-size: 40px;
        left: 380px;
        top: 16px;
W
wenjun 已提交
388
    }
[
[yang] 已提交
389 390 391 392 393 394 395 396 397
    .container {
        flex-direction: column;
        height: 480px;
        width: 960px;
    }
    .circle-progress {
        center-x: 128px;
        center-y: 128px;
        radius: 128px;
N
NEEN 已提交
398 399
        startAngle: 198;
        totalAngle: 320;
[
[yang] 已提交
400 401 402 403 404
        strokeWidth: 24px;
        width: 256px;
        height: 256px;
        left: 160px;
        top: 58px;
W
wenjun 已提交
405
    }
[
[yang] 已提交
406 407 408 409 410 411
    .detail {
        width: 256px;
        height: 265px;
        left: 544px;
        top: 58px;
        flex-direction: column;
W
wenjun 已提交
412
    }
[
[yang] 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
    .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;
N
NEEN 已提交
453
        height: 40px;
[
[yang] 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
        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;
W
wenjun 已提交
486 487 488 489 490
    }
    ```

    -   **index.js:**

[
[yang] 已提交
491
    js文件主要用于实现App应用的逻辑交互。在本页面js文件中,需要实现如下功能:根据数值动态改变文字、进度条颜色、页面跳转。
W
wenjun 已提交
492 493

    ```
[
[yang] 已提交
494 495 496 497
    //导入router和app模块
    import router from '@system.router'
    import app from '@system.app'
    
W
wenjun 已提交
498 499
    export default {
        data: {
[
[yang] 已提交
500
          //页面绑定数据
N
NEEN 已提交
501 502 503 504 505
          textColor1: '#00ff00',
          textColor2: '#00ff00',
          bgColor1: '#669966',
          bgColor2: '#669966',
          swiperPage: 0,
[
[yang] 已提交
506 507 508 509 510
          percent1: 40,
          percent2: 90,
          iconUncheckedColor: '#262626',
          iconcheckedColor: '#ffffff',
          iconcheckedBR: '6px',
N
NEEN 已提交
511 512
          src1: 'common/cloud_green.png',
          src2: 'common/cloud_green.png',
W
wenjun 已提交
513
          airData: [{
[
[yang] 已提交
514 515 516
            location: '东莞',
            airQuality: '良',
            detailData: 40
W
wenjun 已提交
517
          }, {
[
[yang] 已提交
518 519
            location: '深圳',
            airQuality: '差',
N
NEEN 已提交
520
            detailData: 90
W
wenjun 已提交
521 522 523
          }]
        },
        onInit () {
[
[yang] 已提交
524 525 526 527 528 529 530 531 532
          //根据数值的不同,设置不同的字体、背景颜色和图片
          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';
W
wenjun 已提交
533
          }
[
[yang] 已提交
534 535 536 537 538 539 540 541
          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';
W
wenjun 已提交
542
          }
[
[yang] 已提交
543 544 545 546 547 548 549 550
          if(this.selectedCityIndex){
            this.swiperPage = this.selectedCityIndex;
            if(this.swiperPage == 0){
              this.iconcheckedColor = '#ffffff';
              this.iconUncheckedColor = '#262626';
            }else{
              this.iconcheckedColor = '#262626';
              this.iconUncheckedColor = '#ffffff';
W
wenjun 已提交
551
            }
[
[yang] 已提交
552
          }
W
wenjun 已提交
553
        },
[
[yang] 已提交
554
        //跳转到详情页面
W
wenjun 已提交
555 556
        openDetail () {
          router.replace({
N
NEEN 已提交
557 558
            uri: 'pages/detail/detail',
            params: {selectedCityIndex:this.swiperPage}
W
wenjun 已提交
559 560
          });
        },
[
[yang] 已提交
561 562 563 564 565 566 567
        //退出应用
        exitApp(){
          console.log('start exit');
          app.terminate();
          console.log('end exit');
        },
        //页面滑动事件,滑动时改变最新的标识
W
wenjun 已提交
568
        swiperChange (e) {
[
[yang] 已提交
569 570 571 572 573 574 575 576
          this.swiperPage = e.index;
          if(e.index == 0){
            this.iconcheckedColor = '#ffffff';
            this.iconUncheckedColor = '#262626';
          }else{
            this.iconcheckedColor = '#262626';
            this.iconUncheckedColor = '#ffffff';
          }
W
wenjun 已提交
577 578 579 580 581
        }
    }
    ```