Vue3 + Axios 实现一个精美天气组件(含实时与未来预报)

发布于:2025-08-17 ⋅ 阅读:(16) ⋅ 点赞:(0)

Vue3 + Axios 实现一个精美天气组件(含实时与未来预报)

一、前言

在很多管理系统、信息看板、门户首页中,天气模块是一个常见的小组件。
它不仅能展示当前的气温、天气状况,还能提供未来几天的天气趋势,让用户对环境有更好的感知。

今天我们就用 Vue3 + Axios,实现一个能够自动定位并展示实时天气和未来预报的天气组件。
并且我们会配上相应的天气图标,让界面更美观。


二、效果预览

组件会自动获取当前城市的天气:

  • 实时天气(温度 + 天气图标)
  • 今日最高/最低温度
  • 未来 5 天天气预报
  • 自动根据天气文字匹配相应的图片

在这里插入图片描述


三、实现思路

  1. 数据来源
    我们使用 心知天气 APIhttps://seniverse.com/)来获取天气数据,location=ip 参数可以根据用户的 IP 自动定位城市。

  2. 技术栈

    • Vue3(组合式 API)
    • Axios(请求 API 数据)
    • SCSS(美化界面)
    • 图片资源(天气图标)
  3. 功能逻辑

    • 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>




网站公告

今日签到

点亮在社区的每一天
去签到