123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- <template>
- <div class="max-w-md mx-auto p-6 bg-white rounded-xl shadow-lg">
- <h2 class="text-2xl font-bold text-center mb-6">天气查询</h2>
-
- <div class="mb-6">
- <input
- type="text"
- v-model="city"
- placeholder="请输入城市名称"
- class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
- >
- <button
- @click="fetchWeather"
- class="mt-3 w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors"
- >
- 查询天气
- </button>
- </div>
-
- <div v-if="loading" class="text-center py-8">
- <div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
- <p class="mt-2 text-gray-500">加载中...</p>
- </div>
-
- <div v-else-if="error" class="text-center py-8 text-red-500">
- {{ error }}
- </div>
-
- <div v-else-if="weatherData" class="space-y-4">
- <div class="flex justify-between items-center">
- <h3 class="text-xl font-bold">{{ weatherData.city }}, {{ weatherData.country }}</h3>
- <span class="text-lg font-medium">{{ formatDate(weatherData.date) }}</span>
- </div>
-
- <div class="flex items-center justify-center space-x-4 py-6">
- <img
- :src="getWeatherIcon(weatherData.conditionCode)"
- alt="天气图标"
- class="w-20 h-20 object-contain"
- >
- <div>
- <p class="text-4xl font-bold">{{ weatherData.temperature }}°C</p>
- <p class="text-lg text-gray-600">{{ weatherData.description }}</p>
- </div>
- </div>
-
- <div class="grid grid-cols-2 gap-4">
- <div class="bg-gray-50 p-3 rounded-lg">
- <p class="text-sm text-gray-500">体感温度</p>
- <p class="text-lg font-medium">{{ weatherData.feelsLike }}°C</p>
- </div>
- <div class="bg-gray-50 p-3 rounded-lg">
- <p class="text-sm text-gray-500">湿度</p>
- <p class="text-lg font-medium">{{ weatherData.humidity }}%</p>
- </div>
- <div class="bg-gray-50 p-3 rounded-lg">
- <p class="text-sm text-gray-500">风速</p>
- <p class="text-lg font-medium">{{ weatherData.windSpeed }} km/h</p>
- </div>
- <div class="bg-gray-50 p-3 rounded-lg">
- <p class="text-sm text-gray-500">气压</p>
- <p class="text-lg font-medium">{{ weatherData.pressure }} hPa</p>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { ref, computed, onMounted } from 'vue'
- // 天气数据接口
- interface WeatherData {
- city: string
- country: string
- date: Date
- temperature: number
- feelsLike: number
- humidity: number
- windSpeed: number
- pressure: number
- description: string
- conditionCode: number
- }
- const city = ref('北京')
- const weatherData = ref<WeatherData | null>(null)
- const loading = ref(false)
- const error = ref('')
- // 模拟API请求
- const fetchWeather = async () => {
- if (!city.value.trim()) {
- error.value = '请输入城市名称'
- return
- }
-
- loading.value = true
- error.value = ''
-
- try {
- // 实际项目中应替换为真实API
- const response = await simulateWeatherApi(city.value)
- weatherData.value = response
- } catch (err: any) {
- error.value = err.message || '获取天气数据失败'
- } finally {
- loading.value = false
- }
- }
- // 模拟API返回数据
- const simulateWeatherApi = async (city: string): Promise<WeatherData> => {
- // 实际项目中应使用fetch或axios调用真实API
- return new Promise((resolve) => {
- setTimeout(() => {
- const mockData: WeatherData = {
- city,
- country: '中国',
- date: new Date(),
- temperature: Math.floor(Math.random() * 30) + 5,
- feelsLike: Math.floor(Math.random() * 30) + 5,
- humidity: Math.floor(Math.random() * 80) + 20,
- windSpeed: Math.floor(Math.random() * 20) + 1,
- pressure: Math.floor(Math.random() * 50) + 1000,
- description: ['晴天', '多云', '阴天', '小雨', '中雨', '雷阵雨'][Math.floor(Math.random() * 6)],
- conditionCode: Math.floor(Math.random() * 40) + 100
- }
- resolve(mockData)
- }, 1000)
- })
- }
- // 获取天气图标URL
- const getWeatherIcon = (conditionCode: number) => {
- // 实际项目中应根据天气状况代码返回对应的图标
- return `https://picsum.photos/seed/${conditionCode}/100/100`
- }
- // 格式化日期
- const formastDate = (date: Date) => {
- const options: Intl.DateTimeFormatOptions = {
- weekday: 'long',
- month: 'long',
- day: 'numeric'
- }
- return new Date(date).toLocaleDateString('zh-CN', options)
- }
- // 组件挂载后自动查询一次
- onMounted(() => {
- fetchWeather()
- })
- </script>
|