【HarmonyOS NEXT星河版开发实战】天气查询APP

目录

前言

界面效果展示

首页

添加和删除 

界面构建讲解

1. 获取所需数据

 2. 在编译器中准备数据

 3. index页面代码讲解

  3.1 导入模块:

 3.2 定义组件:

3.3 定义状态变量:

3.4  定义Tabs控制器:

3.5 定义按钮样式:

 3.6 页面显示时触发的方法:

 3.7 获取数据的方法:

3.8  初始化数据的方法:

 3.9 构建UI:

4. AddCity页面代码讲解

   4.1 导入模块:

   4.2 定义组件:

   4.3 定义状态变量:

   4.4 接受数据的载体:

   4.5 页面显示时触发的方法:

   4.6 构建UI:

 5. getWeather页面代码讲解

  5.1 导入模块:

  5.2 定义类:

  5.3 定义方法 getWeather:

  5.4 定义方法 getWeathers:

  5.5 实例化并导出类:

全套源代码展示

AddCity 

Index

getWeather

casts

cityView

forecasts

WeatherModel


 

个人主页→VON

收录专栏→鸿蒙综合案例开发​​​​​

代码及其图片资源会发布于gitee上面(已发布)

gitee地址icon-default.png?t=N7T8https://gitee.com/wang-xin-jie234/harmony-os

 

​ 

前言

基础部分如今已经学完,可能有些东西并不是太了解,在练习实战项目的过程中也是一个不断学习的过程,因为实战项目复杂代码量较大,所以写的时候要及其认真,一个小的错误可能会花费几小时的时间去寻找bug。所以在学习的过程中要十分严谨,希望大家可以跟着我的思路独自完成天气查询app这一项目。

界面效果展示

首页

 首页包括添加删除天气的功能,还有近五天天气的展示,以及温度的展示。

添加和删除 

 

添加城市列表是本地进行导入的,如果有需要可以将想要的城市自行导入进去,添加完城市点击完成会跳转到首页进行渲染展示。删除功能,点击确定的时候改城市的信息会被删除。 

界面构建讲解

1. 获取所需数据

因为天气的数据需要我们联网去获取,所以要去调用天气的API。

我这里用的是高德开放平台,没有注册过的要先进行账号的注册。

注:必须要进行账号注册,后面要用到我们个人的Key值,每个用户都不一样。 

拿到key之后在浏览器上输入服务示例+key+extensions=all 

 2. 在编译器中准备数据

​ 

 3. index页面代码讲解

  3.1 导入模块

import getweatherutil from '../util/getWeather'
import { cityView } from '../view/cityView'
import {WeatherModel} from '../view/WeatherModel'
import router from '@ohos.router'

 3.2 定义组件

@Entry
@Component
struct Index {

3.3 定义状态变量:

// 城市代码集合
@State cityCoeList: number[] = [110000, 120000]
// 城市名字集合
@State cityNameList: string[] = []
// 城市信息集合
@State cityWeatherList: Array<WeatherModel> = []
// 当前城市索引
@State cityIndex: number = 0

3.4  定义Tabs控制器:

tabController: TabsController = new TabsController()

3.5 定义按钮样式

@Builder tabBuild(index: number) {
  Circle({ width: 10, height: 10 })
    .fill(this.cityIndex === index ? Color.White : Color.Gray).opacity(0.4)
}

 3.6 页面显示时触发的方法

onPageShow() {
  let params = router.getParams()
  if (params !== null) {
    this.cityCoeList = params['codes']
    // 清空所有数据
    this.cityWeatherList = []
    this.cityNameList = []
    this.initDate()
  }
}

 3.7 获取数据的方法

aboutToAppear() {
  this.initDate()
}

3.8  初始化数据的方法

async initDate() {
  let result: Array<WeatherModel> = await getweatherutil.getWeathers(this.cityCoeList)
  for (let i = 0; i < result.length; i++) {
    // 城市天气
    let ACityWeather = new WeatherModel()
    ACityWeather = result[i]
    this.cityWeatherList.push(ACityWeather)
    // 城市名称
    let cityname = result[i].forecasts[0].city
    this.cityNameList.push(cityname)
  }
}

