天气数据是从彩云天气获取的。详细参数含义请查看文档。关于请求API用到的key,大家可以在彩云官网进行申请试用。当然大家本着体验学习不想申请试用的话,看这里学着分析提取key。
通过代理的方式解决前端本地开发请求彩云天气接口的跨域问题
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
server: {
proxy: {
'/caiyun-weather': {
target: 'https://api.caiyunapp.com',
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(/^\/caiyun-weather/, ''),
},
},
},
plugins: [vue()],
})
<template>
<div class="weather-content" ref="echartRef"></div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import * as echarts from 'echarts'
const echartRef = ref()
const tem1 = ref<number[]>([]) //最高温度
const tem2 = ref<number[]>([]) //最低温度
const weatherDate = ref<string[]>([]) // 日期
const weatherDay = ref<string[]>([])
const weaterImg = ref<string[]>([])
const weaterDesc = ref<string[]>([])
const WEEKDAY = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
async function getWeather() {
// v2.6 是api版本号
// Y2FpeXVuX25vdGlmeQ== 是调用api需要用到的key
// 101.6656,39.2072 是要查询位置的经纬度
const { data } = await axios({
url: '/caiyun-weather/v2.6/Y2FpeXVuX25vdGlmeQ==/101.6656,39.2072/daily',
method: 'get',
params: {
dailysteps: 7,
},
})
let { status, result, error } = data
if (status != 'ok') {
alert(error)
return
}
let { temperature_08h_20h, temperature_20h_32h, skycon, precipitation } = result.daily
const Today = new Date().getDay()
for (let i = 0; i < temperature_08h_20h.length; i++) {
tem1.value.push(temperature_08h_20h[i].max)
tem2.value.push(temperature_20h_32h[i].min)
weatherDate.value.push(temperature_08h_20h[i].date.substr(0, 10))
weatherDay.value.push(i == 0 ? '今天' : WEEKDAY[(Today + i) % 7])
weaterImg.value.push(getSkyIconPicName(skycon[i].value, precipitation[i].avg))
weaterDesc.value.push(parseSkycon(skycon[i].value))
}
}
function initEchart() {
const Color = ['#FAFF00', '#1165FF']
let options = {
grid: {
show: true,
backgroundColor: 'transparent',
opacity: 0.3,
borderWidth: '0',
top: '150',
bottom: '20',
},
tooltip: { trigger: 'axis' },
legend: { show: false },
xAxis: [
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 110,
zlevel: 100,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
formatter: ['{a|{value}}'].join('\n'),
rich: {
a: {
color: 'white',
fontSize: 14,
fontFamily: 'Alibaba PuHuiTi 2-75 SemiBold',
},
},
},
nameTextStyle: {},
data: weatherDate.value,
},
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 90,
zlevel: 100,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
formatter: ['{a|{value}}'].join('\n'),
rich: {
a: {
color: 'white',
fontSize: 12,
fontFamily: 'Alibaba PuHuiTi 2-75 SemiBold',
},
},
},
nameTextStyle: {
fontWeight: 'bold',
fontSize: 19,
},
data: weatherDay.value,
},
{
type: 'category',
boundaryGap: false,
position: 'top',
offset: 10,
zlevel: 100,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
formatter: function (value: any, index: any) {
return '{' + index + '| }\n{b|' + value + '}'
},
rich: {
...weaterImg.value.reduce((obj: any, image: string, index: number) => {
obj[index] = {
backgroundColor: { image },
height: 40,
width: 40,
}
return obj
}, {}),
b: {
color: 'white',
fontSize: 12,
lineHeight: 30,
height: 20,
},
},
},
data: weaterDesc.value,
},
],
yAxis: {
type: 'value',
show: false,
axisLabel: {
formatter: '{value} °C',
color: 'white',
},
},
series: [
{
name: '最高气温',
type: 'line',
data: tem1.value,
symbol: 'circle',
smooth: true,
itemStyle: { color: Color[0] },
label: {
show: true,
position: 'top',
color: 'white',
formatter: '{c} °C',
},
lineStyle: { color: Color[0] },
},
{
name: '最低气温',
type: 'line',
data: tem2.value,
symbol: 'circle',
smooth: true,
itemStyle: { color: Color[1] },
label: {
show: true,
position: 'bottom',
color: 'white',
formatter: '{c} °C',
},
lineStyle: { color: Color[1] },
},
],
}
let instance = echarts.getInstanceByDom(echartRef.value)
if (instance) {
instance.setOption(options)
} else {
echarts.init(echartRef.value).setOption(options)
}
}
onMounted(async () => {
await getWeather()
initEchart()
})
/**
* 获取天气图标名称
* https://www.caiyunapp.com/h5/js/process-data.js
* @param skycon
* @param prec
*/
function getSkyIconPicName(skycon: string, prec: number) {
var allPicName = {
CLEAR: 'clear.png',
CLEAR_NIGHT: 'clear_night.png',
PARTLY_CLOUDY: 'partly_cloudy.png',
PARTLY_CLOUDY_NIGHT: 'partly_cloudy_night.png',
CLOUDY: 'cloudy.png',
SNOW: 'snow.png',
RAIN: 'rain.png',
FOG: 'fog.png',
HAZE: 'haze.png',
WIND: 'wind.png',
}
// @ts-ignore
var name = allPicName[skycon.match(/CLEAR_NIGHT|CLEAR|PARTLY_CLOUDY_NIGHT|PARTLY_CLOUDY|CLOUDY|SNOW|RAIN|FOG|HAZE|WIND|/)[0]] || 'partly_cloudy.png'
if (prec && prec > 1) {
if (prec < 10) {
name = 'rain_low.png'
} else if (prec < 25) {
name = 'rain_middle.png'
} else if (prec < 50) {
name = 'rain_high.png'
} else {
name = 'rain_large.png'
}
}
return 'https://caiyunapp.com/images/skyicon/' + name
}
/**
* 将天气现象转成中文
* https://www.caiyunapp.com/h5/js/process-data.js
* @param skycon
*/
function parseSkycon(skycon: string) {
const allDesc: any = {
CLEAR_DAY: '晴',
CLEAR_NIGHT: '晴',
PARTLY_CLOUDY_DAY: '多云',
PARTLY_CLOUDY_NIGHT: '多云',
CLOUDY: '阴',
CLOUDY_NIGHT: '阴',
RAIN: '雨',
SNOW: '雪',
SNOW_NIGHT: '雪',
WIND: '大风',
FOG: '雾',
HAZE: '雾霾',
}
return allDesc[skycon] || allDesc['CLEAR_DAY']
}
</script>
<style scoped>
.weather-content {
width: 590px;
height: 290px;
background: rgba(0, 0, 0, 0.5);
}
</style>
完事。
浏览器打开彩云天气官网天气预报页面:https://www.caiyunapp.com/h5/
F12
打开控制台, 再次刷新页面Network
这个tabforecast
过滤请求v2
这个版本号后面跟着的字符串就是key