小程序可通過小程序插件或基礎地圖來實現收貨地址的選擇
<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;
}