一、任务

雾霾的频繁出现已严重的影响到人们的出行,对人们的健康造成了重大影响。因此,能在出行前查看雾霾的指数,并采取相应的措施来把雾霾的影响降到最小就显得尤为重要。本系统在分析多种因子的影响下,设计一款手机端雾霾app探测系统。

二、要求

1.定位功能:将定位城市保存在服务器端,并同时显示在客户端。

2.界面设计:包含显示天气和空气质量指数的动态显示。

3.天气详情和空气质量指数:定位后的城市在服务器端获取后,传给天气详情界面,通过所传城市用百度天气api获取对应的天气详情和空气质量指数,并保存在服务器端。

4.完成报告。

三、说明

1.可以通过百度地图api获取对应的定位源代码和请求接口,获取定位数据,将定位城市保存在服务器端,并同时显示在客户端。

2. 天气详情和空气质量指数数据通过和风天气、墨迹天气、我的天气等均可获取,百度地图、高德地图等可以辅助位置信息。

3.界面设计可以是使用html语言,主要目的是为了解决因为手机像素的不同,显示结果的不同,用html5解决网页适配问题,手机像素的大小不影响显示效果。主要部分为定位,即header部分,Body部分。Body部分包含显示天气和空气质量指数的动态显示部分,湿度温度折线图。

正文

因为网上的比较旧且没有什么帮助,在自己捣鼓一个星期解决后决定写一篇来给大家提供一些思路。不会发源码,因为我也要验收,只提供思路和关键代码片段,仅适合打算自己写的同学。

使用web网页开发,技术栈:vue3+typescript+echarts+lodash-es

当然,你用传统三件套也是能写的

思路:

  1. 申请和风天气key和host
  2. 使用navigator.geolocation.getCurrentPosition获取用户位置信息location
  3. 根据host,key和location,结合和风天气api模板,发送正确请求,拿到json格式天气数据
  4. 对天气数据进行处理,展示至浏览器界面
  5. 编写样式

一、申请和风天气相关权限

网站:和风天气开发服务 ~ 强大、丰富的天气数据服务

注册后,在控制台左侧项目管理中,创建项目

创建名称后创建凭据,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中包含longitudelatitude

三、获取天气信息

因为不止从一个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行,我所展示的代码只是其中一部分,照搬肯定是不行的,你需要理解后转化到你的代码中。如果跟着写的过程中遇到实在解决不了的问题,可以评论留言或者私信我,如果看到我会回复的(虽然大概率不会看)。当然,实在解决不了我这也提供一条龙服务。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