添加地址实现方式一般有三种:
- 最传统的,省市区联动选择,地址详细手动编辑
- 地图选点,通过使用第三方地图位置的SDK来实现,例如:百度、高德、腾讯等等。
- 智能识别,复制一串文字、然后识别出联系人、手机号、地址等等信息,例如:寄快递的 app
下面会把三种方式都说一下。demo 可以到这里拉取 ——「微信通用模板」
项目技术相关:
组件库:vant-weapp
小程序插件SDK:腾讯城市选点插件、腾讯位置服务小程序SDK
第三方插件:smartParsePro 智能识别地址
准备工作
注册腾讯位置服务账号、配置信息、下载SDK
开始之前,我们需要先注册一个腾讯位置服务的账号,个人账号日免费额度每日1w,并发额度 5(秒/次),企业账号(企业认证),免费额度为 50w~300w,并发额度 200~1000(秒/次)。一般都够用了。具体怎么注册就不赘述了,主要说一下怎么创建应用 —— 腾讯位置服务官网
控制台 –> 我的应用 –> 创建应用 –>填写名称以及分类

添加key –>勾选 WebServiceAPI –>勾选微信小程序 –>填写你的小程序 APPID –> 复制Key(这个很重要小程序要用)

创建完应用,接下来就是使用了。我们先下载 SDK —— 下载地址,把 qqmap-wx-jssdk.min.js(压缩版)放进项目里,这里放在utils目录下。
为了方便理解和使用,三种方法的会分开实现
第一种 —— 省市区联动选择,地址详细手动编辑

这种方法重点主要在省市区联动器上,vant-weapp 提供了 van-area组件,还提供了一份省市区的数据源,数据源需要先安装依赖:npm i @vant/area-data,目前貌似已经停止维护,而且为本地的需要手动更新,不推荐使用。
我们通过地图服务的 SDK 提供的 getCityList接口获取数据源,通过SDK接口获取的数据和van-area 提供的数据有差异,所以我们需要加工一下。
首先基于 vant 提供的 van-area和van-popup组件封装一个省市区联动选择组件,再准备一个存放表单的页面
area-select 「省市区联动选择组件」
// area-select/index.wxml
<van-popup show="{{ isShowAreaSelect }}" position="bottom" custom-style="height: 50%" bind:close="closeAreaSelect">
<van-area area-list="{{ areaList }}" :columns-num="3" bind:cancel="closeAreaSelect" bind:confirm="confirmArea" />
</van-popup>
复制代码
// area-select/index.js
import { MAP_KEY } from "../../config.js" //腾讯位置服务的 Key
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min'); // 引入 SDK 文件
var qqmapsdk; // SDK实例对象
Component({
properties: {},
data: {
isShowAreaSelect: false,
areaList: {
// 变量名称是 van-area 规定写死的,不能换!不能换!不能换!
province_list: {}, //省
city_list: {}, //市
county_list: {} //区
},
},
lifetimes: {
attached() {
//创建SDK实例
qqmapsdk = new QQMapWX({
key: MAP_KEY
});
//调用 getCityList
qqmapsdk.getCityList({
success: (res) => { //成功后的回调
console.log('省份数据:', res.result[0]); //打印省份数据
console.log('城市数据:', res.result[1]); //打印城市数据
console.log('区县数据:', res.result[2]); //打印区县数据
this.setData({
"areaList.province_list": this.ArrayToObject(res.result[0]),
"areaList.city_list": this.ArrayToObject(res.result[1]),
"areaList.county_list": this.ArrayToObject(res.result[2]),
})
},
fail: function (error) {
console.error(error);
},
complete: function (res) {
console.log(res);
}
});
}
},
methods: {
//确认选择
confirmArea: function (e) {
const values = e.detail.values
//直辖市,需要处理数据,保持省市一致,例如,省:北京市;市:北京市;区:朝阳区
if (values.some(x => !Boolean(x)))[values[1], values[2]] = [values[0], values[1]]; 1
const arr = (values.map(x => x.name))
//调用父组件的传递方法,并传递选择结果。
this.triggerEvent("confirm", arr)
this.setData({
isShowAreaSelect: false,
})
},
//关闭省市区选择组件
closeAreaSelect: function () {
this.setData({
isShowAreaSelect: false
})
},
//打开省市区选择组件
showAreaSelect: function () {
this.setData({
isShowAreaSelect: true
})
},
// 格式化省市区数据
ArrayToObject(arr) {
const obj = {}
for (let i = 0; i < arr.length; i++) {
obj[arr[i].id] = arr[i].fullname
}
return obj
}
}
})
复制代码
// area-select/index.json(注释不要复制)
"usingComponents": {
"van-area": "@vant/weapp/area/index",
"van-popup": "@vant/weapp/popup/index"
}
复制代码
如果需要获取省市区的经纬度,可以在confirmArea 里调用 SDK 提供的 geocoder 方法来获取,比较很简单,这种方式最省事,就不赘述了。
address-detail 地址添加页面
这里只显示关键代码,也就是省市区选择的部分,至于手机号码、联系人等,请自行拉取项目
<!-- address-detail/index.wxml -->
<van-field value="{{ formData.province + formData.city + formData.county}}" title-width="4.5em" label="所在地区"
type="textarea" autosize clearable readonly placeholder="省 / 市 / 区 (只读)" border="{{ false }}" columns-num="{{3}}"
bindtap="showAreaSelect" />
复制代码
//address-detail/index.js
//打开省市区选择器
showAreaSelect: function () {
this.selectComponent("#area-select").showAreaSelect();
},
//确认选择结果
confirmArea: function ({
detail
}) {
this.setData({
"formData.province": detail[0],
"formData.city": detail[1],
"formData.county": detail[2],
})
},
复制代码
第二种 地图选点

