WARNING
在开始使用实践之前,你需要注意,自建网站需要一定的相关知识,你可能会遇到一系列的问题,请确保你有独立解决问题的能力。
假如你想修改主题的某些组件或样式,你还需要掌握 Vue.js 的相关知识
虽然如今你可以借助 AI 来辅助完成一些需求,但知其然,知其所以然
是每一个优秀的人都应该具备的基本素养。
天气及地区获取需要 高德开放平台 相关 API
- 前往 高德开放平台控制台 创建一个
Web
服务 类型的Key
,并将Key
填入.env
中的VITE_WEATHER_KEY
中
TIP
本文章基于imsyy的home里的weather组件魔改而来
在项目根目录创建一个 .env 文件
写入以下内容:
VITE_WEATHER_KEY = "你获取到的天气API KEY"
新建 Weather.vue 文件
新建在:.vitepress\theme\components\Aside\Widgets\Weather.vue
写入以下内容:
vue
<!-- 侧边栏 - 天气数据 -->
<template>
<div class="weather-data s-card">
<div class="title">
<i class="iconfont icon-chart"></i>
<span class="title-name">天气数据</span>
</div>
<div class="all-data">
<!-- 城市 -->
<div class="data-item">
<span class="name"><i class="iconfont icon-home"></i> 城市</span>
<span class="num">{{ weatherData?.city || '--' }}</span>
</div>
<!-- 温度 -->
<div class="data-item">
<span class="name"><i class="iconfont icon-fire"></i> 温度</span>
<span class="num">
{{ weatherData?.temperature != null ? weatherData.temperature + '℃' : '--' }}
</span>
</div>
<!-- 湿度 -->
<div class="data-item">
<span class="name"><i class="iconfont icon-visibility"></i> 湿度</span>
<span class="num">
{{ weatherData?.humidity != null ? weatherData.humidity + '%' : '--' }}
</span>
</div>
<!-- 风向 -->
<div class="data-item">
<span class="name"><i class="iconfont icon-arrow-right"></i> 风向</span>
<span class="num">{{ weatherData?.winddirection || '--' }}</span>
</div>
<!-- 风力 -->
<div class="data-item">
<span class="name"><i class="iconfont icon-refresh"></i> 风力</span>
<span class="num">{{ weatherData?.windpower || '--' }}</span>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getAdcode, getWeather } from '@/api'
const weatherData = ref(null)
// 移动端检测:若是移动端,则不请求,直接显示“--”
const isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent)
onMounted(async () => {
if (isMobile) return
try {
const { adcode } = await getAdcode(import.meta.env.VITE_WEATHER_KEY)
const { lives } = await getWeather(import.meta.env.VITE_WEATHER_KEY, adcode)
weatherData.value = lives[0]
} catch (e) {
console.error('获取天气失败:', e)
$message.error("获取天气失败,可能是天气API超出使用上限");
}
})
</script>
<style lang="scss" scoped>
.weather-data {
.all-data {
display: flex;
flex-direction: column;
margin-top: 12px;
.data-item {
width: 100%;
padding: 8px 0;
display: flex;
justify-content: space-between;
.name {
font-weight: 500;
display: flex;
align-items: center;
i {
margin-right: 4px;
}
}
.num {
font-size: 1.1em;
}
}
}
}
</style>
修改 index.vue
修改index.vue使Weather.vue挂载在侧边
index.vue路径:.vitepress\theme\components\Aside\index.vue
vue
<template>
<aside class="main-aside">
<Hello v-if="theme.aside.hello.enable" class="weidgets" />
<div class="sticky">
<Toc v-if="theme.aside.toc.enable && showToc" class="weidgets" />
<Weather v-if="theme.aside.weather.enable" class="weidgets" />
<Countdown class="weidgets" />
<Tags v-if="theme.aside.tags.enable" class="weidgets" />
<SiteData v-if="theme.aside.siteData.enable" class="weidgets" />
</div>
</aside>
</template>
修改 index.js
.vitepress\theme\api\index.js
js
// 获取高德地理位置信息
export const getAdcode = async (key) => {
const res = await fetch(`https://restapi.amap.com/v3/ip?key=${key}`);
return await res.json();
};
// 获取高德地理天气信息
export const getWeather = async (key, city) => {
const res = await fetch(
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`,
);
return await res.json();
};
修改 themeConfig.mjs
.vitepress\theme\assets\themeConfig.mjs
js
// 天气数据
weather: {
enable: true,
},
完成
按照步骤做完后,你现在dev之后应该就可以看见一个天气侧边栏出现在右边了。祝愉快~
优化:天气组件获取失败自动隐藏
.vitepress\theme\components\Aside\Widgets\Weather.vue
vue
<script setup>
import { ref, onMounted } from 'vue'
import { getAdcode, getWeather } from '@/api'
// 声明会在请求出错时抛出的事件
const emit = defineEmits(['fetch-error'])
const weatherData = ref(null)
const loading = ref(true)
const error = ref(false)
// 移动端检测:若是移动端,则不请求,直接不渲染
const isMobile = /Mobi|Android|iPhone|iPad|Pad|iPod/i.test(navigator.userAgent)
onMounted(async () => {
if (isMobile) {
loading.value = false
return
}
try {
const { adcode } = await getAdcode(import.meta.env.VITE_WEATHER_KEY)
const { lives } = await getWeather(import.meta.env.VITE_WEATHER_KEY, adcode)
weatherData.value = lives[0]
} catch (e) {
console.error('获取天气失败:', e)
error.value = true
// 向父组件抛出“fetch-error”事件
emit('fetch-error', e)
} finally {
loading.value = false
}
})
</script>
.vitepress\theme\components\Aside\index.vue
vue
<template>
<aside class="main-aside">
<Hello v-if="theme.aside.hello.enable" class="weidgets" />
<div class="sticky">
<Toc v-if="theme.aside.toc.enable && showToc" class="weidgets" />
<Weather
v-if="theme.aside.weather.enable && showWeather"
class="weidgets"
@fetch-error="onWeatherError"
/>
<Countdown class="weidgets" />
<Tags v-if="theme.aside.tags.enable" class="weidgets" />
<SiteData v-if="theme.aside.siteData.enable" class="weidgets" />
</div>
</aside>
</template>
<script setup>
const { theme } = useData();
const props = defineProps({
// 显示目录
showToc: {
type: Boolean,
default: false,
},
});
const showWeather = ref(true)
// 一旦收到子组件的 fetch-error 事件,就把 showWeather 置为 false
function onWeatherError(err) {
console.error('天气组件获取失败:', err)
showWeather.value = false
}
</script>
给你的 Curve 主题添加一个天气侧边栏https://chiyu.it/posts/2025/0615
赞赏博主
评论 隐私政策