 3.9 构建UI

build() {
  Column() {
    Row() {
      Button('添加')
        .fontSize(25)
        .fontColor(Color.Gray)
        .backgroundColor('#00ffffff')
        .onClick(() => {
          router.pushUrl({
            url: "pages/AddCity",
            params: {
              codes: this.cityCoeList,
              names: this.cityNameList
            }
          })
        })
      Text(this.cityNameList[this.cityIndex]).fontSize(40).fontColor(Color.Orange)
      Button('删除')
        .fontSize(25)
        .fontColor(Color.Gray)
        .backgroundColor('#00ffffff')
        .onClick(() => {
          AlertDialog.show({
            title: '删除',
            message: `你确定要删除${this.cityNameList[this.cityIndex]}吗?`,
            confirm: {
              value: '确定',
              action: () => {
                this.cityNameList = this.cityNameList.filter(item => item !== this.cityNameList[this.cityIndex])
                this.cityCoeList = this.cityCoeList.filter(item => item !== this.cityCoeList[this.cityIndex])
                this.cityWeatherList = this.cityWeatherList.filter(item => item !== this.cityWeatherList[this.cityIndex])
              }
            }
          })
        })
    }
    .width('100%')
    .height('10%')
    .justifyContent(FlexAlign.SpaceBetween)

    Tabs({ barPosition: BarPosition.Start, controller: this.tabController }) {
      ForEach(this.cityWeatherList, (cityWeather: WeatherModel) => {
        TabContent() {
          cityView({ casts: cityWeather.forecasts[0].casts })
        }
        .tabBar(this.tabBuild(this.cityWeatherList.findIndex((obj => obj === cityWeather))))
      })
    }
    .barWidth(40)
    .barHeight(40)
    .onChange((index: number) => {
      this.cityIndex = index
    })
  }
  .width('100%')
  .height('100%')
  .backgroundImage($r('app.media.weather_background'))
  .backgroundImageSize({ width: '100%', height: '100%' })
  .backgroundImagePosition({ x: 0, y: 0 })
}

4. AddCity页面代码讲解

   4.1 导入模块

import router from '@ohos.router'

   4.2 定义组件

@Entry
@Component
struct AddCity {

   4.3 定义状态变量

// 所有城市的代码列表
@State AllCityCodeList: Array<number> = [
  410100, 410200, 410300, 410400, 410500, 410600, 410700, 410800, 410900, 411000, 411200, 411300, 411400, 411500, 411600, 411700
]
// 所有城市的名称列表
@State AllCityNameList: Array<string> = [
  '郑州市', '开封市', '洛阳市', '平顶山市', '安阳市', '鹤壁市', '新乡市', '焦作市', '濮阳市', '许昌市', '三门峡市', '南阳市', '商丘市', '信阳市', '周口市', '驻马店市'
]

   4.4 接受数据的载体

@State cityCodeList: number[] = []
@State cityNameList: string[] = []

   4.5 页面显示时触发的方法

onPageShow() {
  let param = router.getParams()
  this.cityCodeList = param['codes']
  this.cityNameList = param['names']
}

   4.6 构建UI

build() {
  Column() {
    Row() {
      Text('添加城市列表')
        .fontSize(35)
        .fontColor(Color.White)
      Blank()
      Button('完成')
        .fontSize(26)
        .backgroundColor("")
        .onClick(() => {
          router.back({
            url: 'pages/Index',
            params: {
              codes: this.cityCodeList,
              names: this.AllCityNameList
            }
          })
        })
    }
    .height('10%')
    .width('95%')
    Column() {
      List() {
        ForEach(this.AllCityNameList, (name: string) => {
          ListItem() {
            if (this.cityNameList.includes(name)) {
              Column() {
                Row() {
                  Text(name)
                    .fontSize(35)
                    .fontColor(Color.White)
                    .width('60%')
                    .margin({ top: 20, left: 30 })
                  Blank()
                  Text('已添加')
                    .backgroundColor('')
                    .fontSize(18)
                    .margin({ top: 5 }).opacity(0.8)
                }.width('100%')
                Blank()
                Divider().strokeWidth(5)
              }
              .height(90)
              .width('100%')
              .margin({ top: 20 })
              .backgroundColor('#ff4a93c6')
            } else {
              Column() {
                Row() {
                  Text(name)
                    .fontSize(35)
                    .fontColor(Color.White)
                    .width('60%')
                    .margin({ top: 20, left: 30 })
                  Blank()
                  Button('添加')
                    .margin({ right: 5 })
                    .backgroundColor("")
                    .onClick(() => {
                      // 根据name来获取索引
                      let index = this.AllCityNameList.findIndex(obj => obj === name)
                      // 根据索引获取城市编码
                      let cityCode: number = this.AllCityCodeList[index]
                      // 将城市编码加入列表
                      this.cityCodeList.push(cityCode)
                      this.cityNameList.push(name)
                    })
                }.width('100%')
                Blank()
                Divider().strokeWidth(5)
              }
              .height(90)
              .width('100%')
              .margin({ top: 20 })
            }
          }
        })
      }
    }
  }
  .width('100%')
  .height('100%')
  .backgroundImage($r('app.media.weather_background'))
  .backgroundImageSize({ width: '100%', height: '100%' })
  .backgroundImagePosition({ x: 0, y: 0 })
}