地图选点也有两种方案:
- 直接使用腾讯提供的地图选点插件,方便快捷。但是腾讯地图选点插件有一个缺点,就是不能选择某个城市来进行搜索,默认优先搜索当前城市的地点,如果没有,再自动匹配其他城市的地点。要是觉得这小缺点能接受,推荐使用这个方案。省事。具体实现参考:「开发文档」;
- 通过 SDK 提供的接口来自己实现,也是本文要介绍的实现方式。
「SDK 接口 + 腾讯地图城市选点插件」,相对于第一种方式,多了个城市选择的功能,这种方式主要的优势是定制化;第一种直接使用选点插件,完全不存在可以插手的可能性。
添加插件
在 app.json 中添加下面的代码,添加完保存,微信开发者工具会提醒你添加插件,如果没有提醒,需要到小程序的后台添加,「设置」–>「第三方设置」–>「添加插件」–>搜索「腾讯位置服务城市选择器」添加即可。
"plugins": {
"citySelector": {
"version": "1.0.0",
"provider": "wx63ffb7b7894e99ae"
}
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序定位"
}
},
复制代码
地图选点页面
坑点一:map 地图组件,在开发者工具中无法正常显示,需点击预览,手机上查看
坑点二:小程序 2.17 版本库之后,wx.getLocation 有调用频率限制,用wx.onLocationChange 代替 ,「频率限制说明」
坑点三: 用户手动关闭的授权,wx.authorize` 无法调出授权窗口
<!-- map/index.wxml -->
<view class="container">
<!-- 顶部导航栏 -->
<navbar navConfig="{{navConfig}}" />
<!-- 搜索组件 -->
<van-search value="{{ addressInput }}" shape="round" placeholder="请输入搜索关键词" use-left-icon-slot
bind:change="nearby_search">
<view class="cityName ellipsis_1" slot="left-icon" bindtap="toSelectCity">{{cityName}}</view>
</van-search>
<!--地图容器-->
<map id="myMap" style="width:100%;height:450rpx;" longitude="{{longitude}}" latitude="{{latitude}}" scale="15"
bindregionchange="mapChange">
<cover-view class="map-prompt">您可拖动地图, 标记准确位置</cover-view>
<cover-image class="current-site-icon" src="../../images/marker.png"></cover-image>
<cover-view class="reload" bindtap="reload">
<cover-view class="center1">
<cover-view class="center2"></cover-view>
</cover-view>
</cover-view>
</map>
<!-- 地点列表 -->
<scroll-view class="scroll" bindscrolltolower="loadLocation" scroll-y lower-threshold="100">
<view class="near-item" wx:for="{{nearList}}" wx:key="index" id="{{index}}" data-name="{{item.title}}"
bindtap="chooseCenter">
<van-icon name="location-o" custom-class="current-site" color="{{activeColor}}" wx:if="{{index == selectedId}}" />
<van-icon name="location-o" custom-class="current-site" wx:else />
<view class="item-main ellipsis_1">
<view class="title {{ index == selectedId?'activeTitle':'' }}">{{item.title}}</view>
<view class="address {{ index == selectedId?'activeAddress':'' }}">{{item.addr}}</view>
</view>
</view>
</scroll-view>
</view>
复制代码
//map/index.js
import {
MAP_KEY
} from "../../config"
const cityS elector = requirePlugin('citySelector');
import QQMapWX from "../../utils/qqmap-wx-jssdk.min.js"
let qqmapsdk;
Page({
data: {
navConfig: {
title: "地图选点",
isLeftArrow: true
},
cityName: "佛山市",
latitude: '',
longitude: '',
centerData: {},
nearList: [],
selectedId: 0,
defaultKeyword: '房产小区',
keyword: '',
pageIndex: 1,
pageSize: 20,
isDone: false,
MAP_KEY,
},
onLoad: async function (options) {
//获取地图 map 实例
this.mapCtx = wx.createMapContext('myMap')
// 实例化API核心类
qqmapsdk = new QQMapWX({
key: MAP_KEY
});
//判断是否授权定位
let scopeRes = await wx.getSetting()
if (!scopeRes.authSetting['scope.userLocation']) {
try {
// 没有授权的时候弹出授权窗口
await wx.authorize({
scope: 'scope.userLocation',
})
} catch (error) {
// 用户手动关闭的授权,无法自动调起授权窗口,我们只能提示引导用户授权
wx.showModal({
showCancel: false,
title: '位置授权',
content: '该功能,需要进行「位置授权」才能使用。可点击「右上角」-->「设置」-->「位置消息」-->「仅在使用小程序使用」',
})
return
}
}
wx.showLoading({
title: '加载中'
});
//判断表单是否传了经纬度,如果有则使用表单的,用于在地图里显示刚才选择的位置
const longitudeLatitude = options ? options.longitudeLatitude : ""
if (longitudeLatitude) {
const longLatArr = longitudeLatitude.split(',')
this.initLocation(longLatArr[1], longLatArr[0])
} else {
//微信作死!新版本 wx.getLocation 存在调用频率限制, 使用 onLocationChange 来代替
wx.startLocationUpdate({
success: (res) => {
wx.onLocationChange((location) => {
if (location) {
wx.stopLocationUpdate()
const {
latitude,
longitude
} = this.data
if (latitude && longitude) return
this.initLocation.call(this, location.latitude, location.longitude)
}
})
},
})
}
},
onShow: function () {
//城市选择插件,获取城市信息
const selectedCity = citySelector.getCity();
if (selectedCity) {
const {
fullname,
location
} = selectedCity
this.setData({
longitude: location.longitude,
latitude: location.latitude,
cityName: fullname
})
this.data.pageIndex = 1
this.data.isDone = false
this.nearby_search()
}
},
onUnload() {
// 页面卸载时清空插件数据,防止再次进入页面,getCity返回的是上次的结果
citySelector.clearCity();
},
toSelectCity() {
const key = MAP_KEY; // 使用在腾讯位置服务申请的key
const referer = '微信模板'; // 调用插件的app的名称
wx.navigateTo({
url: `plugin://citySelector/index?key=${key}&referer=${referer}`,
})
},
//监听拖动地图,拖动结束根据中心点更新页面
mapChange: function (e) {
if (e.type == 'end' && (e.causedBy == 'scale' || e.causedBy == 'drag')) {
this.mapCtx.getCenterLocation({
success: (res) => {
this.setData({
nearList: [],
latitude: res.latitude,
longitude: res.longitude,
})
this.data.pageIndex = 1
this.data.isDone = false
this.nearby_search.call(this);
}
})
}
},
//重新定位
reload: function () {
this.setData({
nearList: []
})
this.onLoad();
},
chooseCenter: function (e) {
let id = e.currentTarget.id;
for (let i = 0; i < this.data.nearList.length; i++) {
if (i == id) {
this.setData({
selectedId: id,
centerData: this.data.nearList[i],
latitude: this.data.nearList[i].latitude,
longitude: this.data.nearList[i].longitude,
});
this.selectedOk()
return;
}
}
},
//搜索附近地点
nearby_search: function (e) {
if (e) this.data.keyword = e.detail
wx.hideLoading();
wx.showLoading({
title: '加载中'
});
qqmapsdk.search({
keyword: this.data.keyword,
location: this.data.latitude + ',' + this.data.longitude,
page_size: this.data.pageSize,
page_index: this.data.pageIndex,
success: (res) => {
wx.hideLoading();
var sug = [];
for (let i = 0; i < res.data.length; i++) {
sug.push({
title: res.data[i].title,
id: res.data[i].id,
addr: res.data[i].address,
province: res.data[i].ad_info.province,
city: res.data[i].ad_info.city,
district: res.data[i].ad_info.district,
latitude: res.data[i].location.lat,
longitude: res.data[i].location.lng
});
}
let pageIndex = this.data.pageIndex + 1
if (sug.length < this.data.pageSize) {
this.data.isDone = true
pageIndex = this.data.pageIndex
};
this.setData({
selectedId: 0,
centerData: sug[0],
nearList: this.data.nearList.concat(sug),
pageIndex: pageIndex
})
},
fail: function (res) {
wx.hideLoading();
},
complete: function (res) {
wx.hideLoading();
}
});
},
//确认选择地址
selectedOk: function () {
let pages = getCurrentPages();
//获取上一个页面的实例
let prevPage = pages[pages.length - 2];
const {
title,
city,
district,
province,
latitude,
longitude
} = this.data.centerData
prevPage.setData({
"formData.county": district,
"formData.province": province,
"formData.city": city,
"formData.addressDetail": title,
"formData.longitudeLatitude": longitude + ',' + latitude,
})
wx.navigateBack({
delta: 1
})
},
//初始化
initLocation: function (latitude, longitude) {
qqmapsdk.reverseGeocoder({
location: {
latitude: latitude,
longitude: longitude
},
get_poi: 1,
success: (res) => {
this.setData({
latitude: latitude,
longitude: longitude,
keyword: this.data.defaultKeyword,
cityName: res.result.address_component.city
})
// 调用接口
this.nearby_search.call(this);
},
});
},
//滚动加载
loadLocation() {
if (!this.data.isDone) this.nearby_search();
}
})
复制代码
地图选点使用
「地图选点」使用很简单,只需要跳转到「地图选点页面」就可以了。
<van-field value="{{ formData.addressDetail }}" title-width="4.5em" label="服务地址" type="textarea" autosize clearable
placeholder="点击选择服务地址" border="{{ false }}" center readonly right-icon="location-o"
bind:change="changeAddressDetail" bindtap="getLocation" />
复制代码
// longitudeLatitude 经纬度字符串,如果不为空默认使用 longitudeLatitude,如果为空就获取用户当前的经纬度
getLocation() {
const {
longitudeLatitude
} = this.data.formData
wx.navigateTo({
url: '../../pages/map/index?longitudeLatitude=' + (longitudeLatitude || ''),
})
},
复制代码
第三种 智能识别地址

