Vue3 + Axios 實現一個精美天氣組件(含實時與未來預報)
一、前言
在很多管理系統、信息看板、門戶首頁中,天氣模塊是一個常見的小組件。
它不僅能展示當前的氣溫、天氣狀況,還能提供未來幾天的天氣趨勢,讓用戶對環境有更好的感知。
今天我們就用 Vue3 + Axios,實現一個能夠自動定位并展示實時天氣和未來預報的天氣組件。
并且我們會配上相應的天氣圖標,讓界面更美觀。
二、效果預覽
組件會自動獲取當前城市的天氣:
- 實時天氣(溫度 + 天氣圖標)
- 今日最高/最低溫度
- 未來 5 天天氣預報
- 自動根據天氣文字匹配相應的圖片
三、實現思路
-
數據來源
我們使用 心知天氣 API(https://seniverse.com/)來獲取天氣數據,location=ip
參數可以根據用戶的 IP 自動定位城市。 -
技術棧
- Vue3(組合式 API)
- Axios(請求 API 數據)
- SCSS(美化界面)
- 圖片資源(天氣圖標)
-
功能邏輯
- 用
axios.get
分別請求 實時天氣 和 未來天氣。 - 將獲取的數據存入 Vue3 的
ref
響應式變量。 - 根據天氣文字選擇對應的圖標(如“晴”、“小雨”、“暴雪”等)。
- 用
v-for
循環渲染未來天氣列表。
- 用
四、代碼實現
<template><div class="weather"><!-- 地址信息 --><div class="address"><img src="@/assets/index/weather/address.png" alt="" /><span>{{ weatherData.location.name }}</span> <!-- 城市名稱 --></div><!-- 當前氣候信息 --><div class="climate"><!-- 天氣圖標 --><img class="climate-icon" :src="getWeatherIcon(weatherData.now.text)" alt="" /><!-- 溫度 --><div class="wendu">{{ weatherData.now.temperature }}<span>℃</span></div><!-- 今日最高/最低氣溫 + 空氣質量 --><div class="today"><div class="label"><span>今天</span><span>{{ text }}</span> <!-- 天氣描述(如晴、陰、雨等) --></div><div class="value"><span class="value-text">{{ future.daily[0].high }}/{{ future.daily[0].low }}℃</span><div class="quality"><span class="quality-icon"></span><span class="quality-text">優</span> <!-- 空氣質量(這里寫死為優) --></div></div></div></div><!-- 未來幾天天氣 --><div class="future"><template v-for="(item, index) in future.daily" :key="index"><div class="future-item"><!-- 天氣圖標(白天) --><img :src="getWeatherIcon(item.text_day)" alt="" /><div class="future-box"><div class="box-label">{{ parseTime(item.date, "{m}月{d}日") }}</div><div class="box-value">{{ item.high }}/{{ item.low }}℃</div></div></div><!-- 分隔線,最后一天不畫 --><div class="future-line" v-if="index !== future.daily.length - 1"></div></template></div></div>
</template><script setup name="Weather">
import axios from "axios";// 當前天氣數據(實時)
const weatherData = ref({location: {},now: {},
});// 未來天氣數據(默認值避免渲染時報錯)
const future = ref({location: {},daily: [{high: "30",low: "10",},],
});// 根據天氣描述返回對應的圖標路徑
const getWeatherIcon = (text) => {let img = "晴"; // 默認是晴天switch (text) {case "晴": img = "晴"; break;case "暴雨": img = "暴雨"; break;case "雷陣雨": img = "雷陣雨"; break;case "雷陣雨伴有冰雹": img = "雷陣雨伴有冰雹"; break;case "大暴雨": img = "特大暴雨"; break;case "特大暴雨": img = "特大暴雨"; break;case "霧": img = "霧"; break;case "小雨":case "中雨":case "大雨": img = "下雨"; break;case "陣雪": img = "陣雪"; break;case "小雪":case "中雪":case "大雪": img = "雪"; break;case "暴雪": img = "暴雪"; break;case "風":case "大風": img = "風"; break;case "颶風":case "熱帶風暴":case "龍卷風": img = "風"; break;case "雨夾雪": img = "雨夾雪"; break;default: break;}// 返回圖片路徑(Vite 的 new URL 寫法)return new URL(`../../assets/index/weather/${img}.png`, import.meta.url).href;
};// 獲取天氣數據(調用心知天氣 API)
const getList = () => {// 當前天氣axios.get("https://api.seniverse.com/v3/weather/now.json?key=SjyiLD_odjCGOsHoF&location=ip&language=zh-Hans&unit=c").then((res) => {weatherData.value = res.data.results[0];});// 未來 5 天的天氣axios.get("https://api.seniverse.com/v3/weather/daily.json?key=SjyiLD_odjCGOsHoF&location=ip&language=zh-Hans&unit=c&start=0&days=5").then((res) => {future.value = res.data.results[0];});
};// 組件加載時調用一次
getList();
</script><style lang="scss" scoped>
.weather {width: 100%;height: 100%;padding: 5px 15px;background: url("@/assets/index/weather/bg.png") no-repeat;background-size: 100% 100%;/* 地址部分樣式 */.address {display: flex;align-items: center;img {width: 14px;height: 17px;margin-right: 5px;}span {font-family: PingFang SC;font-size: 12px;color: #cce6f8;}}/* 當前氣候部分樣式 */.climate {display: flex;align-items: center;margin: 8px 0;.climate-icon {width: 60px;margin-right: 5px;}.wendu {font-size: 50px;font-weight: 600;color: #ffffff;margin-right: 20px;line-height: 1;span {font-size: 20px;}}.today {.label {width: 75px;font-size: 16px;color: #ffffff;display: flex;justify-content: space-between;}.value {display: flex;align-items: center;.value-text {font-size: 18px;color: #ffffff;margin-right: 10px;}.quality {padding: 0 10px;height: 20px;background: #67baee;border-radius: 10px;.quality-icon {width: 9px;height: 9px;border-radius: 50%;background: #51cfa4;border: 1px solid #ffffff;margin-right: 4px;display: inline-block;}.quality-text {font-size: 14px;color: #ffffff;}}}}}/* 未來天氣部分 */.future {display: flex;justify-content: space-between;align-items: center;.future-item {display: flex;align-items: center;img {width: 36px;height: 36px;margin-right: 3px;}.future-box {.box-label {font-size: 12px;color: #cce6f8;}.box-value {font-size: 12px;color: #ffffff;}}}/* 中間的豎線分隔 */.future-line {width: 1px;height: 25px;background: #2794ea;margin: 0 auto;}}
}/* 針對屏幕寬度小于 1650px 時的樣式優化 */
@media screen and (max-width: 1650px) {.weather .climate {.wendu {margin-right: 15px;}.today .value .quality {padding: 0 6px;}}
}
</style>