[中工开发者]鸿蒙项目开发——幸运气候app的实现

打印 上一主题 下一主题

主题 945|帖子 945|积分 2835

“本学期学习了鸿蒙开发课程,想通过一个小项目检验一下自己所学,下面把该项目总结一下,希望对学习鸿蒙开发的小伙伴提供一些参考。”
如:“学习鸿蒙正其时,作为中工的一名学生,现在总结一下希望为同砚们后续学习提供参考。”


一.功能实现总结

这个鸿蒙气候应用通过直观的界面设计,整合多种功能,为用户提供全面的气候服务。以下是具体实现的功能细节:
1. 及时气候信息展示



  • 当前位置:应用通过定位功能,表现用户所在位置(如“河南省·临颍”),提供本地化的气候预报。
  • 当前气候状态

    • 及时温度(如 5°C),以夺目标大字体表现。
    • 当前气候状态(如“雾”)及当天的最高温度和最低温度(如 8°C / 1°C)。

  • 氛围质量指数:例如表现氛围状态为“轻度污染”,提示用户氛围质量状态。
  • 降水环境:如“暂无降水”,表现短时间内无雨雪气候。
2. 短期气候预报



  • 提供将来几天(如3天)的气候信息,包括:

    • 天天的气候状态(如晴、雾)。
    • 温度范围(最高温度/最低温度,如8°C / 1°C)。
    • 氛围质量等级(如“优”)。

  • 配合简便的气候图标,让用户快速把握将来气候厘革趋势。
3. 24小时气候猜测



  • 针对当日气候,提供逐小时的温度、湿度、风速、降水概率等数据,帮助用户更精准地规划活动。
4. 高级景象信息



  • 湿度:及时湿度值(如96%)。
  • 体感温度:表现比实际温度更靠近人体感知的温度。
  • 紫外线强度:如“1级”,提示日晒强度适中。
  • 气压:提供及时气压值(如1017 hPa),供需要更精细景象信息的用户参考。
  • 风速与风向:如“南风1级”,通过图形化展示风的方向与强度。
5. 长期气候预报



  • 提供一个“查看近7天气候”的按钮,支持更具体的长期气候查询,便于用户提前做好预备。

界面设计与用户体验


  • 简便高效

    • 使用极简风格,重点信息(如温度、气候状态)以大字体和夺目标结构突出,信息分类清晰。
    • 图标搭配文字,便于快速理解气候状态。

  • 高交互性

    • 通过按钮设计(如“查看近7天气候”),引导用户探索更多功能。
    • 多屏信息整合,及时数据与短期预报联合,满足多样化需求。

  • 贴心功能

    • 氛围质量、湿度、紫外线等指标提供全面的数据参考,覆盖多种使用场景,如穿衣、出行等。


适用场景



  • 一样平常出行:查看及时气候、氛围质量和降水信息,便于出行安排。
  • 活动计划:通过短期或长期气候预报规划外出活动。
  • 康健防护:参考湿度、紫外线强度和氛围质量,及时做好防护措施。
二. 告急代码实现

 1. 告急页面项目代码展示