 5. getWeather页面代码讲解

  5.1 导入模块

import { WeatherModel } from '../view/WeatherModel'
import http from '@ohos.net.http'

  5.2 定义类

class getWeatherUtil {

  5.3 定义方法 getWeather

// 发送一个url,返回对应的数据
getWeather(cityCode: number): Promise<WeatherModel> {
  return new Promise<WeatherModel>((resolve, reject) => {
    let request = http.createHttp()
    let url = `https://restapi.amap.com/v3/weather/weatherInfo?city=${cityCode}&key=57b5118aed53d7a188874fc44256a0b8&extensions=all`
    let result = request.request(url)

    result.then((res) => {
      if (res.responseCode === 200) {
        console.log(res.result.toString());
        resolve(JSON.parse(res.result.toString()))
      }
    }).catch((err) => {
      console.log(err)
      reject(err)
    })
  })
}

  5.4 定义方法 getWeathers

// 直接发送多个url结果一并返回
async getWeathers(cityCodes: Array<number>): Promise<Array<WeatherModel>> {
  let promises: Array<Promise<WeatherModel>> = []
  let weatherModels: Array<WeatherModel> = []
  for (let i = 0; i < cityCodes.length; i++) {
    promises.push(this.getWeather(cityCodes[i]))
  }

  await Promise.all(promises).then(result => {
    for (const element of result) {
      console.log(element.forecasts[0].city)
    }
    weatherModels = result
  }).catch((err) => {
    console.log(err)
  })
  return weatherModels
}

  5.5 实例化并导出类

let getweatherutil = new getWeatherUtil()
export default getweatherutil as getWeatherUtil

 getWeather  方法

  • 该方法接受一个城市代码 cityCode,并返回一个 Promise<WeatherModel>
  • 创建一个 HTTP 请求对象 request
  • 构建请求 URL,包含城市代码和 API 密钥。
  • 发送 HTTP 请求并处理响应。
  • 如果响应码为 200,解析响应结果并返回 WeatherModel 对象。
  • 如果发生错误,捕获并记录错误。

 getWeat hers 方法

  • 该方法接受一个城市代码数组 cityCodes,并返回一个 Promise<Array<WeatherModel>>
  • 创建一个空数组 promises 用于存储每个城市天气请求的 Promise。
  • 遍历 cityCodes,为每个城市代码调用 getWeather 方法,并将返回的 Promise 添加到 promises 数组中。
  • 使用 Promise.all 等待所有请求完成,并处理结果。
  • 遍历结果数组,记录每个城市的名称。
  • 将结果赋值给 weatherModels 数组并返回。
  • 如果发生错误,捕获并记录错误。

全套源代码展示

AddCity 

import router from '@ohos.router'

@Entry
@Component
struct AddCity {

  @State AllCityCodeList:Array<number>=
    [410100,410200,410300,410400,410500,410600,410700,410800,410900,411000,411200,411300,411400,411500,411600,411700]
  @State AllCityNameList:Array<string>=
    ['郑州市','开封市','洛阳市','平顶山市','安阳市','鹤壁市','新乡市','焦作市','濮阳市','许昌市','三门峡市','南阳市','商丘市','信阳市','周口市','驻马店市']

  // 接受数据的载体
  @State cityCodeList:number[]=[]
  @State cityNameList:string[]=[]

  onPageShow(){
    let param=router.getParams()
    this.cityCodeList=param['codes']
    this.cityNameList=param['names']
  }

