返回 AiToEarn
useGeolocation.ts
根目录 / project / aitoearn-web / src / hooks / useGeolocation.ts
1 /**
2 * useGeolocation - 获取用户地理位置 Hook
3 * 使用浏览器 Geolocation API 获取用户当前位置
4 */
5
6 import { useCallback, useEffect, useState } from 'react'
7
8 export interface GeolocationState {
9 /** 纬度 */
10 latitude: number | null
11 /** 经度 */
12 longitude: number | null
13 /** 精度(米) */
14 accuracy: number | null
15 /** 错误信息 */
16 error: string | null
17 /** 是否正在加载 */
18 loading: boolean
19 }
20
21 export interface UseGeolocationOptions {
22 /** 是否在挂载时自动获取位置 */
23 enableOnMount?: boolean
24 /** 位置精度要求 */
25 enableHighAccuracy?: boolean
26 /** 超时时间(毫秒) */
27 timeout?: number
28 /** 缓存时间(毫秒) */
29 maximumAge?: number
30 }
31
32 const defaultOptions: UseGeolocationOptions = {
33 enableOnMount: false, // 默认不自动获取,由调用方决定时机
34 enableHighAccuracy: false,
35 timeout: 10000,
36 maximumAge: 5 * 60 * 1000, // 5分钟缓存
37 }
38
39 /**
40 * 获取用户地理位置
41 * @param options 配置选项
42 * @returns 地理位置状态和刷新方法
43 */
44 export function useGeolocation(options: UseGeolocationOptions = {}) {
45 const { enableOnMount, enableHighAccuracy, timeout, maximumAge } = {
46 ...defaultOptions,
47 ...options,
48 }
49
50 const [state, setState] = useState<GeolocationState>({
51 latitude: null,
52 longitude: null,
53 accuracy: null,
54 error: null,
55 loading: false,
56 })
57
58 const getPosition = useCallback(() => {
59 // 检查浏览器是否支持 Geolocation
60 if (!navigator.geolocation) {
61 setState(prev => ({
62 ...prev,
63 error: 'Geolocation is not supported by this browser',
64 loading: false,
65 }))
66 return
67 }
68
69 setState(prev => ({ ...prev, loading: true, error: null }))
70
71 navigator.geolocation.getCurrentPosition(
72 (position) => {
73 setState({
74 latitude: position.coords.latitude,
75 longitude: position.coords.longitude,
76 accuracy: position.coords.accuracy,
77 error: null,
78 loading: false,
79 })
80 },
81 (error) => {
82 let errorMessage: string
83 switch (error.code) {
84 case error.PERMISSION_DENIED:
85 errorMessage = 'User denied the request for geolocation'
86 break
87 case error.POSITION_UNAVAILABLE:
88 errorMessage = 'Location information is unavailable'
89 break
90 case error.TIMEOUT:
91 errorMessage = 'The request to get user location timed out'
92 break
93 default:
94 errorMessage = 'An unknown error occurred'
95 }
96 setState(prev => ({
97 ...prev,
98 error: errorMessage,
99 loading: false,
100 }))
101 },
102 {
103 enableHighAccuracy,
104 timeout,
105 maximumAge,
106 },
107 )
108 }, [enableHighAccuracy, timeout, maximumAge])
109
110 // 挂载时自动获取位置
111 useEffect(() => {
112 if (enableOnMount) {
113 getPosition()
114 }
115 }, [enableOnMount, getPosition])
116
117 return {
118 ...state,
119 /** 刷新位置 */
120 refresh: getPosition,
121 }
122 }
123
123 lines TYPESCRIPT