使用Vue.js与OpenWeatherMap API实现7天天气预报功能求助
解决方案
你当前调用的是OpenWeatherMap的实时天气接口(/weather),仅返回当前时刻的天气数据,无法获取未来预报信息,按以下步骤修改即可实现7天天气预报功能:
1. 接口逻辑调整
OpenWeatherMap免费订阅可使用One Call接口获取7天预报数据,需要先通过城市查询接口获取对应城市的经纬度,再调用One Call接口拉取实时+预报数据,无需分开调用两个接口。
2. 完整修改后的App.vue代码
<template> <div id="app" :class="typeof weather.current != 'undefined' && weather.current.temp > 16 ? 'warm' : ''"> <main> <div class="search-box"> <input type="text" class="search-bar" placeholder="输入城市名称..." v-model="query" @keypress="fetchWeather" /> </div> <div class="weather-wrap" v-if="typeof weather.current != 'undefined'"> <div class="location-box"> <div class="location">{{ locationName }}, {{ locationCountry }}</div> <div class="date">{{ dateBuilder() }}</div> </div> <div class="weather-box"> <div class="temp">{{ Math.round(weather.current.temp) }}°c</div> <div class="weather">{{ weather.current.weather[0].main }}</div> </div> <!-- 7天天气预报区域 --> <div class="forecast-wrap"> <h3 class="forecast-title">未来7天预报</h3> <div class="forecast-list"> <div class="forecast-item" v-for="(item, index) in weather.daily" :key="index"> <div class="forecast-day">{{ dateBuilder(item.dt * 1000) }}</div> <div class="forecast-temp">{{ Math.round(item.temp.min) }}° / {{ Math.round(item.temp.max) }}°</div> <div class="forecast-desc">{{ item.weather[0].main }}</div> </div> </div> </div> </div> </main> </div> </template> <script> export default { name: 'app', data () { return { api_key: '替换为你自己的API_KEY', url_base: 'https://api.openweathermap.org/data/2.5/', query: '', weather: {}, locationName: '', locationCountry: '' } }, methods: { async fetchWeather (e) { if (e.key == "Enter") { // 第一步:查询城市经纬度信息 const geoRes = await fetch(`${this.url_base}weather?q=${this.query}&units=metric&APPID=${this.api_key}`) const geoData = await geoRes.json() this.locationName = geoData.name this.locationCountry = geoData.sys.country const { lat, lon } = geoData.coord // 第二步:调用One Call接口获取7天预报 const forecastRes = await fetch(`${this.url_base}onecall?lat=${lat}&lon=${lon}&exclude=minutely,hourly,alerts&units=metric&APPID=${this.api_key}`) const forecastData = await forecastRes.json() this.weather = forecastData } }, // 重载日期方法,支持传入时间戳生成对应日期 dateBuilder (timestamp = Date.now()) { let d = new Date(timestamp); let months = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]; let days = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]; let day = days[d.getDay()]; let date = d.getDate(); let month = months[d.getMonth()]; return `${day} ${date} ${month}`; } } } </script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, Helvetica, sans-serif; } #app { background-image: url('./assets/cold-bg.jpg'); background-size: cover; background-position: bottom; transition: 0.4s; } #app.warm { background-image: url('./assets/warm-bg.jpg'); } main { min-height: 100vh; padding: 25px; background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.75)); } .search-box { width: 100%; margin-bottom: 30px; } .search-box .search-bar { display: block; width: 100%; padding: 15px; color: #313131; font-size: 20px; appearance: none; border:none; outline: none; background: none; box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.25); background-color: rgba(255, 255, 255, 0.5); border-radius: 0px 16px 0px 16px; transition: 0.4s; } .search-box .search-bar:focus { box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.25); background-color: rgba(255, 255, 255, 0.75); border-radius: 16px 0px 16px 0px; } .location-box .location { color: #FFF; font-size: 32px; font-weight: 500; text-align: center; text-shadow: 1px 3px rgba(0, 0, 0, 0.25); } .location-box .date { color: #FFF; font-size: 20px; font-weight: 300; font-style: italic; text-align: center; } .weather-box { text-align: center; } .weather-box .temp { display: inline-block; padding: 10px 25px; color: #FFF; font-size: 102px; font-weight: 900; text-shadow: 3px 6px rgba(0, 0, 0, 0.25); background-color:rgba(255, 255, 255, 0.25); border-radius: 16px; margin: 30px 0px; box-shadow: 3px 6px rgba(0, 0, 0, 0.25); } .weather-box .weather { color: #FFF; font-size: 48px; font-weight: 700; font-style: italic; text-shadow: 3px 6px rgba(0, 0, 0, 0.25); } /* 7天预报新增样式 */ .forecast-wrap { margin-top: 40px; } .forecast-title { color: #FFF; text-align: center; font-size: 24px; margin-bottom: 20px; text-shadow: 1px 3px rgba(0, 0, 0, 0.25); } .forecast-list { display: flex; flex-wrap: wrap; gap: 15px; justify-content: center; } .forecast-item { background-color: rgba(255, 255, 255, 0.2); border-radius: 12px; padding: 15px; min-width: 120px; text-align: center; color: #FFF; box-shadow: 2px 4px rgba(0, 0, 0, 0.2); } .forecast-day { font-weight: 500; margin-bottom: 8px; } .forecast-temp { margin: 8px 0; font-size: 18px; } .forecast-desc { font-size: 14px; font-style: italic; } </style>
注意事项
- 请将代码中
替换为你自己的API_KEY字段替换为你真实的OpenWeatherMap接口密钥 - One Call接口返回的daily数组默认包含当天+未来7天共8天数据,若仅需展示不含当天的未来7天预报,可将模板中循环代码改为
v-for="(item, index) in weather.daily.slice(1)" - One Call接口属于OpenWeatherMap v2.5版本的免费接口,免费订阅额度内可正常调用
内容的提问来源于stack exchange,提问作者sanss
相关产品推荐
相关产品推荐