  build() {
    Column(){
      Row(){
        Text('添加城市列表')
          .fontSize(35)
          .fontColor(Color.White)
        Blank()
        Button('完成')
          .fontSize(26)
          .backgroundColor("")
          .onClick(()=>{
            router.back({
              url:'pages/Index',
              params:{
                codes:this.cityCodeList,
                names:this.AllCityNameList
              }
            })
          })
      }
      .height('10%')
      .width('95%')
      Column(){
        List(){
          ForEach(this.AllCityNameList,(name:string)=>{
            ListItem(){
              if(this.cityNameList.includes(name)){
                Column(){
                  Row(){
                    Text(name)
                      .fontSize(35)
                      .fontColor(Color.White)
                      .width('60%')
                      .margin({top:20,left:30})
                    Blank()
                    Text('已添加')
                      .backgroundColor('')
                      .fontSize(18)
                      .margin({top:5}).opacity(0.8)
                  }.width('100%')
                  Blank()
                  Divider().strokeWidth(5)
                }
                .height(90)
                .width('100%')
                .margin({top:20})
                .backgroundColor('#ff4a93c6')
              }else{
                Column(){
                  Row(){
                    Text(name)
                      .fontSize(35)
                      .fontColor(Color.White)
                      .width('60%')
                      .margin({top:20,left:30})
                    Blank()
                    Button('添加')
                      .margin({right:5})
                      .backgroundColor("")
                      .onClick(()=>{
                        // 根据name来获取索引
                        let index=this.AllCityNameList.findIndex(obj=>obj===name)
                        // 根据索引获取城市编码
                        let cityCode:number=this.AllCityCodeList[index]
                        // 将城市编码加入列表
                        this.cityCodeList.push(cityCode)
                        this.cityNameList.push(name)
                      })
                  }.width('100%')
                  Blank()
                  Divider().strokeWidth(5)
                }
                .height(90)
                .width('100%')
                .margin({top:20})
              }
            }
          })
        }
      }
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.weather_background'))
    .backgroundImageSize({width:'100%',height:'100%'})
    .backgroundImagePosition({x:0,y:0})
  }
}

Index

import getweatherutil from '../util/getWeather'
import { cityView } from '../view/cityView'
import {WeatherModel} from '../view/WeatherModel'
import router from '@ohos.router'

@Entry
@Component
struct Index {
  // 城市代码集合
  @State cityCoeList:number[] =[110000,120000]
  // 城市名字集合
  @State cityNameList:string[]=[]
  // 城市信息集合
  @State cityWeatherList:Array<WeatherModel>=[]
  // 当前城市索引
  @State cityIndex:number=0

  tabController:TabsController=new TabsController()

  // 按钮样式
  @Builder tabBuild(index:number){
    Circle({width:10,height:10})
      .fill(this.cityIndex===index?Color.White:Color.Gray).opacity(0.4)
  }

  onPageShow(){
    let params=router.getParams()
    if(params!==null){
      this.cityCoeList=params['codes']
      // 清空所有数据
      this.cityWeatherList=[]
      this.cityNameList=[]
      this.initDate()
    }
  }

  // 获取数据
  aboutToAppear(){
    this.initDate()
  }

  // 初始化方法
  async initDate(){
    let result:Array<WeatherModel> =await getweatherutil.getWeathers(this.cityCoeList)
    for (let i = 0; i < result.length; i++) {
      // 城市天气
      let ACityWeather=new WeatherModel()
      ACityWeather=result[i]
      this.cityWeatherList.push(ACityWeather)
      // 城市名称
      let cityname=result[i].forecasts[0].city
      this.cityNameList.push(cityname)
    }
  }

  build() {
    Column(){
      Row(){
        Button('添加')
          .fontSize(25)
          .fontColor(Color.Gray)
          .backgroundColor('#00ffffff')
          .onClick(()=>{
            router.pushUrl({
              url:"pages/AddCity",
              params:{
                codes:this.cityCoeList,
                names:this.cityNameList
              }
            })
          })
        Text(this.cityNameList[this.cityIndex]).fontSize(40).fontColor(Color.Orange)
        Button('删除')
          .fontSize(25)
          .fontColor(Color.Gray)
          .backgroundColor('#00ffffff')
          .onClick(()=>{
            AlertDialog.show({
              title:'删除',
              message:`你确定要删除${this.cityNameList[this.cityIndex]}吗?`,
              confirm:{
                value:'确定',
                action:()=>{
                  this.cityNameList=this.cityNameList.filter(item=>item!==this.cityNameList[this.cityIndex])
                  this.cityCoeList=this.cityCoeList.filter(item=>item!==this.cityCoeList[this.cityIndex])
                  this.cityWeatherList=this.cityWeatherList.filter(item=>item!==this.cityWeatherList[this.cityIndex])
                }
              }
            })
          })
      }
      .width('100%')
      .height('10%')
      .justifyContent(FlexAlign.SpaceBetween)

      Tabs({barPosition:BarPosition.Start,controller:this.tabController}){
        ForEach(this.cityWeatherList,(cityWeather:WeatherModel)=>{
          TabContent(){
            cityView({casts:cityWeather.forecasts[0].casts})
          }
          .tabBar(this.tabBuild(this.cityWeatherList.findIndex((obj=>obj===cityWeather))))
        })
      }
      .barWidth(40)
      .barHeight(40)
      .onChange((index:number)=>{
        this.cityIndex=index
      })
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.weather_background'))
    .backgroundImageSize({width:'100%',height:'100%'})
    .backgroundImagePosition({x:0,y:0})

  }
}

getWeather

import {WeatherModel} from '../view/WeatherModel'
import http from '@ohos.net.http'

class getWeatherUtil{
  // 发送一个url,返回对应的数据
  getWeather(cityCode:number){
    return new Promise<WeatherModel>((resolve,reject)=>{
      let request=http.createHttp()
      let url=`https://restapi.amap.com/v3/weather/weatherInfo?city=${cityCode}&key=57b5118aed53d7a188874fc44256a0b8&extensions=all`
      let result=request.request(url)

      result.then((res)=>{
        if(res.responseCode===200){
          console.log(res.result.toString());
          resolve(JSON.parse(res.result.toString()))
        }
      }).catch((err)=>{
        console.log(err)
      })
    })
  }

