watcheffect 通过监听响应式位置状态自动触发异步天气请求,结合 abortcontroller 防竞态、isloading/error/weatherdata 状态管理加载与错误,并处理空值、权限拒绝、api 限频等边界情况。

watchEffect 本身不直接发起网络请求,但它能自动追踪响应式数据变化,并在变化时重新执行副作用函数——这正是实现“基于位置的实时天气更新”的理想机制。关键在于:把地理位置(如 latitude 和 longitude)设为响应式状态,用 watchEffect 监听它,内部触发异步天气请求,并妥善处理加载、错误与取消逻辑。
1. 响应式位置状态 + watchEffect 自动触发
先用 ref 或 reactive 存储位置坐标,确保它们是响应式的:
- 用户手动输入坐标、点击地图获取、或调用
navigator.geolocation获取当前位置 - 只要这些值更新(比如从“未定位”变为经纬度),watchEffect 就会立即重新运行
示例:
const location = reactive({ lat: null, lng: null });watchEffect(async (onInvalidate) => {
if (location.lat == null || location.lng == null) return;
// 后续发起请求...
});
2. 在 watchEffect 内安全发起异步请求
不能直接 await 整个 effect 函数(它必须同步返回),但可以在内部 async 执行请求,并用 onInvalidate 防止竞态问题:
- 每次新请求发起前,上一次未完成的请求应被标记为“过期”
- 使用
AbortController中断正在进行的 fetch,避免旧响应覆盖新结果 - 只在请求成功且未被取消时,才更新天气数据
示例片段:
let currentController;watchEffect(async (onInvalidate) => {
if (!location.lat || !location.lng) return;
currentController?.abort();
const controller = new AbortController();
currentController = controller;
onInvalidate(() => controller.abort()); // 取消旧请求
try {
const res = await fetch(
`/api/weather?lat=${location.lat}&lng=${location.lng}`,
{ signal: controller.signal }
);
if (!res.ok) throw new Error("Weather API failed");
weatherData.value = await res.json();
} catch (err) {
if (err.name !== "AbortError") console.error(err);
}
});
3. 结合加载与错误状态提升体验
仅更新数据不够,用户需要感知“正在加载中”或“定位失败”。建议维护三个响应式状态:
-
isLoading: ref(false)—— 请求开始设为 true,结束(无论成功失败)设为 false -
error: ref(null)—— 捕获并显示错误信息(如“无法获取该位置天气”) -
weatherData: ref(null)—— 仅在有效响应后赋值
这样模板中可自然渲染:v-if="isLoading">加载中...、v-else-if="error">{{ error }}、v-else>{{ weatherData?.temp }}°C
4. 注意边界情况:位置为空、权限拒绝、API 限频
真实场景中,location.lat/lng 可能为 null、0 或无效值;浏览器可能拒绝地理定位;天气 API 也可能返回 429(Too Many Requests)。因此:
- 在 watchEffect 开头加守卫判断,避免无效请求
- 对
navigator.geolocation.getCurrentPosition的错误做分类处理(如PERMISSION_DENIED提示用户开启权限) - 考虑添加简单节流(例如 30 秒内不重复请求同一位置),用
setTimeout+ 标记位控制
不复杂但容易忽略。核心就三点:位置响应化、effect 内发请求、用 onInvalidate 清理副作用。










