PC WEB端新增客户的时候需要填写客户地址和联系人信息,包括:省市区、街道、详细地址和经纬度以及联系人、固话和移动电话。获取客户地址信息之前用的是百度地图,由于小程序中客户拜访时,需要对客户进行定位、距离计算,所以客户经纬度都转换成了gcj02坐标。由于之前的百度地图经纬度坐标是百度自己坐标,因此需要获取经纬度时进行坐标转换,根据坐标点在百度地图上显示时需要二次转换,所以打算将百度地图替换成腾讯地图。
1、腾讯地图WEB API缺陷
先看下百度地图提供的2个现成功能,简单设置即可用:
1)城市切换
2)关键字输入提示
看完百度地图web api,再看看腾讯地图web api有没有这2功能:
1)城市切换,没有自带的,需要自行实现;
2)搜索关键字提示,提供了api接口,没有UI,需要自行完善;
2、基于jquery、bootstrap的腾讯地图城市切换和搜索关键字提示实现
1)页面截图
2)html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>腾讯地图API</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css" />
<script src="https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
ul,li{margin:0; padding:0; list-style: none}
.form-horizontal .form-group {margin-right: 0; margin-left: 0;}
.form-control, .btn{border-radius:0; box-shadow:none;}
.pr0 {padding-right: 0}
.pl0 {padding-left: 0}
#btn-reset, #btn-ok{width: 49.9%}
#btn-ok {margin-left: -1px}
.modal-backdrop {z-index: 900;}
.modal {z-index: 901;}
.pop_map .city-wrapper {position: absolute; background: #fff; border: 1px solid #e2e2e2; top: 46px; z-index: 9; width: 400px;}
.pop_map .city-wrapper .hd {padding: 10px 10px 0; border-bottom: 1px solid #e5ebf3}
.pop_map .city-wrapper .close {position: absolute; right: 0px; top: 0px; padding: 10px; font-size: 14px}
.pop_map .city-wrapper .bd{padding: 10px; height: 300px; overflow-y: auto}
.pop_map .city-wrapper .search{position: relative;}
.pop_map .city-wrapper .search i {position: absolute; right: 10px; top: 10px;}
.pop_map .form-control{box-shadow: none; border-radius:0;}
.pop_map textarea{height: 48px;}
.pop_map .keywords p {margin-bottom:0}
.pop_map a, .pop_map a:hover {color: #166abe;}
.pop_map a{line-height: 24px; margin-right: 10px; white-space:nowrap; text-decoration: none; outline:0}
.pop_map .keywords {border-bottom: 1px solid #e5ebf3}
.pop_map .cities li{padding: 4px 0; border-bottom: 1px solid #e5ebf3}
.pop_map .cities .col1{width: 40px; margin-right: 12px;}
.pop_map .cities .col2{width: 310px;}
.pop_map .cities .col2 a {margin-right: 10px;}
</style>
</head>
<body>
<div class="page-content container">
<div class='page-body'>
<div class='panel panel-default'>
<div class="panel-heading"><h3 class='panel-title'>腾讯地图:城市切换、搜索关键字演示</h3></div>
<table class='table table-bordered'>
<thead>
<tr>
<th width=35>No.</th>
<th width="40%">描述</th>
<th width="60%"><button type="button" class="btn btn-primary" id="btn-call">调用地图</button></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>省-市-区</td>
<td id="td-city"></td></tr>
<tr>
<td>2</td>
<td>街道</td>
<td id="td-street"></td></tr>
<tr>
<td>3</td>
<td>详细地址</td>
<td id="td-address"></td></tr>
<tr>
<td>4</td>
<td>经纬度</td>
<td id="td-jwd"></td></tr>
<tr>
<td>5</td>
<td>联系人</td>
<td id="td-contact"></td></tr>
<tr>
<td>6</td>
<td>联系方式</td>
<td id="td-tel"></td></tr>
</tbody>
</table>
</div>
</div>
<div id="pop-map" class="modal fade modal-primary pop_map" tabindex="-1">
<div class="modal-dialog" style="width:760px; margin-top:20px; min-height: 420px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" id="refresh">×</button>
<h4 class="modal-title" id="title">新增/修改</h4>
</div>
<div class="modal-body form-horizontal clearfix ">
<div class="form-group">
<div class="input-group">
<span class="input-group-btn">
<button type="button" class="btn btn-default" id="btn-city"><span id="btn-city-text" style="margin-right: 5px">全国</span><i class="fa fa-caret-down"></i></button>
</span>
<input id="pop-map_ap" class="form-control"></input>
<span class="input-group-btn">
<button type="button" id="btn-search" class="btn btn-primary">搜索</button>
</span>
</div>
</div>
<div class="clearfix">
<div id="pop-map_map" class="col-xs-9" style="height:480px"></div>
<div class="col-xs-3 pr0">
<div class="form-group">
<label>省-市-区</label><input class="form-control input-sm" id="txt-city" readonly></input>
</div>
<div class="form-group">
<label>街道门牌号</label><textarea class="form-control input-sm" id="txt-street"></textarea>
</div>
<div class="form-group">
<label>经纬度</label><input class="form-control input-sm" id="txt-jwd" readonly></input>
</div>
<div class="form-group">
<label>联系人</label><input class="form-control input-sm" id="txt-contact"></input>
</div>
<div class="form-group">
<label>移动电话</label><input class="form-control input-sm" id="txt-mobile"></input>
</div>
<div class="form-group">
<label>固话</label><input class="form-control input-sm" id="txt-tel"></input>
</div>
<div class="form-group" style='margin-bottom:0'>
<button class="btn btn-sm btn-default" id="btn-reset">重置</button><button class="btn btn-sm btn-primary ml-1" id="btn-ok">确定</button>
</div>
</div>
</div> <!-- /.modal-body -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=VEQBZ-2NIRW-3AARP-OAXJ3-2SFQ7-RFBNL&libraries=place&callback=initMap"></script>
<script type="text/javascript">
var LyPop = {
id: "pop-map",
poi: {},
show: function(poi) {
$("#" + this.id).modal({backdrop: 'static', keyboard: false});
this.initPoi(poi);
},
hide: function() {
$("#" + this.id).modal('hide');
},
onOk: function(poi) {
console.log(poi);
poi = poi || {};
$("#td-city").text(poi.province ? poi.province + "-" + poi.city + "-" + poi.district : "");
$("#td-street").text(poi.street || '');
$("#td-address").text(poi.address || '');
$("#td-jwd").text(poi.pos_jd ? poi.pos_jd + ", " + poi.pos_wd : "");
$("#td-contact").text(poi.contact || "");
$("#td-mobile").text(poi.mobile || "");
$("#td-tel").text(poi.tel || "");
this.hide();
},
initPoi: function(poi) {
console.log("p: ", poi)
poi = poi || {};
$("#txt-city").val(poi.province ? poi.province + "-" + poi.city + "-" + poi.district : "");
$("#txt-street").val(poi.street || '');
$("#txt-jwd").val(poi.pos_jd ? poi.pos_jd + ", " + poi.pos_wd : "");
$("#txt-contact").val(poi.contact || "");
$("#txt-mobile").val(poi.mobile || "");
$("#txt-tel").val(poi.tel || "");
this.poi = poi;
if(poi.pos_jd && poi.pos_wd) { // 设置地图center
map.panTo(new qq.maps.LatLng(poi.pos_wd, poi.pos_jd));
}
}
}
var StringUtil = {
format: function() {
if(arguments.length == 0) return null;
var str = arguments[0], a = arguments.length > 1 ? arguments[1] : null;
if (! a || typeof a != 'object') {
for(var i=1;i<arguments.length;i++) {
var re = new RegExp('\\{' + (i-1) + '\\}','gm');
str = str.replace(re, arguments[i]);
}
} else { //对象格式化.
var r = new RegExp('\\{([\\s\\S]+?)\\}','gm'), b = null, _str = str;
while((b = r.exec(_str)) !== null) {
str = str.replace(b[0], a[b[1]]);
}
}
return str;
}
}
var map = null, geocoder = null, cityservice = null, searchService = null, keyword = "";
function initMap() {
//init map
map = new qq.maps.Map(document.getElementById("pop-map_map"), {
// 地图的中心地理坐标。
center: new qq.maps.LatLng(39.916527,116.397128),
zoom: 13, //缩放级别,4-17
mapTypeControl: false, //地图、卫星类型选择开关
panControl: true //东南西北旋转按钮
});
geocoder = new qq.maps.Geocoder({
complete : function(result){
var addrComponents = result.detail && result.detail.addressComponents;
if (addrComponents) {
var strCity = addrComponents.province + "-" + addrComponents.city + "-" + addrComponents.district;
if(strCity != $("#txt-city").val()) {
$("#txt-city").val(strCity);
$("#txt-street").val(addrComponents.street);
}
$("#txt-jwd").val(result.detail.location.lng + ", " + result.detail.location.lat);
LyPop.curPoi = {
province: addrComponents.province, city: addrComponents.city, district: addrComponents.district,
pos_jd: result.detail.location.lng, pos_wd: result.detail.location.lat
}
}
}
});
//设置城市信息查询服务
cityservice = new qq.maps.CityService();
//请求成功回调函数
cityservice.setComplete(function(result) {
console.log("sss: ", result)
map.setCenter(result.detail.latLng);
});
cityservice.setError(function(result) {
console.log("error: ", result, arguments)
// map.setCenter(result.detail.latLng);
});
//调用Poi检索类。用于进行本地检索、周边检索等服务。
searchService = new qq.maps.SearchService({
complete : function(results){
if(results.type === "CITY_LIST") {
var cityName = results.detail.cities[0].cityName;
searchService.setLocation(cityName);
$("#" + LyPop.id + " .btn-city-text").text(cityName).data("city", cityName);
searchService.search(keyword);
return;
}
var pois = results.detail.pois;
var latlngBounds = new qq.maps.LatLngBounds();
for(var i = 0,l = pois.length;i < l; i++){
var poi = pois[i];
latlngBounds.extend(poi.latLng);
var marker = new qq.maps.Marker({
map:map,
position: poi.latLng
});
marker.setTitle(poi.name);
}
map.fitBounds(latlngBounds);
}
});
//添加监听事件
var ap = new qq.maps.place.Autocomplete(document.getElementById("pop-map_ap"));
qq.maps.event.addListener(ap, "confirm", function(res){
keyword = res.value;
searchService.search(keyword);
});
qq.maps.event.addListener(map, 'click', function(event) {
geocoder.getAddress(event.latLng);
});
}
$(function() {
//
var hotcities = ['北京','上海','广州','天津', '重庆', '深圳','杭州', '成都', '南京'];
var provincePys = ['A','F','G','H', 'J', 'L','N', 'Q', 'S', 'T', 'X', 'Y', 'Z'];
var provinceList = [
{province: "安徽", py: "A", fullname: "安徽省", cities: ["合肥", "芜湖", "蚌埠", "淮南", "马鞍山", "淮北", "铜陵", "安庆", "黄山", "滁州", "阜阳", "宿州", "六安", "亳州", "池州", "宣城"]},
{province: "福建", py: "F", fullname: "福建省", cities: ["福州", "厦门", "莆田", "三明", "泉州", "漳州", "南平", "龙岩", "宁德"]},
{province: "广东", py: "G", fullname: "广东省", cities: ["广州", "韶关", "深圳", "珠海", "汕头", "佛山", "江门", "湛江", "茂名", "肇庆", "惠州", "梅州", "汕尾", "河源", "阳江", "清远", "东莞", "中山", "潮州", "揭阳", "云浮"]},
{province: "广西", fullname: "广西壮族自治区", cities: ["南宁", "柳州", "桂林", "梧州", "北海", "防城港", "钦州", "贵港", "玉林", "百色", "贺州", "河池", "来宾", "崇左"]},
{province: "贵州", fullname: "贵州省", cities: ["贵阳", "六盘水", "遵义", "安顺", "毕节", "铜仁", "黔西南", "黔东南", "黔南"]},
{province: "甘肃", fullname: "甘肃省", cities: ["兰州", "嘉峪关", "金昌", "白银", "天水", "武威", "张掖", "平凉", "酒泉", "庆阳", "定西", "陇南", "临夏", "甘南"]},
{province: "河北", py: "H", fullname: "河北省", cities: ["石家庄", "唐山","秦皇岛","邯郸","邢台","保定","张家口","承德","沧州", "廊坊", "衡水"]},
{province: "河南", fullname: "河南省", cities: ["郑州", "开封", "洛阳", "平顶山", "安阳", "鹤壁", "新乡", "焦作", "濮阳", "许昌", "漯河", "三门峡", "南阳", "商丘", "信阳", "周口", "驻马店"]},
{province: "湖北", fullname: "湖北省", cities: ["武汉", "黄石", "十堰", "宜昌", "襄阳", "鄂州", "荆门", "孝感", "荆州", "黄冈", "咸宁", "随州", "恩施"]},
{province: "湖南", fullname: "湖南省", cities: ["长沙", "株洲", "湘潭", "衡阳", "邵阳", "岳阳", "常德", "张家界", "益阳", "郴州", "永州", "怀化", "娄底", "湘西"]},
{province: "黑龙江", fullname: "黑龙江省", cities: ["哈尔滨", "齐齐哈尔", "鸡西", "鹤岗", "双鸭山", "大庆", "伊春", "佳木斯", "七台河", "牡丹江", "黑河", "绥化", "大兴安岭"]},
{province: "海南", fullname: "海南省", cities: ["海口", "三亚", "三沙", "儋州"]},
{province: "江苏", py: "J", fullname: "江苏省", cities: ["南京", "无锡", "徐州", "常州", "苏州", "南通", "连云港", "淮安", "盐城", "扬州", "镇江", "泰州", "宿迁"]},
{province: "江西", fullname: "江西省", cities: ["南昌", "景德镇", "萍乡", "九江", "新余", "鹰潭", "赣州", "吉安", "宜春", "抚州", "上饶"]},
{province: "吉林", fullname: "吉林省", cities: ["长春", "吉林", "四平", "辽源", "通化", "白山", "松原", "白城", "延边"]},
{province: "辽宁", py: "L", fullname: "辽宁省", cities: ["沈阳", "大连", "鞍山", "抚顺", "本溪", "丹东", "锦州", "营口", "阜新", "辽阳", "盘锦", "铁岭", "朝阳", "葫芦岛"]},
{province: "宁夏", py: "N", fullname: "宁夏回族自治区", cities: ["银川", "石嘴山", "吴忠", "固原", "中卫"]},
{province: "内蒙古", fullname: "内蒙古自治区", cities: ["呼和浩特", "包头", "乌海", "赤峰", "通辽", "鄂尔多斯", "呼伦贝尔", "巴彦淖尔", "乌兰察布", "兴安", "锡林郭勒", "阿拉善"]},
{province: "青海", py: "Q", fullname: "青海省", cities: ["西宁", "海东", "海北", "黄南", "海南", "果洛", "玉树", "海西"]},
{province: "山东", py: "S", fullname: "山东省", cities: ["济南", "青岛", "淄博", "枣庄", "东营", "烟台", "潍坊", "济宁", "泰安", "威海", "日照", "莱芜", "临沂", "德州", "聊城", "滨州", "菏泽"]},
{province: "山西", fullname: "山西省", cities: ["太原", "大同", "阳泉", "长治", "晋城", "朔州", "晋中", "运城", "忻州", "临汾", "吕梁"]},
{province: "陕西", fullname: "陕西省", cities: ["西安", "铜川", "宝鸡", "咸阳", "渭南", "延安", "汉中", "榆林", "安康", "商洛"]},
{province: "四川", fullname: "四川省", cities: ["成都", "自贡", "攀枝花", "泸州", "德阳", "绵阳", "广元", "遂宁", "内江", "乐山", "南充", "眉山", "宜宾", "广安", "达州", "雅安", "巴中", "资阳", "阿坝", "甘孜", "凉山"]},
{province: "台湾", py: "T", fullname: "台湾省", cities: ["台北", "高雄", "台南", "台中", "南投", "基隆", "新竹", "嘉义", "新北", "宜兰", "桃园", "苗栗", "彰化", "云林", "屏东", "台东", "花莲", "澎湖"]},
{province: "西藏", py: "X", fullname: "西藏自治区", cities: ["拉萨", "日喀则", "昌都", "林芝", "山南", "那曲", "阿里"]},
{province: "新疆", fullname: "新疆维吾尔自治区", cities: ["乌鲁木齐", "克拉玛依", "吐鲁番", "哈密", "昌吉", "博州", "巴州", "阿克苏", "克州", "喀什", "和田", "伊犁", "塔城", "阿勒泰"]},
{province: "云南", py: "Y", fullname: "云南省", cities: ["昆明", "曲靖", "玉溪", "保山", "昭通", "丽江", "普洱", "临沧", "楚雄", "红河", "文山", "西双版纳", "大理", "德宏", "怒江", "迪庆"]},
{province: "浙江", py: "Z", fullname: "浙江省", cities: ["杭州", "宁波", "温州", "嘉兴", "湖州", "绍兴", "金华", "衢州", "舟山", "台州", "丽水"]},
{province: "其它", fullname: "", cities: ["香港", "澳门"]}
];
var cities = [];
for(var i in provinceList) {
var _cities = provinceList[i]['cities'];
for(var ii in _cities) {
cities.push({name: _cities[ii], fullname: (provinceList[i]['province'] == '其它' ? '' : provinceList[i]['province'] + "/") + _cities[ii]});
}
}
var mapCity = '<div id="city-wrapper" class="city-wrapper" style="display:none;">'
+ "<div class='hd'>"
+ "<p>请选择城市</p>"
+ "<div class='close'><i class='fa fa-close'></i></div>"
+ "<p>当前城市: <span id='cur-city'></span></p>"
+ "</div>"
+ "<div class='bd'><div class='search'>";
// 热门城市
mapCity += "<div class='keywords'><p><a href='javascript:void(0);' fullname='全国'>全国</a>";
for(var i in hotcities) {
mapCity += StringUtil.format("<a href='javascript:void(0);' fullname='{0}'>{1}</a>", hotcities[i] + '市', hotcities[i]);
}
mapCity += "</p></p>";
for(var i in provincePys) {
mapCity += StringUtil.format("<a href='{0}'>{1}</a>", "#py_" + provincePys[i], provincePys[i]);
}
mapCity += "</p></div>";
mapCity += "</div>" // search-end
mapCity += "<ul class='cities'>";
for(var i in provinceList) {
var province = provinceList[i];
mapCity += "<li class='clearfix'>";
mapCity += StringUtil.format("<div class='pull-left col1'><a href='javascript:void(0);' {0}>{1}</a></div>", province.py ? "name=py_" + province.py: "", province.province);
mapCity += "<div class='pull-left col2'>";
for(var ii in province.cities) {
mapCity += StringUtil.format("<a href='javascript:void(0);' fullname='{0}'>{1}</a>", province.province + "/" + province.cities[ii], province.cities[ii]);
}
mapCity += "</div>"
mapCity += "</li>"
}
mapCity += "</ul>";
mapCity += "</div></div>";
//
$("#btn-call").click(function(e){
LyPop.show(LyPop.curPoi || {});
});
$("#btn-ok").on("click", function(e) {
var curPoi = LyPop.curPoi || {};
if (LyPop.onOk) {
var result = $.extend({}, LyPop.poi, LyPop.curPoi);
result.street = $("#txt-street").val();
result.contact = $("#txt-contact").val();
result.tel = $("#txt-tel").val();
result.mobile = $("#txt-mobile").val();
if(result.province && result.city)
result.address = (result.province == result.city ? "" : result.province) + result.city + result.district + ' ' + result.street;
if(!result.province || !result.city || !result.district || !result.street) {
alert('省市区、详细地址不能为空'); return
}
LyPop.curPoi = result;
LyPop.onOk(result);
}
});
$("#btn-reset").on("click", function(e) { LyPop.initPoi(LyPop.poi || {}); });
$("#btn-search").on("click", function(e) {
var keyword = $("#pop-map_ap").val();
if(keyword) searchService.search(keyword);
})
$('#btn-city').on('click', function(e) {
$("#city-wrapper").toggle();
})
$(".close").on('click', function(e) {
$("#city-wrapper").hide();
})
$("#pop-map .modal-body").append(mapCity);
$("#pop-map a[fullname]").on('click', function(e) {
$("#cur-city").text($(this).attr('fullname'));
$("#btn-city-text").text($(this).attr('fullname')).data('city', $(this).text());
$("#pop-map_ap").val('');
cityservice.searchCityByName( $(this).text() + "市");
$("#city-wrapper").hide();
});
})
</script>
</body>
</html>
代码说明:
中文整理的代码,结构有点乱,勉强可以工作,仅供参考。
3、进一步优化
建议大家封装成一个弹出框组件,可以:
1)根据poi数据,初始化地图;
2)可以显示、隐藏弹出框组件;
3)可以有返回结果回调;