meng-weather-daily-kit
v1.1.0
Published
获取当日天气 + 经纬度 + 当前时间戳的跨框架 npm 包,支持 Vanilla JS / Vue / React
Maintainers
Readme
meng-weather-daily-kit
获取当日天气 + 经纬度 + 当前时间戳的跨框架 npm 包,支持 Vanilla JS / Vue / React。
功能特点
- 调用 OpenWeatherMap API 获取实时天气数据
- 自动返回城市经纬度坐标
- 内置当前时间戳(本地生成,不依赖网络)
- 零运行时依赖,纯原生 API(fetch / AbortController / Intl)
- ESM + CJS 双格式,
import/require均可使用 - 完整 TypeScript 类型定义
- 内存缓存(默认 10 分钟 TTL),避免重复请求
- 请求去重:并发调用同一城市只发一次网络请求
- 9 种分类错误类,方便精确捕获和处理异常
安装
npm i meng-weather-daily-kit快速开始
Vanilla JS (ESM)
import { getDailyWeather } from "meng-weather-daily-kit";
const result = await getDailyWeather({
city: "北京",
apiKey: "your-openweathermap-api-key",
});
console.log(result);
// {
// weather: { city: '北京', temperature: 22, feelsLike: 20, ... },
// location: { latitude: 39.9042, longitude: 116.4074 },
// timestamp: 1742496000000,
// date: '2026-05-20'
// }React
import { useState, useEffect } from "react";
import { getDailyWeather } from "meng-weather-daily-kit";
function WeatherCard() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
getDailyWeather({
city: "上海",
apiKey: import.meta.env.VITE_WEATHER_API_KEY,
})
.then(setData)
.catch(setError);
}, []);
if (error) return <div>加载失败: {error.message}</div>;
if (!data) return <div>加载中...</div>;
return (
<div>
<h1>{data.weather.city}</h1>
<p>温度: {data.weather.temperature}°C</p>
<p>天气: {data.weather.description}</p>
<p>
纬度: {data.location.latitude}, 经度: {data.location.longitude}
</p>
</div>
);
}Vue 3 (Composition API)
<template>
<div v-if="error">{{ error.message }}</div>
<div v-else-if="data">
<h1>{{ data.weather.city }}</h1>
<p>{{ data.weather.temperature }}°C · {{ data.weather.description }}</p>
<small>{{ data.location.latitude }}, {{ data.location.longitude }}</small>
</div>
<div v-else>加载中...</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { getDailyWeather } from "meng-weather-daily-kit";
const data = ref(null);
const error = ref(null);
onMounted(async () => {
try {
data.value = await getDailyWeather({
city: "广州",
apiKey: import.meta.env.VITE_WEATHER_API_KEY,
});
} catch (e) {
error.value = e;
}
});
</script>API 参考
getDailyWeather(options) => Promise<DailyWeatherResult>
获取指定城市的当日天气、经纬度和时间戳。
参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| ---------- | ------------------------ | ---- | ---------- | ---------------------- |
| city | string | 是 | - | 城市名称,支持中英文 |
| apiKey | string | 是 | - | OpenWeatherMap API Key |
| unit | 'metric' \| 'imperial' | 否 | 'metric' | 温度单位:摄氏/华氏 |
| lang | string | 否 | 'zh_cn' | 天气描述语言 |
| cacheTTL | number | 否 | 600000 | 缓存有效期(毫秒) |
返回值 DailyWeatherResult
{
weather: {
city: string; // 城市名
temperature: number; // 温度(根据 unit 决定单位)
feelsLike: number; // 体感温度
humidity: number; // 湿度 (%)
windSpeed: number; // 风速
description: string; // 天气描述文字
type: WeatherType; // 天气类型枚举
}
location: {
latitude: number; // 纬度
longitude: number; // 经度
}
timestamp: number; // 当前时间戳 (ms)
date: string; // 当前日期 yyyy-MM-dd
}天气类型 WeatherType
| 值 | 含义 |
| ---------------- | ---- |
| 'sunny' | 晴天 |
| 'cloudy' | 多云 |
| 'rainy' | 雨 |
| 'snowy' | 雪 |
| 'foggy' | 雾 |
| 'thunderstorm' | 雷暴 |
| 'windy' | 大风 |
getTimestamp() => TimestampResult
纯本地函数,无需网络请求,返回当前时间信息。
import { getTimestamp } from "meng-weather-daily-kit";
const ts = getTimestamp();
// { timestamp: 1742496000000, date: '2026-05-20', iso: '2026-05-20T...', timezone: 'Asia/Shanghai' }| 字段 | 类型 | 说明 |
| ----------- | -------- | ----------------- |
| timestamp | number | 毫秒时间戳 |
| date | string | 日期 yyyy-MM-dd |
| iso | string | ISO 8601 格式 |
| timezone | string | 系统时区标识 |
clearCache() => void
清除内存缓存和去重队列。在需要强制刷新数据时调用。
import { clearCache } from "meng-weather-daily-kit";
clearCache();错误处理
所有错误继承自 WeatherKitError,包含 code 属性便于程序化判断:
| 错误类 | code | 触发场景 |
| ---------------------- | ---------------------- | ---------------------------------------- |
| ConfigurationError | CONFIGURATION_ERROR | city 或 apiKey 缺失或格式错误 |
| AuthenticationError | AUTHENTICATION_ERROR | API Key 无效 (HTTP 401) |
| WeatherNotFoundError | WEATHER_NOT_FOUND | 城市未找到 (HTTP 404) |
| RateLimitError | RATE_LIMIT_ERROR | 请求频率超限 (HTTP 429),含 retryAfter |
| ApiError | API_ERROR | 服务端错误 (HTTP 5xx),含 statusCode |
| NetworkError | NETWORK_ERROR | 网络连接失败 |
| TimeoutError | TIMEOUT_ERROR | 请求超时(默认 5 秒) |
| ParseError | PARSE_ERROR | 响应 JSON 解析失败 |
| EnvironmentError | ENVIRONMENT_ERROR | 运行环境不支持 fetch |
使用示例
import {
getDailyWeather,
ConfigurationError,
AuthenticationError,
WeatherNotFoundError,
RateLimitError,
NetworkError,
} from "meng-weather-daily-kit";
try {
const result = await getDailyWeather({ city: "北京", apiKey: "xxx" });
} catch (e) {
if (e instanceof ConfigurationError) {
console.error("配置错误:", e.message);
} else if (e instanceof AuthenticationError) {
console.error("API Key 无效");
} else if (e instanceof WeatherNotFoundError) {
console.error("找不到该城市");
} else if (e instanceof RateLimitError) {
console.error("限流了", e.retryAfter, "秒后重试");
} else if (e instanceof NetworkError) {
console.error("网络问题", e.cause);
}
}获取 OpenWeatherMap API Key
- 访问 https://openweathermap.org/api 注册账号
- 进入 My API keys 页面
- 复制你的 API Key(免费套餐支持每分钟 60 次调用)
技术架构
用户调用 getDailyWeather()
│
▼
┌─ validateOptions() ───── 配置校验
│
├─ cache.get() ─────────── 命中缓存直接返回
│
├─ dedup.dedup() ───────── 并发去重(同一 key 只发一次请求)
│ │
│ ▼
│ buildUrl() ─────────── 构建 OpenWeatherMap 请求 URL
│ httpRequest() ─────── fetch 封装(超时 5s / 重试 1 次 / 错误分类)
│ mapResponse() ─────── 将 API 响应映射为 DailyWeatherResult
│ cache.set() ───────── 写入缓存
│
▼
返回 DailyWeatherResult核心模块
| 文件 | 职责 |
| ------------------------ | -------------------------------------------------------- |
| src/getDailyWeather.ts | 主函数入口,串联校验、缓存、去重、请求、映射 |
| src/http.ts | fetch 封装:超时控制、自动重试、HTTP 状态码 → 错误类映射 |
| src/cache.ts | MemoryCache 泛型类,TTL 过期机制 |
| src/dedup.ts | RequestDedup 泛型类,Promise 合并去重 |
| src/weatherTypeMap.ts | OpenWeatherMap icon code → WeatherType 枚举映射表 |
| src/getTimestamp.ts | 纯本地时间戳生成,零依赖 |
| src/types.ts | 所有接口定义 + 9 种错误类 |
测试
# 运行全部测试(44 个用例)
npm test
# 监听模式
npm run test:watch
# 类型检查
npm run typecheck测试覆盖范围
| 测试文件 | 用例数 | 覆盖内容 |
| ------------------------- | ------ | ---------------------------------------------------------------------------- |
| getDailyWeather.test.ts | 18 | 正常请求、中英文城市、字段完整性、单位切换、缓存命中、并发去重、所有错误类型 |
| getTimestamp.test.ts | 6 | 字段完整性、时间精度、日期格式、ISO 格式、时区检测 |
| cache.test.ts | 8 | 存取、过期淘汰、自定义 TTL、has/delete/clear/size |
| dedup.test.ts | 5 | 并发合并、不同 key 并行、完成/拒绝后清理 |
| weatherTypeMap.test.ts | 7 | 全部 17 个 icon 映射 + 未知 icon 兜底 |
测试边界说明
| 边界项 | 说明 |
| ---------------- | ----------------------------------------------------------------------------------------- |
| 环境依赖 | 测试使用 vi.fn() mock fetch,不发送真实网络请求;真实 API 调用需有效 API Key |
| API 数据源 | 依赖 OpenWeatherMap 免费层,有速率限制(60 次/分钟),超出会触发 RateLimitError |
| 浏览器兼容性 | 使用 fetch / AbortController / Intl / URLSearchParams,需现代浏览器或 Node.js 18+ |
| 缓存一致性 | 多进程/多实例间缓存不共享,仅进程内内存级别 |
| 时区精度 | getTimestamp() 的 timezone 来自运行环境,服务端可能返回 UTC |
发布流程
# 1. 更新版本号(patch / minor / major)
npm version patch
# 2. 构建 + 自动发布
npm publish
# 或手动分步:
npm run build
npm publish --access publicLicense
MIT
