1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| <template> <div :class="['weather-app', weatherClass]"> <div class="container"> <h1>天氣查詢</h1>
<select v-model="selectedCity" @change="fetchWeather"> <option v-for="city in cities" :key="city" :value="city">{{ city }}</option> </select>
<div v-if="weatherData" class="weather-info"> <img :src="weatherIcon" alt="Weather Icon" class="weather-icon" /> <p><strong>天氣現象:</strong>{{ weatherData.weather }}</p> <p><strong>最高溫度:</strong>{{ weatherData.maxT }} °C</p> <p><strong>最低溫度:</strong>{{ weatherData.minT }} °C</p> <p><strong>降雨機率:</strong>{{ weatherData.pop }}%</p> </div> </div> </div> </template>
<script setup> import { ref, onMounted, watch } from 'vue'
const apiKey = '你的API_KEY' // <<--- 請替換為你註冊的 CWA API Key const cities = ref([]) const selectedCity = ref('') const weatherData = ref(null) const weatherClass = ref('') const weatherIcon = ref('')
// 取得城市清單 const fetchCities = async () => { const url = `https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=${apiKey}` const res = await fetch(url) const data = await res.json() cities.value = data.records.location.map(loc => loc.locationName) selectedCity.value = cities.value[0] }
// 根據縣市抓取天氣資訊 const fetchWeather = async () => { const url = `https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=${apiKey}` const res = await fetch(url) const data = await res.json() const cityData = data.records.location.find(loc => loc.locationName === selectedCity.value)
if (cityData) { const weather = cityData.weatherElement.find(e => e.elementName === 'Wx').time[0].parameter.parameterName const maxT = cityData.weatherElement.find(e => e.elementName === 'MaxT').time[0].parameter.parameterName const minT = cityData.weatherElement.find(e => e.elementName === 'MinT').time[0].parameter.parameterName const pop = cityData.weatherElement.find(e => e.elementName === 'PoP').time[0].parameter.parameterName
weatherData.value = { weather, maxT, minT, pop } updateWeatherStyle(weather) } }
// 設定背景與圖示 const updateWeatherStyle = (weather) => { if (weather.includes('雷')) { weatherClass.value = 'thunder' weatherIcon.value = 'https://cdn-icons-png.flaticon.com/512/1146/1146858.png' } else if (weather.includes('雨')) { weatherClass.value = 'rainy' weatherIcon.value = 'https://cdn-icons-png.flaticon.com/512/4150/4150897.png' } else if (weather.includes('雲') || weather.includes('陰')) { weatherClass.value = 'cloudy' weatherIcon.value = 'https://cdn-icons-png.flaticon.com/512/414/414825.png' } else { weatherClass.value = 'sunny' weatherIcon.value = 'https://cdn-icons-png.flaticon.com/512/869/869869.png' } }
onMounted(() => { fetchCities().then(() => fetchWeather()) })
watch(selectedCity, fetchWeather) </script>
<style scoped> .weather-app { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 1rem; transition: background 0.5s ease; }
.container { background: white; padding: 2rem; border-radius: 1rem; max-width: 400px; width: 100%; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }
select { width: 100%; padding: 0.5rem; margin-bottom: 1rem; }
.weather-info { text-align: center; }
.weather-icon { width: 100px; margin-bottom: 1rem; }
/* RWD */ @media (max-width: 600px) { .container { padding: 1rem; }
.weather-icon { width: 70px; } }
/* 背景漸層樣式 */ .sunny { background: linear-gradient(to bottom, #87CEEB, #ffffff); } .cloudy { background: linear-gradient(to bottom, #ccc, #eee); } .rainy { background: linear-gradient(to bottom, #3a3a3a, #666); } .thunder { background: linear-gradient(to bottom, #000000, #333333); } </style>
|