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
| <template> <h2>🌦️ 自選三個城市天氣概況</h2>
<label>請選擇最多三個城市:</label> <select multiple v-model="selectedCities" > <option v-for="city in allCityNames" :key="city">{{ city }}</option> </select> <p>目前選擇:{{ selectedCities.join(', ') }}</p>
<div class="weather-container"> <div v-for="city in filteredWeatherData" :key="city.locationName" class="city-card"> <h3>🌆 {{ city.locationName }}</h3> <p>☀️ 天氣:{{ getWeatherElement(city, 'Wx') }}</p> <p>🔥 最高溫:{{ getWeatherElement(city, 'MaxT') }}°C</p> <p>❄️ 最低溫:{{ getWeatherElement(city, 'MinT') }}°C</p> <p>🌧️ 降雨機率:{{ getWeatherElement(city, 'PoP') }}%</p> </div> </div> </template>
<script setup> import { ref, computed, onMounted } from 'vue'
const apiKey = 'CWA-290D12F1-3FA3-4A61-B613-623327DD04C2'
const url = `https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=${apiKey}`
const weatherData = ref([]) const allCityNames = ref([]) const selectedCities = ref([]) const limitReached = ref(false)
onMounted(async () => { try { const response = await fetch(url) const data = await response.json() const locations = data.records.location
weatherData.value = locations allCityNames.value = locations.map(loc => loc.locationName)
selectedCities.value = ['臺北市', '臺中市', '高雄市'] } catch (error) { console.error('❌ 發生錯誤:', error) } })
function checkLimit() { if (selectedCities.value.length > 3) { selectedCities.value.pop() limitReached.value = true setTimeout(() => { limitReached.value = false }, 2000) } }
const filteredWeatherData = computed(() => weatherData.value.filter(city => selectedCities.value.includes(city.locationName)) )
function getWeatherElement(city, elementName) { const element = city.weatherElement.find(el => el.elementName === elementName) return element?.time[0]?.parameter?.parameterName || 'N/A' } </script>
<style scoped> select { width: 100%; padding: 0.5rem; margin-bottom: 0.5rem; font-size: 1rem; }
.weather-container { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.city-card { flex: 1 1 300px; max-width: 300px; background: #f0f8ff; padding: 1rem; border-radius: 0.75rem; box-shadow: 0 2px 6px rgba(0,0,0,0.1); border-left: 6px solid #3498db; } </style>
|