Vue + 和风天气API实战:组件化数据流与工程化部署全解析 📅 发布时间:2026/9/15 7:55:06 👁 浏览次数: 简介基于Vue框架实现的和风天气功能代码源码包主要面向前端开发者和正在学习Vue的初学者提供一套可直接运行的天气查询应用参考实现。功能上覆盖当前天气展示、空气质量查询、地理位置定位、未来天气预报等核心场景并通过组件化方式拆分界面与逻辑适合用于课程设计、毕业设计及日常功能练习。压缩包共包含26个文件整体大小约477KB以Vue组件、JavaScript脚本与JSON配置文件为主体其中可见10个Vue组件、7个JavaScript文件、3个JSON文件此外还配有HTML入口文件、图标文件、浏览器兼容范围配置、版本忽略规则、工程说明文档等辅助内容目录结构清楚便于逐文件对照学习。当前已有130人学习下载参考价值得到初步验证。借助这套代码能够理解组件间通信、数据绑定、接口调用、路由配置以及项目构建配置的完整链路尤其适合希望将第三方天气数据接入前端项目的开发者。1. 和风天气接入Vue值得拆开看的组件化范本拿到一份和风天气QWeather的 Vue 源码时第一反应往往是去翻组件里写了什么但真正决定这套代码能不能复用的是它的工程结构与数据流设计。这份源码一共 26 个文件10 个 Vue 组件、7 个 JavaScript 脚本、3 个 JSON 配置恰好覆盖了一个前端应用从开发环境到构建产物所需的全部环节。对准备做天气类 vue 项目实战的开发者来说它比单独看 API 文档更有参考价值因为里面包含了城市定位、实况天气、未来预报、空气质量四条完整链路而且把请求逻辑分散到组件与状态层而不是全部堆在 App.vue 里。下面按工程骨架、组件拆分、路由编排、上线优化的顺序逐一拆解顺手把参数怎么配、坑在哪里一起说清楚。2. Vue CLI工程骨架与和风天气API代理策略2.1 26个文件的工程结构Vue 2项目该有的骨架解压 upload.zip 之后先看根目录文件这套结构是典型的 Vue CLI 工程。main.js 是入口App.vue 是最外层容器store/index.js 管全局状态router/index.js 管页面路由components 目录放业务组件views 目录放页面级组件。其中公共业务组件有 6 个NowWeather 实况天气、FutureWeather 未来预报、AirQulity 空气质量、GeoLocation 地理定位、TianZi 天气卡片外加一个 App.vue页面组件有 4 个HomeView 主页、AboutView 关于页、AirView 空气质量页、TianZhi 预报详情页。vue-weather/ ├── .browserslistrc ├── babel.config.js ├── .eslintrc.js ├── vue.config.js ├── package.json ├── public/ │ ├── favicon.ico │ └── index.html └── src/ ├── main.js ├── App.vue ├── common/constrant.js ├── components/ │ ├── NowWeather.vue │ ├── FutureWeather.vue │ ├── AirQulity.vue │ ├── GeoLocation.vue │ └── TianZi.vue ├── router/index.js ├── store/index.js └── views/ ├── HomeView.vue ├── AboutView.vue ├── AirView.vue └── TianZhi.vue这套目录里值得留意的是几个配置文件的分工。.browserslistrc 声明浏览器兼容范围Babel 和 Autoprefixer 都会读取它来决定转译和加前缀的目标.eslintrc.js 约束代码规范防止多人协作时风格漂移jsconfig.json 的作用是让 IDE 识别开头路径指向 src 目录写 import 的时候可以直接/components/...。babel.config.js 与 package-lock.json 的存在说明依赖锁定和转译配置都已经就位npm install 之后直接npm run serve就能拉起 vue 开发环境。2.2 vue.config.js代理把API Key挡在浏览器外和风天气的接口域名是devapi.qweather.com和geoapi.qweather.com如果前端直接请求这两个域名会碰到两个问题一是浏览器跨域限制二是 API Key 直接暴露在 Network 面板里。施工队常挂在嘴边的一句话是Key 放前端等于没放。正确做法是在 vue.config.js 里配置 devServer.proxy让浏览器只跟本地同源地址通信由 Vue CLI 开发服务器转发到和风天气。// vue.config.js module.exports { devServer: { port: 8080, proxy: { /devapi: { target: https://devapi.qweather.com, changeOrigin: true, pathRewrite: { ^/devapi: } }, /geoapi: { target: https://geoapi.qweather.com, changeOrigin: true, pathRewrite: { ^/geoapi: } } } } }changeOrigin 的作用是把请求头里的 Host 字段改写成 target 域名否则和风天气服务端校验 Host 时会拒绝pathRewrite 把/devapi前缀去掉因为真实接口路径是/v7/weather/now没有/devapi这一段。开发环境里请求写/devapi/v7/weather/now代理转发后到达服务器的是https://devapi.qweather.com/v7/weather/now浏览器看不到真实域名也就绕过了跨域限制。注意生产环境没有 devServer这份代理只在本地生效上线时要靠 Nginx 做同样的转发后面第 5 章单独讲。2.3 constrant.js统一管理接口常量源码里 common 目录下有一个文件名带拼写差异的 constrant.js按工程惯例它就是 constants 的用途集中放接口前缀、API Key、城市编码映射。不要把接口地址散落在各个组件里后续换域名或切换 API 版本时只改这一个文件即可。这里留一个空 Key 位主要用于本地联调。// src/common/constrant.js export const QWEATHER_DEV /devapi/v7 export const QWEATHER_GEO /geoapi/v2 // 开发环境可以临时填测试Key提交代码前必须置空 export const API_KEY export const CITY_ID_MAP { beijing: 101010100, shanghai: 101020100, guangzhou: 101280101 }和风天气的 Location 参数支持两种格式LocationID如北京的 101010100和经纬度如116.41,39.92。用 LocationID 的好处是后续请求未来预报、空气质量时不需要做第二次坐标转换所以推荐在定位拿到城市后先查表或调用城市搜索接口换取 LocationID。这份源码里的 GeoLocation 组件职责就是干这件事单独拿出来也能复用。3. 组件化数据流GeoLocation、NowWeather与FutureWeather的接口编排3.1 GeoLocation定位链路从IP到城市ID定位组件是整条数据链路的起点。GeoLocation.vue 的思路很直白页面加载后先请求和风天气的 IP 定位接口/geoapi/v2/ip拿到当前公网 IP 对应的城市信息再从中取出 LocationID 传给其他组件。IP 定位不需要用户授权HTTP 环境下也能用这是它在开发环境里比浏览器 Geolocation 更顺手的优势。// GeoLocation.vue 核心方法 async locate() { this.loading true try { const res await fetch(${QWEATHER_GEO}/ip?key${API_KEY}) const data await res.json() if (data.code 200) { const { id, name, adm1 } data.location this.$store.commit(weather/setLocation, { id, name, adm1 }) } } catch (e) { this.errorMsg 定位失败请手动选择城市 } finally { this.loading false } }这里的 commit 是 Vuex 的标准写法把从 IP 定位得到的{ id, name, adm1 }写入全局状态 store。adm1 是省级行政区名称渲染层级导航时可以直接展示“北京市 / 北京”id 就是后面所有天气接口要用的 location 参数。如果定位失败组件会把 errorMsg 抛给上层页面HomeView.vue 可以据此切换成城市搜索框调用城市查询接口GET /geoapi/v2/city/lookup?location城市名让用户手动选择。这套降级逻辑在移动端很常见因为部分网络环境下 IP 库的精度并不理想。3.2 NowWeather与FutureWeather的接口编排实况天气和未来预报两个组件是 vue 面试题里“多个组件共享同一份数据”的落地场景。常规误写是把请求逻辑各写一遍NowWeather 请求一次、FutureWeather 又请求一次浪费请求次数不说两边的 loading 状态还难以同步。这份源码采用了 store 统一请求的方式GeoLocation 定位成功后HomeView 监听 location.id 变化触发一次天气数据拉取再分别派发给子组件。// HomeView.vue 中监听定位结果并拉取数据 watch: { location.id: { handler(id) { if (!id) return this.fetchAllWeather(id) }, immediate: true } }, methods: { async fetchAllWeather(id) { const params location${id}key${API_KEY} const res await fetch(${QWEATHER_DEV}/weather/now?${params}) const data await res.json() if (data.code 200) { this.$store.commit(weather/setNow, data.now) } } }fetch 拿回的数据写入 Vuex 的 weather 模块后NowWeather 和 FutureWeather 通过 computed 读取// NowWeather.vue import { mapState } from vuex export default { computed: { ...mapState(weather, [now, location]), currentTemp() { return this.now ? this.now.temp : -- } } }mapState 第一个参数weather对应 store 里声明的模块名组件内部不感知请求状态只关心 store 里的数据是否就绪。这样做还有一个好处从首页跳到 TianZhi 详情页时实况数据已经在 store 里页面切换瞬间就能渲染不用二次等待。3.3 FutureWeather表格化渲染与天气代码映射FutureWeather 组件负责把 3 天预报渲染成结构化表格。和风天气/weather/3d接口返回的daily数组里每一项包含fxDate预报日期、tempMax、tempMin、textDay白天天气现象、iconDay白天天气图标代码。v-for 循环即可完成列表渲染但有一个细节要注意iconDay 返回的是数字代码而项目里需要根据代码映射成对应的图标或样式。code天气现象图标映射建议100晴太阳图标101多云云太阳图标104阴云图标300阵雨云雨点图标305小雨雨点图标306中雨中雨图标311小雪雪点图标999未知默认图标这段映射逻辑适合放在单独的工具函数里不建议写在模板中。模板里做复杂判断会让 DOM 层难以维护前面 constrant.js 里已经预留了常量位把映射表也放进去组件只负责查找。AirQulity 组件同样适用这个模式空气质量接口返回的 category 字段本身就是文本优、良、轻度污染但 AQI 数值需要颜色分级用 CSS 类名控制展示层级更灵活。4. vue路由与视图编排HomeView到TianZhi的传参与复用4.1 路由表设计三个视图页与懒加载views 目录下有 4 个页面组件router/index.js 里把这几个页面串成了完整导航。注意这里用的是路由懒加载组件通过() import()引入首屏只加载 HomeView其他页面在路由命中时才请求对应 JS 文件能明显减少首包体积。// src/router/index.js import Vue from vue import VueRouter from vue-router Vue.use(VueRouter) const routes [ { path: /, name: HomeView, component: () import(/views/HomeView.vue) }, { path: /about, name: AboutView, component: () import(/views/AboutView.vue) }, { path: /air, name: AirView, component: () import(/views/AirView.vue) }, { path: /tianzhi, name: TianZhi, component: () import(/views/TianZhi.vue) } ] export default new VueRouter({ routes })AirView 挂载的是空气质量独立页面与 HomeView 里的 AirQulity 组件在数据源上是同源的都指向/air/now接口。区别在于路由级页面往往承担更多交互比如切换城市、查看 24 小时变化曲线组件则优先保证信息密度。工程项目里这样安排最合理通用组件放 components 目录带完整路由的页面视图放 views 目录组件通过 props 或 store 接收数据页面通过路由管理自己的生命周期。4.2 路由转场时TianZhi怎么知道要请求哪个城市从 HomeView 跳转到 TianZhi 详情页难点不是写跳转方法而是在刷新页面后数据不丢。最稳妥的做法是用 query 而不是 params 传参query 会保留在 URL 上用户刷新浏览器后 Vue 路由仍能读到$route.query.cityId。// HomeView.vue 跳转方法 goDetail() { const cityId this.location.id if (!cityId) { this.$store.commit(weather/setError, 城市定位未完成) return } this.$router.push({ name: TianZhi, query: { cityId } }) }对应的 TianZhi.vue 在 created 阶段读取 query 并请求数据created() { const { cityId } this.$route.query if (cityId) { this.fetchFuture(cityId) } }, watch: { $route.query.cityId(id) { if (id) this.fetchFuture(id) } }watch 的作用是处理同一组件内切换 query 的场景比如从/tianzhi?cityId101010100跳到/tianzhi?cityId101020100组件实例被复用created 不会重新执行只有 watch 能感知变化。这里如果把参数放到 Vuex 里就能实现“首页定位一次全站可用”配合第 3 章的 watch 监听两个页面之间的状态同步就闭环了。4.3 keep-alive与activated返回首页不重新定位一个实际痛点从 TianZhi 返回首页时HomeView 重新走一遍 created 里的定位流程用户会看到页面闪一下 loading。解决方案是在 App.vue 的 router-view 外层包 keep-alive并限定只缓存 HomeView。!-- App.vue -- template div idapp keep-alive includeHomeView router-view / /keep-alive /div /templateinclude 匹配的是组件 name 选项不是路由 name所以 HomeView.vue 里必须显式声明name: HomeView。缓存生效后HomeView 切换回来时不会重新加载定位数据这时页面中如果有“刷新天气”按钮要在 activated 钩子里触发数据刷新因为 activated 在每次进入缓存页面时都会执行created 却只执行一次。判断数据时效时可以对比 store 里最后更新时间与当前时间超过 10 分钟才重新请求兼顾体验和接口限流。5. 项目落地API Key隐藏、打包路径与请求缓存开发环境和生产环境最大的差异不在代码而在请求链路。第 2 章的 devServer.proxy 只在本地有效build 产物是纯静态文件直接部署后请求/devapi会落在业务服务器上必须在 Nginx 里补一段反向代理。# nginx.conf 中 server 块内部 location /devapi/ { proxy_pass https://devapi.qweather.com/; proxy_set_header Accept application/json; proxy_set_header X-QW-Api-Key YOUR_BACKEND_KEY; }Key 只出现在 Nginx 配置和服务器环境变量里浏览器端请求的是同源/devapi路径Network 面板中看不到任何和风天气域名相关的明文请求。如果连这个反代都不想做就只能把请求全部改到后端服务由后端统一拼 Key 后请求和风天气前端拿到的已经是处理完的 JSON。vue 打包后 布局异常是这类项目反馈率最高的问题多半不是样式写错而是路由模式匹配问题。开发环境用的是 history 模式URL 里没有#但 Nginx 没配置 try_files 时刷新/air页面会返回 404。解决方法是加一行try_files $uri $uri/ /index.html;或者在路由配置里改用 hash 模式代价是 URL 会多一个#对 SEO 影响微乎其微但对展示型项目更方便。最后是接口限流与缓存。和风天气免费版对 QPS 有限制天气数据本身短时间变化不大用 localStorage 缓存城市天气 10 分钟即可key 设计为weather_${cityId}_${type}type 区分 now、daily、air。缓存命中时直接返回不命中才走请求缓存里顺便存 updatedAt 时间戳供 activated 钩子判断是否刷新。验证整套链路时先用 curl 确认接口连通性curl -L -X GET \ https://devapi.qweather.com/v7/weather/now?location101010100keyYOUR_KEY \ -H Accept: application/json返回 JSON 中 code 为 200 且 now 字段存在说明 Key 有效再用 Vue Devtools 观察 store 中 weather 模块是否写入数据页面布局异常时优先检查路由 try_files 和 publicPath 相对路径。这样从开发到上线的每一步都有明确的检查点后续换城市逻辑或新增生活指数接口时沿着 store 的 commit 链路往上追即可。本文还有配套的精品资源点击获取