2025西电B测雾霾探测系统设计(思路+核心代码)
一、任务
雾霾的频繁出现已严重的影响到人们的出行,对人们的健康造成了重大影响。因此,能在出行前查看雾霾的指数,并采取相应的措施来把雾霾的影响降到最小就显得尤为重要。本系统在分析多种因子的影响下,设计一款手机端雾霾app探测系统。
二、要求
1.定位功能:将定位城市保存在服务器端,并同时显示在客户端。
2.界面设计:包含显示天气和空气质量指数的动态显示。
3.天气详情和空气质量指数:定位后的城市在服务器端获取后,传给天气详情界面,通过所传城市用百度天气api获取对应的天气详情和空气质量指数,并保存在服务器端。
4.完成报告。
三、说明
1.可以通过百度地图api获取对应的定位源代码和请求接口,获取定位数据,将定位城市保存在服务器端,并同时显示在客户端。
2. 天气详情和空气质量指数数据通过和风天气、墨迹天气、我的天气等均可获取,百度地图、高德地图等可以辅助位置信息。
3.界面设计可以是使用html语言,主要目的是为了解决因为手机像素的不同,显示结果的不同,用html5解决网页适配问题,手机像素的大小不影响显示效果。主要部分为定位,即header部分,Body部分。Body部分包含显示天气和空气质量指数的动态显示部分,湿度温度折线图。
正文
因为网上的比较旧且没有什么帮助,在自己捣鼓一个星期解决后决定写一篇来给大家提供一些思路。不会发源码,因为我也要验收,只提供思路和关键代码片段,仅适合打算自己写的同学。
使用web网页开发,技术栈:vue3+typescript+echarts+lodash-es
当然,你用传统三件套也是能写的
思路:
- 申请和风天气key和host
- 使用navigator.geolocation.getCurrentPosition获取用户位置信息location
- 根据host,key和location,结合和风天气api模板,发送正确请求,拿到json格式天气数据
- 对天气数据进行处理,展示至浏览器界面
- 编写样式
一、申请和风天气相关权限
注册后,在控制台左侧项目管理中,创建项目
创建名称后创建凭据,JOSN Web Token或者API KEY都可以,第二个更简单,第一个更安全,我都创建了,具体过程参考官方的开发文档

后续发送请求需要的key不是上图的ID,而是点进去后的API KEY

二、浏览器定位
// 浏览器定位
const getLocation = () => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(pos) => resolve(pos.coords),
(err) => reject(err),
{ enableHighAccuracy: true, timeout: 5000 }
);
});
};
上面是一段示例代码,封装成函数方便调用,使用Promise返回结果
getCurrentPosition 方法有三个参数:
-
成功回调(
(pos) => resolve(pos.coords)): 如果位置获取成功,getCurrentPosition会调用第一个回调函数,并传入一个位置对象pos。位置对象包含了用户的经纬度信息。这里resolve(pos.coords)会将位置的坐标(pos.coords)作为参数传递给Promise的resolve方法,表示成功。 -
失败回调(
(err) => reject(err)): 如果获取位置失败(例如用户拒绝了位置权限,或发生了其他错误),getCurrentPosition会调用第二个回调函数,并传入一个错误对象err。这里reject(err)会将错误信息传递给Promise的reject方法,表示失败。 -
选项对象(
{ enableHighAccuracy: true, timeout: 5000 }): 这是第三个可选参数,它是一个配置对象,包含两个选项:enableHighAccuracy: true:启用高精度模式,。timeout: 5000:设置获取位置的最大超时时间为 5000 毫秒。如果 5 秒内没有获取到位置,则会触发错误回调。
然后在初始化里,使用const coords = await getLocation();拿到定位信息,
coords中包含longitude和latitude
三、获取天气信息
因为不止从一个api处申请数据,先对API进行封装
// API 请求封装
const fetchData = async (url) => {
const response = await fetch(url, {
headers: {
"请求标头": "你的API KEY",
//如果是JWT请求,请求标头是 Authorization: Bearer
//如果是API KEY,请求标头是 X-QW-Api-Key
"Cache-Control": "max-age=7200, stale-while-revalidate=3600",
//缓存策略,防止短时间的大量请求,因为天气数据并不需要非常新鲜
},
// cache: "force-cache", // 如有必要可以开启,强制使用浏览器缓存
});
if (!response.ok) throw new Error("网络请求失败");
return response.json();
};
然后是发送GET请求,这里我拿获取实时天气(实时天气 for API | 和风天气开发服务)和
实时空气质量(new)(实时空气质量(new) for API | 和风天气开发服务)为例
// 获取数据
const getWeatherData = async (coords) => {//coords就是定位信息
try {
const [weatherRes, airRes] = await Promise.all([
fetchData(
`https://{你的HOST}/v7/weather/now?location=${coords.longitude},${coords.latitude}`
),
fetchData(
`https://{你的HOST}/airquality/v1/current/${coords.latitude}/${coords.longitude}`
),
]);
processWeatherData(weatherRes);//处理实时天气数据
processAirData(airRes);//处理空气质量数据
} catch (err) {
error.value = `数据获取失败: ${err.message}`;
}
};
你会发现,两者的请求url格式不太一致,
一个是location=经度,纬度;另一个是/纬度/经度
所以不同数据的请求参数不同,请自己查看相应开发文档

