
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>选择收货地址</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
body {
background-color: #f5f7fa;
font-size: 15px;
color: #333;
padding-bottom: 84px;
}
/* 顶部搜索栏 */
.search-bar {
background: #fff;
padding: 12px 16px;
display: flex;
gap: 10px;
align-items: center;
position: sticky;
top:0;
z-index:100;
box-shadow: 0 1px 6px rgba(0,0,0,0.05);
}
.search-bar input {
flex:1;
border: 1px solid #e5e7eb;
border-radius: 24px;
padding: 10px 16px;
font-size:15px;
}
.search-bar input:focus {
outline:none;
border-color:#0066cc;
}
.search-bar button {
background:#0066cc;
color:#fff;
border:none;
border-radius:24px;
padding: 10px 14px;
font-size:14px;
}
/* 地图容器 + 中心定位大头针(打车样式) */
.map-wrap {
position:relative;
width:100%;
height: 200px;
}
#mapDiv {
width:100%;
height:100%;
}
.map-pin {
position:absolute;
left:50%;
top:50%;
transform: translate(-50%, -100%);
font-size:36px;
pointer-events:none;
z-index:900;
}
/* 重新定位悬浮按钮 */
.btn-refresh-loc {
position:absolute;
right:14px;
bottom:14px;
width:44px;
height:44px;
border-radius:50%;
background:#fff;
box-shadow:0 2px 8px rgba(0,0,0,0.15);
border:none;
font-size:20px;
z-index:900;
}
/* 卡片 */
.card {
background:#fff;
border-radius:12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
margin:12px 12px;
overflow:hidden;
}
.card-header {
padding:14px 16px;
font-size:16px;
font-weight:600;
border-bottom:1px solid #f2f2f2;
}
.card-body {
padding:16px;
}
.form-item {
margin-bottom:14px;
}
.form-item label {
display:block;
font-size:14px;
color:#666;
margin-bottom:6px;
}
.form-item input {
width:100%;
border:1px solid #e5e7eb;
border-radius:10px;
padding:8px 14px;
font-size:15px;
}
.form-item input:focus {
outline:none;
border-color:#0066cc;
}
.row-three {
display:flex;
gap:8px;
}
.row-three .form-item {
flex:1;
margin-bottom:0;
}
.row-three input {
padding:10px 8px;
font-size:14px;
}
/* 底部提交 */
.btn-submit {
position:fixed;
left:16px;
right:16px;
bottom:16px;
background:#ff6b35;
color:#fff;
border:none;
border-radius:12px;
padding:14px 0;
font-size:17px;
font-weight:600;
}
.btn-submit:active {
background:#e65c2b;
}
/* Toast */
.toast {
position:fixed;
left:50%;
top:40%;
transform:translate(-50%,-50%);
background:rgba(0,0,0,0.72);
color:#fff;
padding:10px 18px;
border-radius:8px;
font-size:14px;
z-index:9999;
display:none;
}
.tip-desc {
text-align:center;
color:#999;
font-size:13px;
padding:8px 0;
}
</style>
<!-- 天地图JS4.0 官方引入 -->
<script src="https://api.tianditu.gov.cn/api?v=4.0&tk=98dbc34f1a1a583022c722ff951a465d"></script>
</head>
<body>
<!-- 搜索区域 -->
<div class="search-bar">
<input id="searchInput" placeholder="输入地址搜索,例如:重庆市渝北区XX小区">
<button id="searchBtn">搜索</button>
</div>
<!-- 地图区域 打车风格:中心大头针 -->
<div class="map-wrap">
<div id="mapDiv"></div>
<div class="map-pin">📍</div>
<button class="btn-refresh-loc" id="refreshLocBtn">🎯</button>
</div>
<div class="tip-desc">拖动地图选择位置,自动识别地址</div>
<!-- 收货表单 -->
<div class="card">
<div class="card-header">收货信息</div>
<div class="card-body">
<div class="form-item">
<label>收货人</label>
<input type="text" id="name" placeholder="请输入姓名">
</div>
<div class="form-item">
<label>手机号码</label>
<input type="tel" id="phone" placeholder="请输入手机号">
</div>
<div class="row-three">
<div class="form-item">
<label>省</label>
<input type="text" id="province" readonly>
</div>
<div class="form-item">
<label>市</label>
<input type="text" id="city" readonly>
</div>
<div class="form-item">
<label>区/县</label>
<input type="text" id="district" readonly>
</div>
</div>
<div class="form-item" style="margin-top:14px;">
<label>详细地址</label>
<input type="text" id="address" placeholder="街道、小区、门牌号">
</div>
</div>
</div>
<button class="btn-submit" id="submitBtn">保存收货地址</button>
<div class="toast" id="toast"></div>
<script>
const TK = "98dbc34f1a1a583022c722ff951a465d";
let map;
const toastDom = document.getElementById('toast');
const searchInput = document.getElementById('searchInput');
const searchBtn = document.getElementById('searchBtn');
const refreshLocBtn = document.getElementById('refreshLocBtn');
// toast提示
function showToast(msg, time=2000) {
toastDom.innerText = msg;
toastDom.style.display = "block";
setTimeout(()=>{
toastDom.style.display = "none";
}, time)
}
// 初始化地图
function initMap() {
map = new T.Map("mapDiv");
const initCenter = new T.LngLat(116.404,39.915);
map.centerAndZoom(initCenter,12);
// 地图拖动结束,取中心点经纬度,逆解析地址(核心!打车模式)
map.addEventListener("moveend", function(){
const center = map.getCenter();
getAddressByLngLat(center.lng, center.lat);
})
}
// 【逆地理编码】经纬度 → 省市区地址(官方接口)
function getAddressByLngLat(lon, lat) {
const url = `https://api.tianditu.gov.cn/geocoder?postStr={"lon":${lon},"lat":${lat},"ver":1}&type=geocode&tk=${TK}`;
fetch(url)
.then(res=>res.json())
.then(json=>{
if(json.status !== "0"){
return;
}
const r = json.result;
document.getElementById("province").value = r.addressComponent.province || "";
document.getElementById("city").value = r.addressComponent.city || "";
if(r.addressComponent.city=="")
{
document.getElementById("city").value = r.addressComponent.province || "";
}
document.getElementById("district").value = r.addressComponent.county || "";
document.getElementById("address").value = r.addressComponent.address || "";
})
.catch(err=>{
console.error("逆编码错误",err);
})
}
// 【地理编码】地址搜索 → 经纬度(官方接口)
function searchAddress(keyword) {
if(!keyword.trim()) return showToast("请输入地址");
showToast("正在搜索...",9999);
const url = `https://api.tianditu.gov.cn/geocoder?ds={"keyWord":"${keyword}"}&tk=${TK}`;
fetch(url)
.then(res=>res.json())
.then(json=>{
if(json.status !== "0"){
showToast("未找到该地址");
return;
}
const loc = json.location;
const point = new T.LngLat(loc.lon, loc.lat);
map.centerAndZoom(point,16);
showToast("定位成功");
})
.catch(err=>{
showToast("搜索失败");
console.error(err);
})
}
// GPS定位(自动定位 + 重新定位按钮共用)
function getGpsLocation() {
if(!navigator.geolocation){
showToast("浏览器不支持定位");
return;
}
showToast("正在获取您的位置...",9999);
navigator.geolocation.getCurrentPosition(pos=>{
const lon = pos.coords.longitude;
const lat = pos.coords.latitude;
const point = new T.LngLat(lon, lat);
map.centerAndZoom(point,16);
showToast("定位成功");
},err=>{
let msg;
if(err.code === 1) msg="定位权限被拒绝,请在浏览器允许位置权限";
else if(err.code ===2) msg="定位失败,信号弱";
else msg="定位超时";
showToast(msg);
},{enableHighAccuracy:true,timeout:12000})
}
// 保存地址
document.getElementById('submitBtn').onclick = function(){
const data = {
name: document.getElementById('name').value.trim(),
phone: document.getElementById('phone').value.trim(),
province: document.getElementById('province').value,
city: document.getElementById('city').value,
district: document.getElementById('district').value,
address: document.getElementById('address').value
}
if(!data.name) return showToast("请填写收货人姓名");
if(!data.phone) return showToast("请填写手机号");
if(!data.address) return showToast("请选择地址");
showToast("地址保存成功!");
console.log("收货地址数据", data);
// 这里可以ajax提交后端
}
// 绑定事件
window.onload = function(){
initMap();
// 页面加载【自动触发GPS定位】
getGpsLocation();
// 搜索按钮
searchBtn.onclick = ()=> searchAddress(searchInput.value);
// 回车搜索
searchInput.onkeydown = (e)=>{
if(e.key === 'Enter') searchAddress(searchInput.value);
}
// 重新定位按钮
refreshLocBtn.onclick = getGpsLocation;
}
</script>
</body>
</html>
本文介绍一个基于天地图API的收货地址选择页面,集成搜索、地图定位、自动逆地理编码功能。用户可通过输入地址搜索或拖动地图选择位置,系统自动识别省市区及详细地址。支持GPS定位与重新定位,表单填写后可保存收货信息,界面简洁,适配移动端,提升地址录入效率。