智能识别地址,听起来很高大上,其实复制一段文本,然后通过与数据源的比对校验来识别出,手机号、联系人、省市区、详细地址等等。主要是这份数据源是否足够完善
智能识别地址也有两种方式
-
直接调用第三方提供的智能识别地址 api,没啥好说,百度、腾讯等都有提供服务(有免费额度),给点小钱,效果应该是最好。推荐使用!这种方式基本没有前端什么事,把文本传给后端,后端稍微配置一下,调用 SDK 提供的地址识别 api ,然后返回结果给前端就好。
-
前端自己来实现,这种方法准确率应该没有第一种那么高,不过只要不是用户故意捣乱,基本都也能识别出来。这里使用开源库 —— 「smartParsePro」来实现。
下面主要说说第二种
「拉取代码」——>「复制 smartWeChat 到自己的项目」
代码实现:
// app.js
import address_parse from "./utils/smartWeChat/js/address_parse"
App({
// 识别地址
smart: function (val) {
return address_parse.method(val || '')
},
//手动重新挂载数据
getAddressData: function () {
address_parse.getData()
},
})
复制代码
// address-detail_03/index.js
const app = getApp()
//智能识别
insightAddress() {
// 重新挂载数据,非必须,保险起见
app.getAddressData()
// 解析文本,提取地址信息
const addressObj = app.smart(this.data.smartAddress)
let {
name = "",
phone = "",
province = "",
city = "",
county = "",
street = "",
address = ""
} = addressObj
this.setData({
"formData.contactName": name,
"formData.contactTel": phone,
"formData.province": province,
"formData.city": city,
"formData.county": county,
"formData.addressDetail": street + address
})
},
复制代码
这样就算完成了 。
注意点:
-
手机预览的时候,需要在小程序配置好请求地址或者开发调试模式,不然无法加载数据源。
-
小程序后台没有配置数据源请求地址的时候,开发者工具记得勾选

smartWeChat开源库用的数据源地址,是开发者提供的,正式环境,推荐把数据源下载下来并存在自己的服务器上。开发者把数据源分成了多等份存储起来,这样做应该是为了避免文件过大,以及微信请求限制数据大小为 2M ,下载时候也需要按照多等分切割开,不然你就需要改源码
修改数据源请求地址
//smartWeChat/js/address_parse.js
wx.request({
//把地址 https://wangzc.wang/addressJson/ 替换成自己的
url: "https://wangzc.wang/addressJson/" + i,
method: "GET",
success: function (res) {}
})
复制代码
码字不易,麻烦多多点赞,谢谢。
demo 可以到这里拉取——「微信通用模板」
相关文章:


















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)