实现代码项目截图
  1. import log from '../../common/log'
  2. import { promptAction } from '@kit.ArkUI'
  3. import {
  4.     ForecastWeatherDayResult,
  5.     ForecastWeatherHourResult,
  6.     NowAirResult,
  7.     RealWeatherResult
  8. } from '../../network/type'
  9. import { distributedKVStore } from '@kit.ArkData'
  10. import {
  11.     checkDataValidate,
  12.     fetchAndCachedForecast24HourWeather,
  13.     fetchAndCachedForecast7DayWeather,
  14.     fetchAndCachedNowAirData,
  15.     fetchAndCachedRealWeatherData,
  16.     getWeatherKvStore
  17. } from '../../utils/WeatherKvStore'
  18. import * as constants from '../../common/constants'
  19. import { RealTemperature } from './RealTemperature'
  20. import { Fetch3dayWeather } from './Fetch3dayWeather'
  21. import { DayTrendPageNavParam } from '../DayTrend/DayTrendPage'
  22. import { Forecast24HourWetherComponent } from './Forecast24Hour/Forecast24HourWeather'
  23. import { RealTimeWeather } from './RealTimeWeather'
  24. import { BusinessError } from '@kit.BasicServicesKit'
  25. export interface CityWeatherOptions {
  26.     location: string,
  27. }
  28. interface RealTemperatureVO {
  29.     curTemp: number
  30.     weatherDesc: string
  31.     airQualityIndex: number
  32.     airQualityDesc: string,
  33.     rain: number,
  34.     highestTemp: number,
  35.     lowestTemp: number,
  36. }
  37. function transformRealTemperatureVO(
  38.     realWeatherData: RealWeatherResult,
  39.     airData: NowAirResult,
  40.     forecastData: ForecastWeatherDayResult
  41. ) {
  42.     const vo: RealTemperatureVO = {
  43.         curTemp: parseInt(realWeatherData.now.temp),
  44.         weatherDesc: realWeatherData.now.text,
  45.         airQualityIndex: parseInt(airData.now.aqi),
  46.         airQualityDesc: airData.now.category,
  47.         rain: parseFloat(realWeatherData.now.precip),
  48.         highestTemp: parseInt(forecastData.daily[0].tempMax),
  49.         lowestTemp: parseInt(forecastData.daily[0].tempMin),
  50.     }
  51.     return vo
  52. }
  53. /**
  54. * 城市天气的主要组件
  55. * 主要逻辑:
  56. * 1. 从本地缓存中获取历史数据,使用该数据,如果超过过期时间,进行更新~
  57. * 2. 下拉刷新操作
  58. * */
  59. @Component
  60. export struct CityWeather {
  61.     @Consume("pageStack") pathStack: NavPathStack
  62.     @Prop options: CityWeatherOptions
  63.     /** 刷新状态 */
  64.     @State
  65.     private refreshing: boolean = false
  66.     /** 当前刷新完成数 */
  67.     @State
  68.     private refreshingCounter: number = 0
  69.     @State
  70.     private refreshingText: string = '刷新中...'
  71.     private kvStore?: distributedKVStore.DeviceKVStore = undefined
  72.     /** 实时天气数据 */
  73.     @State
  74.     @Watch('updateRealTemperatureVOData')
  75.     private realWeatherData?: RealWeatherResult = undefined
  76.     /** 7天预测数据 */
  77.     @State
  78.     @Watch('updateRealTemperatureVOData')
  79.     private forecastDayWeatherData?: ForecastWeatherDayResult = undefined
  80.     /** 24小时预测数据 */
  81.     @State
  82.     private forecastHourWeatherData?: ForecastWeatherHourResult = undefined
  83.     /** 空气数据 */
  84.     @State
  85.     @Watch('updateRealTemperatureVOData')
  86.     private airQualityData?: NowAirResult = undefined
  87.     /** 实时天气数据VO */
  88.     @State
  89.     private realTemperatureVOData?: RealTemperatureVO = undefined
  90.     private updateRealTemperatureVOData(pro: string) {
  91.         if (pro === 'realWeatherData' || pro === 'forecastDayWeatherData' || pro === 'airQualityData') {
  92.             if (this.realWeatherData && this.forecastDayWeatherData && this.airQualityData) {
  93.                 this.realTemperatureVOData = transformRealTemperatureVO(this.realWeatherData, this.airQualityData, this.forecastDayWeatherData)
  94.             }
  95.         }
  96.     }
  97.     /**
  98.      * 开始刷新操作
  99.      * */
  100.     private startRefreshing() {
  101.         this.refreshing = true
  102.         this.refreshingCounter++
  103.         this.refreshingText = "刷新中..."
  104.     }
  105.     /**
  106.      * 刷新完毕操作
  107.      * */
  108.     private completedRefreshing() {
  109.         this.refreshingCounter--;
  110.         if (this.refreshingCounter === 0) {
  111.             this.refreshingText = "刷新成功!"
  112.             setTimeout(() => {
  113.                 this.refreshing = false
  114.             }, 500)
  115.         }
  116.     }
  117.     /**
  118.      * 刷新实时天气数据(实时温度、空气数据、7天数据)
  119.      * */
  120.     private async fetchAndCachedRealWeatherData() {
  121.         this.startRefreshing()
  122.         try {
  123.             this.realWeatherData = await fetchAndCachedRealWeatherData(this.options.location, this.kvStore!)
  124.             this.airQualityData = await fetchAndCachedNowAirData(this.options.location, this.kvStore!)
  125.             this.forecastDayWeatherData = await fetchAndCachedForecast7DayWeather(this.options.location, this.kvStore!)
  126.             // 更新状态变量
  127.             this.realTemperatureVOData =
  128.                 transformRealTemperatureVO(this.realWeatherData, this.airQualityData, this.forecastDayWeatherData)
  129.         } catch (error) {
  130.             promptAction.showToast({
  131.                 message: '网络错误!请重新刷新!'
  132.             })
  133.             log.error('fetchRealWeatherData', error)
  134.         } finally {
  135.             this.completedRefreshing()
  136.         }
  137.     }
  138.     private fetchAndCachedRealAirData() {
  139.         console.log('fetchAndCachedRealAirData kv store', this.kvStore)
  140.         this.startRefreshing()
  141.         fetchAndCachedNowAirData(this.options!.location, this.kvStore!)
  142.             .then((res) => {
  143.                 this.airQualityData = res
  144.             })
  145.             .catch((err: Error) => {
  146.                 log.error('fetchAndCachedAirData Failed!', JSON.stringify(err))
  147.                 promptAction.showToast({
  148.                     message: '获取数据失败,请检查网络!'
  149.                 })
  150.             })
  151.             .finally(() => {
  152.                 this.completedRefreshing()
  153.             })
  154.     }
  155.     /**
  156.      * 获取未来7天的数据
  157.      * */
  158.     private fetchAndCachedForecastDayWeatherData() {
  159.         this.startRefreshing()
  160.         fetchAndCachedForecast7DayWeather(this.options!.location, this.kvStore!)
  161.             .then((res) => {
  162.                 this.forecastDayWeatherData = res
  163.             })
  164.             .catch((err: Error) => {
  165.                 log.error("fetchForecastWeatherDayData failed", err)
  166.                 promptAction.showToast({
  167.                     message: '获取数据失败,请检查网络!'
  168.                 })
  169.             })
  170.             .finally(() => {
  171.                 this.completedRefreshing()
  172.             })
  173.     }
  174.     /**
  175.      * 获取未来24小时的数据
  176.      * */
  177.     private fetchAndCachedForecastHourWeatherData() {
  178.         this.startRefreshing()
  179.         console.log('fetchForecastHourWeatherData kv store', this.kvStore)
  180.         fetchAndCachedForecast24HourWeather(this.options!.location, this.kvStore!)
  181.             .then((res) => {
  182.                 this.forecastHourWeatherData = res
  183.             })
  184.             .catch((err: Error) => {
  185.                 log.error("fetchForecastHourWeatherData failed", err)
  186.                 promptAction.showToast({
  187.                     message: '获取数据失败,请检查网络!'
  188.                 })
  189.             })
  190.             .finally(() => {
  191.                 this.completedRefreshing()
  192.             })
  193.     }
  194.     /** 刷新所有天气数据 */
  195.     private refreshAllWeatherData() {
  196.         this.loadDataFromKvStore()
  197.     }
  198.     /**
  199.      * 从本地读取缓存的数据,如果没有或者过期,则执行刷新操作
  200.      * */
  201.     private async loadDataFromKvStore() {
  202.         // 当前实时天气
  203.         this.startRefreshing()
  204.         checkDataValidate<RealWeatherResult>(
  205.             this.kvStore!,
  206.             constants.getRealWeatherDataKey(this.options.location),
  207.             5 * 60 * 1000,
  208.         )
  209.             .then((res) => {
  210.                 console.log(`checkDataValidate<RealWeatherResult> need refresh: ${res === undefined}`)
  211.                 if (res) {
  212.                     this.realWeatherData = res
  213.                 } else {
  214.                     this.fetchAndCachedRealWeatherData()
  215.                 }
  216.             })
  217.             .catch((err: BusinessError) => {
  218.                 console.error(`checkDataValidate<RealWeatherResult> failed: (${err.code}) ${err.message}`)
  219.             })
  220.             .finally(() => {
  221.                 this.completedRefreshing()
  222.             })
  223.         // 当前空气质量数据
  224.         this.startRefreshing()
  225.         checkDataValidate<NowAirResult>(
  226.             this.kvStore!,
  227.             constants.getRealWeatherAirDataKey(this.options.location),
  228.             5 * 60 * 1000,
  229.         )
  230.             .then((res) => {
  231.                 console.log(`checkDataValidate<NowAirResult> need refresh: ${res === undefined}`)
  232.                 if (res) {
  233.                     this.airQualityData = res
  234.                 } else {
  235.                     this.fetchAndCachedRealAirData()
  236.                 }
  237.             })
  238.             .catch((err: BusinessError) => {
  239.                 console.error(`checkDataValidate<NowAirResult> failed: (${err.code}) ${err.message}`)
  240.             })
  241.             .finally(() => {
  242.                 this.completedRefreshing()
  243.             })
  244.         // 当前7天天气数据
  245.         this.startRefreshing()
  246.         checkDataValidate<ForecastWeatherDayResult>(
  247.             this.kvStore!,
  248.             constants.getForecastWeatherDayDataKey(this.options.location),
  249.             10 * 60 * 1000,
  250.         )
  251.             .then((res) => {
  252.                 console.log(`checkDataValidate<ForecastWeatherDayResult> need refresh: ${res === undefined}`)
  253.                 if (res) {
  254.                     this.forecastDayWeatherData = res
  255.                 } else {
  256.                     this.fetchAndCachedForecastDayWeatherData()
  257.                 }
  258.             })
  259.             .catch((err: BusinessError) => {
  260.                 console.error(`checkDataValidate<ForecastWeatherDayResult> failed: (${err.code}) ${err.message}`)
  261.             })
  262.             .finally(() => {
  263.                 this.completedRefreshing()
  264.             })
  265.         this.startRefreshing()
  266.         checkDataValidate<ForecastWeatherHourResult>(
  267.             this.kvStore!,
  268.             constants.getForecastWeatherHourDataKey(this.options.location),
  269.             10 * 60 * 1000,
  270.         )
  271.             .then((res) => {
  272.                 console.log(`checkDataValidate<ForecastWeatherHourResult> need refresh: ${res === undefined}`)
  273.                 if (res) {
  274.                     this.forecastHourWeatherData = res
  275.                 } else {
  276.                     this.fetchAndCachedForecastHourWeatherData()
  277.                 }
  278.             })
  279.             .catch((err: BusinessError) => {
  280.                 console.error(`checkDataValidate<ForecastWeatherHourResult> failed: (${err.code}) ${err.message}`)
  281.             })
  282.             .finally(() => {
  283.                 this.completedRefreshing()
  284.             })
  285.     }
  286.     private navigateToTrendPage() {
  287.         const data: DayTrendPageNavParam = {
  288.             shouldShowNavigation: false,
  289.             added: true,
  290.             locationID: this.options.location,
  291.             cityName: '',
  292.             data: this.forecastDayWeatherData!
  293.         }
  294.         this.pathStack.pushDestinationByName("day_trend", data, true)
  295.     }
  296.     aboutToAppear(): void {
  297.         // 获取本地数据库
  298.         getWeatherKvStore(getContext(this))
  299.             .then((store) => {
  300.                 this.kvStore = store
  301.                 this.loadDataFromKvStore()
  302.             })
  303.     }
  304.     build() {
  305.         Refresh({ refreshing: $$this.refreshing, promptText: this.refreshingText }) {
  306.             Scroll() {
  307.                 Column({ space: 24 }) {
  308.                     if (this.realTemperatureVOData) {
  309.                         Column({ space: 24 }) {
  310.                             RealTemperature({
  311.                                 options: {
  312.                                     curTemp: this.realTemperatureVOData!.curTemp,
  313.                                     weatherText: this.realTemperatureVOData!.weatherDesc,
  314.                                     highTemp: this.realTemperatureVOData!.highestTemp,
  315.                                     lowTemp: this.realTemperatureVOData!.lowestTemp,
  316.                                     rain: this.realTemperatureVOData!.rain,
  317.                                     airQualityIndex: this.realTemperatureVOData!.airQualityIndex,
  318.                                     airQualityDesc: this.realTemperatureVOData!.airQualityDesc,
  319.                                 }
  320.                             })
  321.                             Fetch3dayWeather({
  322.                                 options: {
  323.                                     dataList: this.forecastDayWeatherData!.daily,
  324.                                     onNavigate: () => {
  325.                                         this.navigateToTrendPage()
  326.                                     }
  327.                                 }
  328.                             })
  329.                         }
  330.                         .alignItems(HorizontalAlign.Center)
  331.                         .justifyContent(FlexAlign.SpaceBetween) // 保证分开两部分
  332.                         .width('100%')
  333.                         .height('100%')
  334.                         Column({ space: 24 }) {
  335.                             Forecast24HourWetherComponent({
  336.                                 dataList: this.forecastHourWeatherData?.hourly
  337.                             })
  338.                                 .height(300)
  339.                             RealTimeWeather({
  340.                                 options: {
  341.                                     sunset: this.forecastDayWeatherData!.daily[0].sunset ?? '',
  342.                                     sunrise: this.forecastDayWeatherData!.daily[0].sunrise ?? '',
  343.                                     moonrise: this.forecastDayWeatherData!.daily[0].moonrise ?? '',
  344.                                     moonset: this.forecastDayWeatherData!.daily[0].moonset ?? '',
  345.                                     uvIndex: this.forecastDayWeatherData!.daily[0].uvIndex,
  346.                                     realData: this.realWeatherData!
  347.                                 }
  348.                             })
  349.                         }
  350.                     }
  351.                 }
  352.                 .width("100%")
  353.                 .padding({ left: 16, right: 16 })
  354.             }
  355.             .height('100%')
  356.             .width('100%')
  357.             .scrollable(ScrollDirection.Vertical)
  358.             .scrollBar(BarState.Off)
  359.         }
  360.         .height('100%')
  361.         .width('100%')
  362.         .onRefreshing(() => {
  363.             this.refreshAllWeatherData()
  364.         })
  365.     }
  366. }
