Geolocation API 基础
Geolocation API 允许网页在用户授权后获取设备的地理位置信息。它是 HTML5 的重要特性之一,广泛应用于地图定位、附近搜索、天气服务等场景。本节将介绍 Geolocation API 的基本用法、权限机制和错误处理。
前置知识
阅读本节前,建议先了解:Cookie 对比
基础概念
Geolocation API 概述
Geolocation API 通过 navigator.geolocation 对象提供位置服务。它可以获取设备的纬度、经度、海拔等地理信息,并支持一次性获取和持续追踪两种模式。
| 特性 | 说明 |
|---|---|
| API 对象 | navigator.geolocation |
| 安全要求 | 必须在安全上下文(HTTPS)中使用 |
| 用户授权 | 首次使用时需要用户同意 |
| 数据来源 | GPS、WiFi、IP 地址、蓝牙等 |
浏览器支持
| 浏览器 | 支持 | 版本 |
|---|---|---|
| Chrome | 支持 | 5.0+ |
| Firefox | 支持 | 3.5+ |
| Safari | 支持 | 5.0+ |
| Edge | 支持 | 12+ |
| IE | 支持 | 9.0+ |
| 移动端 | 支持 | Android 2.0+, iOS 3.0+ |
语法与 API
检测 API 可用性
javascript
// 检测 Geolocation API 是否可用
if ('geolocation' in navigator) {
console.log('Geolocation API 可用');
} else {
console.log('Geolocation API 不可用');
// 提示用户升级浏览器
}
// 更详细的检测
function checkGeolocationSupport() {
const result = {
supported: 'geolocation' in navigator,
secureContext: window.isSecureContext,
permission: null
};
// 检测权限状态
if (navigator.permissions) {
navigator.permissions.query({ name: 'geolocation' }).then(status => {
result.permission = status.state; // 'granted' | 'denied' | 'prompt'
console.log('Geolocation 状态:', result);
});
}
return result;
}获取当前位置 - getCurrentPosition
javascript
// 基本用法
navigator.geolocation.getCurrentPosition(
onSuccess, // 成功回调
onError, // 失败回调
options // 可选配置
);
// 成功回调
function onSuccess(position) {
console.log('位置获取成功:', position);
}
// 失败回调
function onError(error) {
console.error('位置获取失败:', error);
}
// 配置选项
const options = {
enableHighAccuracy: true, // 高精度模式
timeout: 10000, // 超时时间(毫秒)
maximumAge: 0 // 缓存有效期(毫秒)
};详细说明
权限机制
Geolocation API 必须获得用户授权才能获取位置。浏览器会弹出权限请求对话框:
javascript
// 权限状态查询
if (navigator.permissions) {
navigator.permissions.query({ name: 'geolocation' }).then(result => {
switch (result.state) {
case 'granted':
console.log('已授权,可以直接获取位置');
getLocation();
break;
case 'denied':
console.log('用户已拒绝,无法获取位置');
showDeniedMessage();
break;
case 'prompt':
console.log('未决定,将弹出授权请求');
break;
}
// 监听权限变化
result.addEventListener('change', () => {
console.log('权限状态变为:', result.state);
});
});
}错误处理
javascript
function onError(error) {
switch (error.code) {
case error.PERMISSION_DENIED:
// 用户拒绝了位置请求
console.error('用户拒绝了位置授权');
showMessage('请允许获取位置权限以使用此功能');
break;
case error.POSITION_UNAVAILABLE:
// 无法获取位置信息
console.error('位置信息不可用');
showMessage('无法获取您的位置,请检查定位服务');
break;
case error.TIMEOUT:
// 请求超时
console.error('获取位置超时');
showMessage('获取位置超时,请重试');
break;
default:
console.error('未知错误:', error.message);
showMessage('获取位置时发生未知错误');
}
}
// 错误对象属性
// error.code - 错误码(1=拒绝, 2=不可用, 3=超时)
// error.message - 错误描述配置选项详解
javascript
const options = {
// 高精度模式:使用 GPS(更精确但更耗电)
enableHighAccuracy: false,
// 超时时间:获取位置的最大等待时间
timeout: 10000, // 10 秒
// 缓存有效期:接受缓存位置的最大年龄
// 0 = 每次都获取新位置
// Infinity = 永远使用缓存
maximumAge: 300000 // 5 分钟
};| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enableHighAccuracy | boolean | false | 是否使用高精度(GPS) |
timeout | long | Infinity | 超时时间(毫秒) |
maximumAge | long | 0 | 缓存位置的最大年龄 |
实战示例
完整位置获取示例
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Geolocation API 基础演示</title>
<style>
body { font-family: -apple-system, sans-serif; padding: 20px; background: #f5f7fa; }
.geo-card {
max-width: 500px;
margin: 0 auto;
padding: 24px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h2 { text-align: center; color: #1a1a2e; }
.location-btn {
display: block;
width: 100%;
padding: 14px;
background: #1a73e8;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.location-btn:hover { background: #1557b0; }
.location-btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.result {
margin-top: 20px;
padding: 16px;
background: #f8f9fa;
border-radius: 8px;
display: none;
}
.result.show { display: block; }
.result-row {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.result-row:last-child { border-bottom: none; }
.result-label { color: #666; font-weight: 600; }
.result-value { color: #333; font-family: monospace; }
.message {
margin-top: 12px;
padding: 12px;
border-radius: 8px;
font-size: 14px;
display: none;
}
.message.show { display: block; }
.message.error { background: #fee2e2; color: #dc2626; }
.message.success { background: #d1fae5; color: #065f46; }
.message.info { background: #dbeafe; color: #2563eb; }
.status {
text-align: center;
padding: 8px;
color: #888;
font-size: 13px;
}
</style>
</head>
<body>
<div class="geo-card">
<h2>获取当前位置</h2>
<button class="location-btn" id="getLocationBtn" onclick="getLocation()">
获取我的位置
</button>
<div class="status" id="status"></div>
<div class="message" id="message"></div>
<div class="result" id="result"></div>
</div>
<script>
const btn = document.getElementById('getLocationBtn');
const status = document.getElementById('status');
const messageEl = document.getElementById('message');
const resultEl = document.getElementById('result');
function showMessage(text, type = 'info') {
messageEl.textContent = text;
messageEl.className = `message show ${type}`;
}
function hideMessage() {
messageEl.className = 'message';
}
// 检测 API 支持
if (!('geolocation' in navigator)) {
btn.disabled = true;
showMessage('您的浏览器不支持 Geolocation API', 'error');
}
// 检查 HTTPS
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
showMessage('Geolocation API 需要 HTTPS 协议', 'error');
}
function getLocation() {
hideMessage();
// 检查权限
if (navigator.permissions) {
navigator.permissions.query({ name: 'geolocation' }).then(result => {
if (result.state === 'denied') {
showMessage('您已拒绝位置权限,请在浏览器设置中开启', 'error');
return;
}
requestPosition();
});
} else {
requestPosition();
}
}
function requestPosition() {
btn.disabled = true;
status.textContent = '正在获取位置...';
const options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
}
function onSuccess(position) {
btn.disabled = false;
status.textContent = '';
const coords = position.coords;
showMessage('位置获取成功', 'success');
resultEl.className = 'result show';
resultEl.innerHTML = `
<div class="result-row">
<span class="result-label">纬度</span>
<span class="result-value">${coords.latitude.toFixed(6)}</span>
</div>
<div class="result-row">
<span class="result-label">经度</span>
<span class="result-value">${coords.longitude.toFixed(6)}</span>
</div>
<div class="result-row">
<span class="result-label">精度</span>
<span class="result-value">${coords.accuracy.toFixed(0)} 米</span>
</div>
<div class="result-row">
<span class="result-label">海拔</span>
<span class="result-value">${coords.altitude !== null ? coords.altitude.toFixed(0) + ' 米' : '不可用'}</span>
</div>
<div class="result-row">
<span class="result-label">速度</span>
<span class="result-value">${coords.speed !== null ? coords.speed.toFixed(1) + ' m/s' : '不可用'}</span>
</div>
<div class="result-row">
<span class="result-label">获取时间</span>
<span class="result-value">${new Date(position.timestamp).toLocaleString()}</span>
</div>
`;
console.log('完整位置对象:', position);
}
function onError(error) {
btn.disabled = false;
status.textContent = '';
switch (error.code) {
case error.PERMISSION_DENIED:
showMessage('用户拒绝了位置授权请求', 'error');
break;
case error.POSITION_UNAVAILABLE:
showMessage('无法获取位置信息,请检查设备定位服务', 'error');
break;
case error.TIMEOUT:
showMessage('获取位置超时,请检查网络或重试', 'error');
break;
default:
showMessage(`位置获取失败: ${error.message}`, 'error');
}
console.error('Geolocation 错误:', error);
}
</script>
</body>
</html>注意事项
HTTPS 要求
现代浏览器要求 Geolocation API 必须在安全上下文中使用:
| 环境 | 是否支持 |
|---|---|
https:// | 支持 |
http://localhost | 支持 |
http://127.0.0.1 | 支持 |
file:// | 部分浏览器支持 |
http://(其他域名) | 不支持 |
精度与耗电
| 模式 | 精度 | 耗电量 | 数据来源 |
|---|---|---|---|
| 高精度 (GPS) | ~10 米 | 高 | GPS 卫星 |
| 低精度 (WiFi/IP) | ~100-1000 米 | 低 | WiFi 热点、IP 地址 |
| 城市级 (IP) | ~公里级 | 极低 | IP 地理数据库 |
最佳实践
- 先检查权限状态,避免不必要的请求
- 设置合理的超时时间,提升用户体验
- 处理所有错误状态,提供友好的降级提示
- 不要频繁请求高精度定位,避免耗电
- 在 HTTPS 下使用,否则浏览器会拒绝
下一节
继续学习:获取位置信息