  // 直接发送多个url结果一并返回
  async getWeathers(cityCodes:Array<number>){
    let promises:Array<Promise<WeatherModel>>=[]
    let weatherModels:Array<WeatherModel>=[]
    for (let i = 0; i < cityCodes.length; i++) {
      promises.push(this.getWeather(cityCodes[i]))
    }

    await Promise.all(promises).then(result=>{
      for(const element of result){
        console.log(element.forecasts[0].city)
      }
      weatherModels=result
    })
    return weatherModels
  }
}

let getweatherutil=new getWeatherUtil()
export default getweatherutil as getWeatherUtil

casts

export class casts{
  date:string
  dayweather:string
  nightweather:string
  daytemp:number
  nighttemp:number
  daywind:string
  daypower:string
  daytemp_float:number
  nighttemp_float:number
}

cityView

import {casts} from '../view/casts'

@Component
export struct cityView {
  // 获取数据

  // 城市天气数据
  casts:Array<casts>=[]

  @Builder weartherImage(weather:string){
      if(weather==='晴'){
        Image($r('app.media.sun'))
          .width(23)
      }
      if(weather==='阴'){
        Image($r('app.media.cloudy'))
          .width(30)
      }
      if(weather==='多云'){
        Image($r('app.media.cloudy'))
          .width(30)
      }
      if(weather.includes('雨')){
        Image($r('app.media.rain'))
          .width(30)
      }
  }
  // 展示数据
  build() {
    Column(){
      // 当天天气数据
      ForEach(this.casts,(cast:casts)=>{
        if(this.casts[0]===cast){
          // 展示天气所对应图片
          Row(){
            if(cast.dayweather==='晴'){
              Image($r('app.media.sun'))
                .width(250)
            }
            if(cast.dayweather==='阴'){
              Image($r('app.media.cloudy'))
                .width(250)
            }
            if(cast.dayweather==='多云'){
              Image($r('app.media.cloudy'))
                .width(250)
            }
            if(cast.dayweather.includes('雨')){
              Image($r('app.media.rain'))
                .width(300)
            }
          }
          Column(){
            // 温度天气
            Row(){
              Text(cast.dayweather)
                .fontSize(30)
                .fontColor(Color.White)
                .fontWeight(700)
              Text("  "+cast.nighttemp+"°~"+cast.daytemp+"°")
                .fontSize(30)
                .fontColor(Color.White)
                .fontWeight(700)
            }
            Row(){
              Text(cast.daywind+"风")
                .fontSize(30)
                .fontColor(Color.White)
                .fontWeight(700)
              Text(cast.daypower+"级")
                .fontSize(30)
                .fontColor(Color.White)
                .fontWeight(700)
            }
          }
        }
      })
      // 近期天气数据
      Column(){
        Text('近期天气查询')
          .fontSize(26)
          .margin({top:30,bottom:15})
        // 天气列表
        Row(){
          ForEach(this.casts,(cast:casts)=>{
            Column(){
              Text(cast.date.substring(5))
              this.weartherImage(cast.dayweather)
              Text(cast.daytemp.toString())
              Line()
                .width(20)
                .height(80)
                .startPoint([10,0])
                .endPoint([10,70])
                .stroke(Color.Black)
                .strokeWidth(3)
                .strokeDashArray([10,3])
              this.weartherImage(cast.nightweather)
              Text(cast.nighttemp.toString())
            }
            .margin(5)
          })
        }
      }
    }
    .width('100%')
    .height('100%')
  }
}

forecasts

import {casts} from '../view/casts'

export class forecasts{
  city:string
  adcode:number
  casts:Array<casts>
}

WeatherModel

import {forecasts} from './forecasts'

export class WeatherModel{
  status:number
  count:number
  infocode:number
  forecasts:Array<forecasts>=[]
}
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值