复制代码
这段代码实现了城市气候数据展示与交互功能的组件。通过与气候相干的 API 集成,组件能及时表现城市气候信息并支持革新操作,同时通过缓存优化了性能。
2. 告急对象创建与模块代码展示


  1. import { RealWeatherResult } from '../network/type'
  2. export const RealWeatherResultList: RealWeatherResult[] = [
  3.     {
  4.         code: '300',
  5.         /**
  6.          * 最近更新时间
  7.          * */
  8.         updateTime: new Date(),
  9.         /** 当前数据的响应式页面 */
  10.         fxLink: 'string',
  11.         now: {
  12.             /** 数据观测时间 */
  13.             obsTime: "string",
  14.             /** 温度,默认单位摄氏度 */
  15.             temp: '30',
  16.             /** 体感温度 */
  17.             feelsLike: "string",
  18.             /** 图标代码 */
  19.             icon: 'string',
  20.             /** 天气描述 */
  21.             text: 'string',
  22.             /** 风向360角 */
  23.             wind360: 'string',
  24.             /** 风向 */
  25.             windDir: 'string',
  26.             /** 风力等级 */
  27.             windScale: 'string',
  28.             /** 风速 km/h */
  29.             windSpeed: 'string',
  30.             /** 湿度 % */
  31.             humidity: 'string',
  32.             /** 当前小时累计降水量,mm */
  33.             precip: 'string',
  34.             /** 大气压强,百帕 */
  35.             pressure: 'string',
  36.             /** 能见度, km */
  37.             vis: 'string',
  38.         },
  39.         refer: {
  40.             sources: [],
  41.             license: []
  42.         }
  43.     }
复制代码
  1. export class LocationBean {
  2.     /** 城市名称 */
  3.     name: string;
  4.     /** 城市id, location要用的 */
  5.     id: string;
  6.     /** 城市经度 */
  7.     lat: string;
  8.     /** 城市纬度 */
  9.     lon: string;
  10.     /** 上级行政区划名称 */
  11.     adm2: string;
  12.     /** 所属一级形成区域 */
  13.     adm1: string;
  14.     /** 所属国家名称 */
  15.     country: string;
  16.     /** 所处时区 */
  17.     tz: string;
  18.     /** UTC事件偏移的小时数 */
  19.     utcOffset: string;
  20.     /** 是否处于夏令时,1是0否 */
  21.     isDst: string;
  22.     /** 城市属性 */
  23.     type: string;
  24.     /** 地区评分 */
  25.     rank: string;
  26.     /** 该城市的天气预报网页链接 */
  27.     fxLink: string;
  28.     constructor(
  29.         name: string,
  30.         id: string,
  31.         lat: string,
  32.         lon: string,
  33.         adm2: string,
  34.         adm1: string,
  35.         country: string,
  36.         tz: string,
  37.         utcOffset: string,
  38.         isDst: string,
  39.         type: string,
  40.         rank: string,
  41.         fxLink: string
  42.     ) {
  43.         this.name = name;
  44.         this.id = id;
  45.         this.lat = lat;
  46.         this.lon = lon;
  47.         this.adm2 = adm2;
  48.         this.adm1 = adm1;
  49.         this.country = country;
  50.         this.tz = tz;
  51.         this.utcOffset = utcOffset;
  52.         this.isDst = isDst;
  53.         this.type = type;
  54.         this.rank = rank;
  55.         this.fxLink = fxLink;
  56.     }
  57. }
复制代码
  1. export interface CityModel {
  2.     /** 城市名字 */
  3.     cityName: string,
  4.     /** id */
  5.     locationID: string,
  6.     /** 所属省份 */
  7.     provinceName: string,
  8.     /** 经度 */
  9.     longitude: number,
  10.     /** 纬度 */
  11.     latitude: number,
  12.     /** 定位城市 */
  13.     isLocationCity: boolean,
  14.     /**
  15.      * 创建时间
  16.      * */
  17.     createTimestamp: number,
  18. }
  19. export interface RealWeatherData {
  20.     /** 数据观测时间 */
  21.     obsTime: string,
  22.     /** 温度,默认单位摄氏度 */
  23.     temp: string,
  24.     /** 体感温度 */
  25.     feelsLike: string,
  26.     /** 图标代码 */
  27.     icon: string,
  28.     /** 天气描述 */
  29.     text: string,
  30.     /** 风向360角 */
  31.     wind360: string,
  32.     /** 风向 */
  33.     windDir: string,
  34.     /** 风力等级 */
  35.     windScale: string,
  36.     /** 风速 km/h */
  37.     windSpeed: string,
  38.     /** 湿度 % */
  39.     humidity: string,
  40.     /** 当前小时累计降水量,mm */
  41.     precip: string,
  42.     /** 大气压强,百帕 */
  43.     pressure: string,
  44.     /** 能见度, km */
  45.     vis: string,
  46.     /** 云量,百分比,可能为空 */
  47.     cloud?: string,
  48.     /** 露点温度,可能为空 */
  49.     dew?: string,
  50. }
复制代码
3. 气候数据的获取功能告急代码展示

  1. import { API_KEY } from '../common/config'
  2. import { request } from '../common/request'
  3. import {
  4.     ForecastWeatherDayResult,
  5.     ForecastWeatherHourResult,
  6.     LocationParam,
  7.     LocationResult,
  8.     NowAirResult,
  9.     RealWeatherResult,
  10.     WeatherIndexResult,
  11.     WeatherParam
  12. } from './type'
  13. /**
  14. * 通过经纬度查询当前城市信息
  15. * @param {string} lon 经度,十进制最多两位小数
  16. * @param {string} lat 纬度,十进制最多两位小数
  17. * */
  18. export function fetchCityByLatitudeAndLongitude(lon: number, lat: number): Promise<LocationResult> {
  19.     return request<LocationParam, LocationResult>('https://geoapi.qweather.com/v2/city/lookup', {
  20.         useBaseUrl: false,
  21.         param: {
  22.             key: API_KEY,
  23.             location: `${lon.toFixed(2)},${lat.toFixed(2)}`,
  24.             range: 'cn',
  25.             number: 20,
  26.         }
  27.     })
  28. }
  29. /**
  30. * 获取到实时天气
  31. * */
  32. export function     fetchRealWeather(
  33.     location: string,
  34. ): Promise<RealWeatherResult> {
  35.     return request<WeatherParam, RealWeatherResult>('/v7/weather/now', {
  36.         param: {
  37.             key: API_KEY,
  38.             location: location
  39.         }
  40.     })
  41. }
  42. /**
  43. * 获取未来3天天气预报
  44. * */
  45. export function fetchForecast3DayWeather(
  46.     location: string
  47. ): Promise<ForecastWeatherDayResult> {
  48.     return request<WeatherParam, ForecastWeatherDayResult>('/v7/weather/3d', {
  49.         param: {
  50.             key: API_KEY,
  51.             location: location
  52.         }
  53.     })
  54. }
  55. /**
  56. * 获取未来7天天气预报
  57. * */
  58. export function fetchForecast7DayWeather(
  59.     location: string
  60. ): Promise<ForecastWeatherDayResult> {
  61.     return request<WeatherParam, ForecastWeatherDayResult>('/v7/weather/7d', {
  62.         param: {
  63.             key: API_KEY,
  64.             location: location
  65.         }
  66.     })
  67. }
  68. /**
  69. * 获取未来24小时天气预报
  70. * */
  71. export function fetchForecast24HourWeather(
  72.     location: string
  73. ): Promise<ForecastWeatherHourResult> {
  74.     return request<WeatherParam, ForecastWeatherHourResult>('/v7/weather/24h', {
  75.         useBaseUrl: false,
  76.         param: {
  77.             key: API_KEY,
  78.             location: location
  79.         },
  80.     })
  81. }
  82. /*
  83. * 根据关键字获取城市信息
  84. * */
  85. export function fetchCityInfoByKeyWord(
  86.     keyword: string
  87. ): Promise<LocationResult> {
  88.     return request<LocationParam, LocationResult>('https://geoapi.qweather.com/v2/city/lookup', {
  89.         param: {
  90.             key: API_KEY,
  91.             location: keyword
  92.         }
  93.     })
  94. }
  95. /**
  96. * 获取空气质量数据
  97. * */
  98. export function fetchNowAir(
  99.     location: string,
  100. ): Promise<NowAirResult> {
  101.     return request<WeatherParam, NowAirResult>('/v7/air/now', {
  102.         param: {
  103.             key: API_KEY,
  104.             location: location
  105.         }
  106.     })
  107. }
  108. /**
  109. * 获取天气指数
  110. * */
  111. export function fetchWeatherIndices(
  112.     location: string,
  113. ): Promise<WeatherIndexResult> {
  114.     return request<WeatherParam, WeatherIndexResult>('/v7/indices/1d', {
  115.         param: {
  116.             key: API_KEY,
  117.             location: location
  118.         }
  119.     })
  120. }
复制代码
该代码文件是项目标核心数据交互模块,完成了:

  • 及时气候与猜测数据的获取:涵盖从当前到将来 7 天的气候数据。
  • 氛围质量与生活指数的查询:提供额外的环境和生活信息。
  • 城市定位与查询:支持自动定位和关键字搜索。
通过 API 的分层封装,代码清晰易扩展,便于后续功能升级和维护。
4. 搜索功能组件代码实现告急展示

  1. import { CityMangerModel2, CityWeatherVO } from '../../model/CityManagerModel2'
  2. import { CityModel } from '../../model/CityModel'
  3. import { fetchCityInfoByKeyWord } from '../../network/api'
  4. import { Location, LocationResult } from '../../network/type'
  5. import { SearchResult } from './SearchResult'
  6. import { CityManager } from './CityManager'
  7. /*
  8. * 搜索
  9. * */
  10. @Component
  11. export struct SearchLink {
  12.     result?: LocationResult
  13.     @State locations: Location[] = []
  14.     @State
  15.     isShow: boolean = false
  16.     @Link
  17.     dataList: CityMangerModel2[]
  18.     @Link
  19.     tureDataList: CityWeatherVO[]
  20.     @Link citiesInfo: CityModel[]
  21.     private searchDebounceId = -1
  22.     /**
  23.      * 搜索结果变化触发api搜索
  24.      * */
  25.     private searchValueChange(value: string) {
  26.         if (value) {
  27.             if (this.searchDebounceId != -1) {
  28.                 clearTimeout(this.searchDebounceId)
  29.             }
  30.             this.searchDebounceId = setTimeout(() => {
  31.                 fetchCityInfoByKeyWord(value).then(value1 => {
  32.                     this.result = value1
  33.                     this.locations = value1.location
  34.                     this.isShow = true
  35.                 })
  36.             }, 300)
  37.         } else {
  38.             clearTimeout(this.searchDebounceId)
  39.             this.searchDebounceId = -1
  40.             this.isShow = false
  41.         }
  42.     }
  43.     build() {
  44.         Column() {
  45.             //搜索框
  46.             Row() {
  47.                 Search({ placeholder: '搜索位置' })
  48.                     .width('100%')
  49.                     .onChange(value => {
  50.                         this.searchValueChange(value)
  51.                     })
  52.             }
  53.             //搜索结果列表
  54.             Stack() {
  55.                 CityManager({ dataList: this.dataList, trueDataList: this.tureDataList, citiesInfo: this.citiesInfo })
  56.                 if (this.isShow) {
  57.                     SearchResult({
  58.                         locations: this.locations,
  59.                         dataList: this.dataList,
  60.                         tureDataList: this.tureDataList,
  61.                         citiesInfo: this.citiesInfo
  62.                     })
  63.                 }
  64.             }
  65.         }
  66.         .height('100%')
  67.         .padding({ left: 20, right: 20, top: 20 })
  68.         .alignItems(HorizontalAlign.Center)
  69.     }
  70. }
复制代码
这段代码实现了一个位置搜索功能的组件,用于根据用户输入的关键字搜索城市信息,并将结果展示出来。用户可以通过搜索框输入关键字,触发搜索 API 获取城市列表,并在界面中动态表现搜索结果。
5. 气候和城市相干的 API 请求功能实现告急代码展示

  1. import { API_KEY } from '../common/config'
  2. import { request } from '../common/request'
  3. import {
  4.     ForecastWeatherDayResult,
  5.     ForecastWeatherHourResult,
  6.     LocationParam,
  7.     LocationResult,
  8.     NowAirResult,
  9.     RealWeatherResult,
  10.     WeatherIndexResult,
  11.     WeatherParam
  12. } from './type'
  13. /**
  14. * 通过经纬度查询当前城市信息
  15. * @param {string} lon 经度,十进制最多两位小数
  16. * @param {string} lat 纬度,十进制最多两位小数
  17. * */
  18. export function fetchCityByLatitudeAndLongitude(lon: number, lat: number): Promise<LocationResult> {
  19.     return request<LocationParam, LocationResult>('https://geoapi.qweather.com/v2/city/lookup', {
  20.         useBaseUrl: false,
  21.         param: {
  22.             key: API_KEY,
  23.             location: ${lon.toFixed(2)},${lat.toFixed(2)},
  24.             range: 'cn',
  25.             number: 20,
  26.         }
  27.     })
  28. }
  29. /**
  30. * 获取到实时天气
  31. * */
  32. export function     fetchRealWeather(
  33.     location: string,
  34. ): Promise<RealWeatherResult> {
  35.     return request<WeatherParam, RealWeatherResult>('/v7/weather/now', {
  36.         param: {
  37.             key: API_KEY,
  38.             location: location
  39.         }
  40.     })
  41. }
  42. /**
  43. * 获取未来3天天气预报
  44. * */
  45. export function fetchForecast3DayWeather(
  46.     location: string
  47. ): Promise<ForecastWeatherDayResult> {
  48.     return request<WeatherParam, ForecastWeatherDayResult>('/v7/weather/3d', {
  49.         param: {
  50.             key: API_KEY,
  51.             location: location
  52.         }
  53.     })
  54. }
  55. /**
  56. * 获取未来7天天气预报
  57. * */
  58. export function fetchForecast7DayWeather(
  59.     location: string
  60. ): Promise<ForecastWeatherDayResult> {
  61.     return request<WeatherParam, ForecastWeatherDayResult>('/v7/weather/7d', {
  62.         param: {
  63.             key: API_KEY,
  64.             location: location
  65.         }
  66.     })
  67. }
  68. /**
  69. * 获取未来24小时天气预报
  70. * */
  71. export function fetchForecast24HourWeather(
  72.     location: string
  73. ): Promise<ForecastWeatherHourResult> {
  74.     return request<WeatherParam, ForecastWeatherHourResult>('/v7/weather/24h', {
  75.         useBaseUrl: false,
  76.         param: {
  77.             key: API_KEY,
  78.             location: location
  79.         },
  80.     })
  81. }
  82. /*
  83. * 根据关键字获取城市信息
  84. * */
  85. export function fetchCityInfoByKeyWord(
  86.     keyword: string
  87. ): Promise<LocationResult> {
  88.     return request<LocationParam, LocationResult>('https://geoapi.qweather.com/v2/city/lookup', {
  89.         param: {
  90.             key: API_KEY,
  91.             location: keyword
  92.         }
  93.     })
  94. }
  95. /**
  96. * 获取空气质量数据
  97. * */
  98. export function fetchNowAir(
  99.     location: string,
  100. ): Promise<NowAirResult> {
  101.     return request<WeatherParam, NowAirResult>('/v7/air/now', {
  102.         param: {
  103.             key: API_KEY,
  104.             location: location
  105.         }
  106.     })
  107. }
  108. /**
  109. * 获取天气指数
  110. * */
  111. export function fetchWeatherIndices(
  112.     location: string,
  113. ): Promise<WeatherIndexResult> {
  114.     return request<WeatherParam, WeatherIndexResult>('/v7/indices/1d', {
  115.         param: {
  116.             key: API_KEY,
  117.             location: location
  118.         }
  119.     })
  120. }
复制代码
这段代码实现了与气候和城市相干的 API 请求功能,告急用于获取及时气候、气候预报、城市信息、氛围质量等数据。每个函数都是基于 fetch 函数封装的,用于向景象 API 发送请求并获取相应数据
三.项目实现截图展示










四.项目不足与经验总结

项目设计不足


  • 错误处置惩罚机制不同一:不同的请求有不同的错误处置惩罚方式,缺少同一的管理。
  • 数据缓存策略不美满:缓存逾期时间与革新机制不够机动,可能导致数据滞后。
  • 网络请求与组件耦合:网络请求和 UI 组件耦合过深,应该解耦。
  • 过度依赖外部 API:对第三方 API 依赖过高,缺少容错机制和备用方案。
  • UI 设计与用户体验欠缺:UI 交互和细节优化不足,加载提示和数据展示有待改进。
  • 气候数据展示层次不清晰:展示的气候数据缺乏优先级和层次感。
  • 缺少单元测试与自动化测试:缺少美满的单元测试和自动化测试,难以及时发现问题。
经验总结


  • 模块化设计:功能模块化提高代码可维护性和可扩展性。
  • 合理利用数据缓存:优化缓存机制,淘汰网络请求,提高用户体验。
  • UI 交互优化:通过动态结果和反馈提升用户体验。
  • 提前规划错误处置惩罚:同一的错误处置惩罚机制提升代码可靠性。
  • 第三方 API 备选方案:避免过度依赖单一 API,增长容错机制。
  • 清晰的数据结构界说:明确数据格式和结构,保证一致性。
  • 可扩展性:设计时考虑将来功能扩展,保持机动性。
参考与告急鉴戒网址:GitHub - YeMengLiChou/LuckWeather-HarmonyApp: 鸿蒙课设开发——晴气候App

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表