geolocationUtils.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /**
  2. * 地理定位工具函数模块
  3. * 提供浏览器定位相关的通用工具函数
  4. *
  5. * 主要功能:
  6. * - 浏览器定位 API 封装
  7. * - 定位错误处理
  8. * - HTTPS 环境检测
  9. */
  10. /**
  11. * 检查是否为安全上下文(HTTPS)
  12. * @returns {boolean} 是否为安全上下文
  13. */
  14. export function isSecureContext() {
  15. // #ifdef H5
  16. if (typeof window !== 'undefined' && window.location) {
  17. return window.isSecureContext || window.location.protocol === 'https:'
  18. }
  19. // #endif
  20. return false
  21. }
  22. /**
  23. * 检查浏览器是否支持定位
  24. * @returns {boolean} 是否支持定位
  25. */
  26. export function isGeolocationSupported() {
  27. // #ifdef H5
  28. return typeof navigator !== 'undefined' && 'geolocation' in navigator
  29. // #endif
  30. // #ifndef H5
  31. return false
  32. // #endif
  33. }
  34. /**
  35. * 获取当前位置
  36. * 使用浏览器 Geolocation API
  37. * @param {Object} options 定位选项
  38. * @returns {Promise<{longitude: number, latitude: number}>} 定位结果
  39. */
  40. export function getCurrentPosition(options = {}) {
  41. return new Promise((resolve, reject) => {
  42. // #ifdef H5
  43. if (!isGeolocationSupported()) {
  44. reject(new Error('浏览器不支持定位功能'))
  45. return
  46. }
  47. const defaultOptions = {
  48. enableHighAccuracy: true,
  49. timeout: 10000,
  50. maximumAge: 0,
  51. ...options
  52. }
  53. navigator.geolocation.getCurrentPosition(
  54. (position) => {
  55. resolve({
  56. longitude: position.coords.longitude,
  57. latitude: position.coords.latitude,
  58. accuracy: position.coords.accuracy,
  59. timestamp: position.timestamp
  60. })
  61. },
  62. (error) => {
  63. reject(error)
  64. },
  65. defaultOptions
  66. )
  67. // #endif
  68. // #ifndef H5
  69. reject(new Error('当前平台不支持浏览器定位 API'))
  70. // #endif
  71. })
  72. }
  73. /**
  74. * 解析定位错误
  75. * @param {GeolocationPositionError} error 定位错误对象
  76. * @returns {Object} 包含 message 和 detail 的错误信息对象
  77. */
  78. export function parseGeolocationError(error) {
  79. let errorMsg = '定位失败'
  80. let errorDetail = ''
  81. // #ifdef H5
  82. if (error && typeof error.code === 'number') {
  83. switch(error.code) {
  84. case 1: // PERMISSION_DENIED
  85. errorMsg = '定位权限被拒绝'
  86. errorDetail = '请在浏览器设置中允许定位权限。'
  87. // 检查 HTTPS 环境
  88. if (!isSecureContext()) {
  89. errorDetail += ' 注意:HTTP 环境下浏览器可能会直接拒绝定位请求,建议使用 HTTPS 访问。'
  90. }
  91. break
  92. case 2: // POSITION_UNAVAILABLE
  93. errorMsg = '位置信息不可用'
  94. errorDetail = '请检查 GPS 或网络连接,确保设备定位服务已开启。'
  95. break
  96. case 3: // TIMEOUT
  97. errorMsg = '定位请求超时'
  98. errorDetail = '定位请求超过设定时间未响应,请重试或检查网络连接。'
  99. break
  100. default:
  101. errorMsg = '定位失败'
  102. errorDetail = error.message || '未知错误'
  103. }
  104. } else if (error && error.message) {
  105. errorMsg = '定位失败'
  106. errorDetail = error.message
  107. }
  108. // #endif
  109. return {
  110. message: errorMsg,
  111. detail: errorDetail,
  112. code: error?.code
  113. }
  114. }
  115. /**
  116. * 监听位置变化
  117. * @param {Function} successCallback 成功回调
  118. * @param {Function} errorCallback 错误回调
  119. * @param {Object} options 定位选项
  120. * @returns {number|null} watchId,用于停止监听
  121. */
  122. export function watchPosition(successCallback, errorCallback, options = {}) {
  123. // #ifdef H5
  124. if (!isGeolocationSupported()) {
  125. if (errorCallback) {
  126. errorCallback(new Error('浏览器不支持定位功能'))
  127. }
  128. return null
  129. }
  130. const defaultOptions = {
  131. enableHighAccuracy: true,
  132. timeout: 10000,
  133. maximumAge: 0,
  134. ...options
  135. }
  136. return navigator.geolocation.watchPosition(
  137. (position) => {
  138. if (successCallback) {
  139. successCallback({
  140. longitude: position.coords.longitude,
  141. latitude: position.coords.latitude,
  142. accuracy: position.coords.accuracy,
  143. timestamp: position.timestamp
  144. })
  145. }
  146. },
  147. (error) => {
  148. if (errorCallback) {
  149. errorCallback(error)
  150. }
  151. },
  152. defaultOptions
  153. )
  154. // #endif
  155. // #ifndef H5
  156. if (errorCallback) {
  157. errorCallback(new Error('当前平台不支持浏览器定位 API'))
  158. }
  159. return null
  160. // #endif
  161. }
  162. /**
  163. * 停止监听位置变化
  164. * @param {number} watchId watchPosition 返回的 ID
  165. */
  166. export function clearWatch(watchId) {
  167. // #ifdef H5
  168. if (watchId !== null && watchId !== undefined && isGeolocationSupported()) {
  169. navigator.geolocation.clearWatch(watchId)
  170. }
  171. // #endif
  172. }