目录
前言
界面效果展示
首页
添加和删除
界面构建讲解
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地址https://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>=[]
}