小程序通过腾讯地图选择收货地址
小程序可通过小程序插件或基础地图来实现收货地址的选择
<a href=” https://lbs.qq.com/miniProgram/plugin/pluginGuide/locationPicker” target=”_blank”>腾讯位置服务-地图选点插件
插件开箱即用方便快捷,但好像商用要付费
看了下百果园和每日优鲜的地图,样子并不像使用插件,猜测是使用基础地图+腾讯地图API实现的选点,于是自己动手试了下
图一分搜索、基础地图、周边推荐列表三部分,用到
腾讯位置服务关键词输入提示、逆地址解析和地点搜索-周边推荐三个接口
<a href=” https://lbs.qq.com/service/webService/webServiceGuide/webServiceSuggestion” target=”_blank”>腾讯位置服务- WebService API
首次进入页面通过wx.getLocation获取手机当前地理位置通过逆地址解析得到当前所在省,地图视野变化会触发regionchange,在切换城市或regionchange时请求周边推荐得到地图下方的地点列表
<a href=” https://developers.weixin.qq.com/miniprogram/dev/component/map.html” target=”_blank”>微信官方文档小程序-组件-地图
城市选择需要用到城市选择器插件
<a href=” https://lbs.qq.com/miniProgram/plugin/pluginGuide/citySelector” target=”_blank”>腾讯位置服务- 城市选择器插件
改善:
地点搜索加了防抖,原本是小程序直接请求的腾讯地图接口,但发现要配域名白名单或授权IP,所以改为后台请求接口再将数据返回
JS
// pages/address-map/address-map.js
import {tencentMapKey} from \'../../utils/config\'
import {mapGeoCoder, mapSuggestion, mapExplore} from \'../../utils/api\'
const citySelector = requirePlugin(\'citySelector\')
Page({
/**
* 页面的初始数据
*/
data: {
cityName: \'\',
longitude: \'\',
latitude: \'\',
city: \'\', // 顶部搜索栏左边的城市
searchText: \'\', // 搜索栏内容
searchValid: true, // 搜索栏节流
searchDelay: 800,
selectLocation: \'\', // 选择的地址
mapCtx: \'\',
mapSetting: {
skew: 0,
rotate: 0,
showLocation: true,
showScale: false, // 比例尺
subKey: \'\',
layerStyle: 1,
enableZoom: true,
enableScroll: true,
enableRotate: false,
showCompass: true, // 指南针
enable3D: false,
enableOverlooking: false,
enableSatellite: false,
enableTraffic: false,
},
searchResult: [], // 搜索结果
exploreList: [] // 周边热点地址
},
removeSearch() {
this.setData({
searchText: \'\',
searchResult: []
})
},
searchInput(e) {
this.setData({
searchText: e.detail.value
})
if (!this.data.searchValid) return
this.setData({searchValid: false})
setTimeout(() => {
this.mapSuggestion()
this.setData({searchValid: true})
}, this.data.searchDelay)
},
mapRegionChange(e) {
if (e.type !== \'end\') return
this.data.mapCtx.getCenterLocation({
success: res => {
this.mapSearchExplore(res.longitude, res.latitude, 1000)
}
})
},
selectCity() {
const referer = \'湘土优选\' // 调用插件的app的名称
const hotCitys = \'\' // 用户自定义的的热门城市
wx.navigateTo({
url: `plugin://citySelector/index?key=${tencentMapKey}&referer=${referer}&hotCitys=${hotCitys}`,
})
},
clickAddress(e) {
let address = e.currentTarget.dataset.address
let param = {
province: address.province,
city: address.city,
district: address.district,
address: address.title,
}
wx.setStorageSync(\'mapAddress\', param)
wx.navigateBack({
delta: 1
})
},
// 腾讯地图-周边搜索
mapSearchExplore(longitude, latitude, radius) {
let param = {
longitude,
latitude,
radius,
}
mapExplore(param).then(res => {
this.setData({
exploreList: res.data || []
})
})
},
// 搜索关键词提示
mapSuggestion() {
let param = {
keyword: this.data.searchText,
region: this.data.cityName
}
mapSuggestion(param).then(res => {
this.setData({
searchResult: res.data || []
})
})
},
// 根据坐标获取地名
mapGeoCoder(latitude, longitude) {
let param = {
longitude: longitude,
latitude: latitude
}
mapGeoCoder(param).then(res => {
this.setData({
cityName: res.data.city
})
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
this.setData({
mapCtx: wx.createMapContext(\'curMap\')
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
// 从城市选择器插件返回后,在页面的onShow生命周期函数中能够调用插件接口,获取cityInfo结果对象
// 结果为null表示不是从选择器插件返回,所以直接获取当前地理位置来显示城市名
const selectedCity = citySelector.getCity()
if (selectedCity) {
let location = selectedCity.location
this.mapSearchExplore(location.longitude, location.latitude, 1000)
this.setData({
cityName: selectedCity.fullname,
longitude: location.longitude,
latitude: location.latitude,
})
} else {
wx.getLocation({
type: \'gcj02\',
altitude: true,
success: res => {
this.setData({
longitude: res.longitude,
latitude: res.latitude,
})
this.mapSearchExplore(res.longitude, res.latitude, 1000)
this.mapGeoCoder(res.latitude, res.longitude)
},
fail: function () {
wx.hideLoading()
console.log("getLocationFail")
},
complete: function () {
wx.hideLoading() // 隐藏定位中信息进度
}
})
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
// 页面卸载时清空插件数据,防止再次进入页面,getCity返回的是上次的结果
citySelector.clearCity()
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
WXML
<!--pages/address-map/address-map.wxml-->
<view class="map-page">
<view class="top-container">
<view class="search">
<view class="city" bindtap="selectCity">
<view class="city-name ellipsis">{{ cityName }}</view>
<icon class="iconfont icon-xiajiantoushixinxiao"></icon>
</view>
<view class="text">
<input type="text" value="{{searchText}}" bindinput="searchInput" placeholder="请输入您的收货地址"/>
<icon class="iconfont icon-guanbi close-btn" bindtap="removeSearch"></icon>
</view>
</view>
<view class="explore-container {{ searchResult.length > 0 ? \'search-result\' :\'\' }}">
<view class="item" wx:for="{{ searchResult }}" data-address="{{item}}" bindtap="clickAddress">
<view class="name">{{ item.title }}</view>
<view class="address">{{ item.address }}</view>
</view>
</view>
</view>
<view class="map-container">
<map id="curMap"
longitude="{{longitude}}"
latitude="{{latitude}}"
setting="{{ mapSetting }}"
bindregionchange="mapRegionChange"></map>
</view>
<view class="explore-container">
<view class="item" wx:for="{{ exploreList }}" data-address="{{item}}" bindtap="clickAddress">
<view class="name">{{ item.title }}</view>
<view class="address">{{ item.address }}</view>
</view>
</view>
</view>
WXSS
/* pages/address-map/address-map.wxss */
.map-page{
padding:90rpx 0 0;
}
.map-page .search {
border: 1px solid #d0d4ce;
background-color: #d3fcbb;
border-radius: 50rpx;
padding: 8rpx 20rpx 8rpx 165rpx;
margin: 10rpx 15rpx 10rpx;
position:relative;
}
.map-page .top-container{
background-color:#fff;
position: fixed;
top:0;
left:0;
right:0;
z-index:100;
}
.map-page .search .city{
position: absolute;
top:8rpx;
left:22rpx;
width:130rpx;
}
.map-page .search .city-name{
width: 120rpx;
padding-right: 15rpx;
box-sizing: border-box;
border-right: 1px solid #ccc;
}
.map-page .search .city icon{
position: absolute;
right:12rpx;
top:-12rpx;
}
.map-page .search .text{
padding-right:40rpx;
}
.map-page .search .text icon{
position: absolute;
right: 20rpx;
top: -5rpx;
font-size: 28rpx;
}
.map-page .map-container {
height: 520rpx;
}
.map-page .map-container map{
width:100%;
height:100%;
}
.explore-container .item{
position: relative;
padding: 25rpx 30rpx 25rpx 80rpx;
border-bottom: 1px solid #eee;
}
.explore-container .item::before{
content: "";
position: absolute;
top: 38rpx;
left: 30rpx;
width: 10rpx;
height: 10rpx;
border-radius: 100%;
border: 8rpx solid #d3fcbb;
}
.explore-container .item .name{
font-size:30rpx;
font-weight: 700;
}
.explore-container .item .address{
font-size:26rpx;
}
.map-page .search-result{
position: fixed;
top: 75rpx;
left: 0;
right: 0;
bottom: 0;
overflow-y: auto;
background-color: #fff;
}