小程序通过腾讯地图选择收货地址

小程序可通过小程序插件或基础地图来实现收货地址的选择
<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;
    130rpx;
}

.map-page .search .city-name{
     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{
    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;
     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;
}
原文地址:https://www.cnblogs.com/Grani/p/14742003.html