找到你在哪里!HTML5 地理位置 API
ko114 · · Tech. & Eng.
本作品采用 CC BY-NC-SA 4.0 授权。因为一些原因,文中出现的位置会被替换或模糊。
注意:如果你要试验地理位置 API,你的网页需要通过 HTTPS 提供。
原理
“找到你在哪里”这件事自古以来就是一个问题。
固然,地址可以表示“你在哪里”,但如果你不在陆地上,该如何定位呢?
所以我们使用经纬度来确定位置。这个概念大家在地理课上一定学过,所以不再赘述。在浏览器得到的度数为十进制记法,与角分法的转换方式如下:
对于低精度,目前一般采用 IP 定位:速度快,但精确度较低。
对于高精度,一般采用 GPS 或北斗定位:原理相似,通过三颗卫星测距计算位置,精度较高,但速度慢。
API
所有接口函数都位于 navigator.geolocation
中。确保浏览器支持:
if ('geolocation' in navigator) {
// 代码
} else {
alert("不支持地理位置 API。")
}
navigator.geolocation.getCurrentPosition(success, error, options)
:定位!成功后调用success
回调函数(传入位置),拒绝后调用error
回调函数(传入错误)。只有success
必选。navigator.geolocation.watchPosition(success, error, options)
:跟踪!参数同上。当你的位置变化时,调用回调函数。注意回调函数会被调用多次。返回一个值,代表watchID
。navigator.geolocation.clearWatch(watchID)
:取消跟踪。传入watchPosition
返回的值。options
:一个对象,满足以下任意条件:- 存在
enableHighAccuracy
布尔属性,表示是否使用精确定位,默认为false
; - 存在
timeout
属性,一个正整数,表示定位时限(单位:ms),默认为\infty (不限时); - 存在
maximumAge
属性,一个正整数,表示可接受的缓存位置的最大存在时间(单位:ms),默认为0 (不缓存);
- 存在
- 位置对象:具有
timestamp
属性,表示获取到位置时的时间戳;具有coords
属性,该属性内容如下:coords.latitude
:经度;coords.longitude
:纬度;coords.altitude
:海拔,单位为米,可能不存在;coords.accuracy
:位置的精确度,单位为米;coords.speed
:当前速度,单位为米每秒,可能不存在;coords.heading
:当前方向,0 为正北,角度制(如90 为正东等),可能不存在或为NaN
。编写
Step 0:准备
准备一个标准的 HTML 页面:
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>定位</title> </head> <body> <div> <p>你的经度:<span id="lat">不知道</span>,纬度:<span id="lon">不知道</span>,海拔约为 <span id="alt">?</span> 米。</p> <p>速度:<span id="spd"></span> m/s,方向:<span id="heading"></span>,位置精确到 <span id="ac"></span> m。</p> <p id='sw'></p> </div> <script> addEventListener('load', ev => { const lat = document.getElementById('lat'); const lon = document.getElementById('lon'); const alt = document.getElementById('alt'); const spd = document.getElementById('spd'); const hd = document.getElementById('heading'); const ac = document.getElementById('ac'); const sw = document.getElementById('sw'); if (navigator.geolocation) { // 代码 } }) </script> </body> </html>
Step 1:获取当前位置
添加如下代码:
navigator.geolocation.getCurrentPosition(cord=>{ lat.innerHTML = cord.coords.latitude; // 经度 lon.innerHTML = cord.coords.longitude; // 纬度 alt.innerHTML = cord.coords.altitude; // 海拔 spd.innerHTML = cord.coords.speed; // 速度 hd.innerHTML = cord.coords.heading; // 方向 ac.innerHTML = cord.coords.accuracy; // 精度 },console.log, {enableHighAccuracy:true});
为了防止跟踪,现代浏览器在脚本访问位置时都会弹出形如下图的对话框:
点击允许就可以了。如果没有显示,打开 F12 控制台看是否出错。效果如下:
Step 2:具体到在哪里
经纬度并不能直观确定位置。我们使用 OpenStreetMap 的免费 API(注:你需要能访问洛谷国际站才可使用):
// 放到顶层
async function getAddress(lat, lon) {
const url = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`;
try {
const response = await fetch(url, {
headers: { 'User-Agent': 'GeoTest/1.0 ([email protected])' } // 必须设置上你的邮箱!
});
const data = await response.json();
return data.display_name; // 完整地址字符串,对象中还有更多信息。
} catch (error) {
console.error("Geocoding error:", error); // 出错了!
return null;
}
}
// 放到回调函数中
getAddress(cord.coords.latitude, cord.coords.longitude).then(address => {
sw.innerText = address;
});
效果:
结语
浏览器自带的 API 是非常有限的,许多功能得靠不稳定的外部 API。
值得一提的是,由于某些因素,地理位置 API 得到的坐标系(WGS-84)并不是各大国内地图软件的坐标系(火星坐标)。要实现地图功能,需要转换坐标系,但“火星坐标”规则保密,较难实现。
Ref.
- MDN