不出意外,你应该能拿到请求返回的数据,格式如下


出了意外也是正常的,自己使出浑身解数去想办法解决
四、数据处理与展示
最难的部分解决了,剩下的想必大家也能信手拈来,我就不过多赘述。
返回数据并不是都用得上,想准确无误拿到想要的数据,首先就需要清楚知道响应数据格式。
比方说上面第一张里的温度temp的值28,就需要data.now.temp获取;
而第二张里的PM2.5的值40,就需要data.indexes[0].pollutants[0].concentration.value获取。
data是返回的整个数据对象。
数据的管理,我使用的是vue3的ref,动态更新,双向绑定。
// 例如对天气数据的处理
const weather = ref({//一开始都是'--',防止没有值时的空值报错,提升代码健壮
temp: "--",
feelsLike: "--",
humidity: "--",
wind: "--",
pressure: "--",
visibility: "--",
condition: "--",
icon: "",
updateTime: "--",
});
const processWeatherData = (data) => {
if (data.code !== "200") throw new Error("天气数据无效");
weather.value = {
temp: data.now.temp,
feelsLike: data.now.feelsLike,
humidity: data.now.humidity,
wind: `${data.now.windDir} ${data.now.windScale}级`,
pressure: `${data.now.pressure} hPa`,
visibility: `${data.now.vis} 公里`,
condition: data.now.text,
updateTime: data.updateTime.replace("T", " ").split("+")[0],
};
};
然后就可以在html中使用这些数据
<!-- 主要天气信息 -->
<div class="main-weather">
<div class="temperature-group">
<div class="current-temp">{{ weather.temp }}°C</div>
<div class="condition">{{ weather.condition }}</div>
</div>
<div class="feels-like">体感 {{ weather.feelsLike }}°C</div>
</div>
<!-- 详细数据网格 -->
<div class="detail-grid">
<div class="detail-item">
<label>湿度</label>
<span class="value">{{ weather.humidity }}%</span>
</div>
<div class="detail-item">
<label>风速</label>
<span class="value">{{ weather.wind }}</span>
</div>
<div class="detail-item">
<label>气压</label>
<span class="value">{{ weather.pressure }}</span>
</div>
<div class="detail-item">
<label>能见度</label>
<span class="value">{{ weather.visibility }}</span>
</div>
</div>
五、样式设计
想省事就大模型帮写,没那么好看也没那么难看,而且不是生成就能直接用,你自己肯定还是要改一改bug之类的。对于这种有复杂嵌套的布局,我推荐用sass去写,它的关系级更符合自觉,比css好用。
除了自己写基本样式,还可以用插件生成一些好看的组件,比如Echarts(Apache ECharts)
我用Echarts创建了温度和湿度的折线图

为了保证手机端和pc端都能正常浏览,我还做了双端适配,有余力也可以试试。


整个项目代码接近700行,我所展示的代码只是其中一部分,照搬肯定是不行的,你需要理解后转化到你的代码中。如果跟着写的过程中遇到实在解决不了的问题,可以评论留言或者私信我,如果看到我会回复的(虽然大概率不会看)。当然,实在解决不了我这也提供一条龙服务。
更多推荐


所有评论(0)