微信小程序使用地图 微信小程序中正确使用地图的方法实例
执鸢者 人气:0前言
今天是我的小兄弟(微信小程序方面)在工作中遇到的一个场景——选择某个位置周围的学校,感觉很有用,就让他给大家分享一下。
这次想分享一下关于微信小程序中选择全国中的一个学校和地址的方法,经过调研发现大多网站提供全国学校名称的是比较老的一些学校,像比较新或者地方比较偏僻的学校一般都找不到。想想这样是肯定不行的,那就继续寻找能更全面的方式,最终想到了地图中提供的服务提供的学校最全面,这里就采用腾讯地图的开放接口作为示例演示。
1. 准备
通过阅读腾讯地图开放平台可以得知微信小程序可以下载SDK提供直接调用接口来使用腾讯地图,当然也可以自己对URL进行封装请求并返回自己的数据,本示例均使用了,因为SDK中封装时会调用某些接口,而在示例中会多时间内调用同一接口,那么就会造成频繁调用接口的错误。
过程中我也会用有赞团队的vant来展示学校信息,所以也需要提前安装好依赖备用,具体安装步骤见官网
2. 实战
2.1 配置小程序权限
首先就是在进入小程序时让用户给我们的小程序开启定位的权限,需要我们在app.json文件中添加以下代码:
"permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }
加上这一字段,当小程序用到定位系统时,发现小程序的权限没给到就会让用户将权限给到小程序,效果如下:
2.2 封装工具函数
2.2.1 全局函数与变量
app.js
// 全局变量 globalData: { userInfo: null }, // 全局引入方法,简便引入第三方包 require: ($url)=> require($url)
2.2.2 工具函数
util.js
// 引入SDK核心类 const QQMapWX = require('./qqmap-wx-jssdk.min.js'); // 实例化API核心类 let key = ''; let qqmapsdk; key &&(qqmapsdk = new QQMapWX({ key // 必填 })); module.exports = { qqmapsdk, key }
这里我们引入SDK,并且将实例化对象直接传出去,但是这里需要给上腾讯的地图开放接口秘钥,这里我的key就不提供了,将key传出去是因为我们后面需要使用,为了不暴露自己的key,一般在开发时,key一般存储在后端的config中的,这里为了方便演示就在前端做处理了。
2.3 跳转选址页面前的处理
手机要定位不仅需要微信权限开启,还有我们的手机也有一个定位系统权限也要开启,所以在正式开始定位前,为了用户的更好体验我们这一块功能我们通常还需要一系列的操作,这里我简单的用button来用作跳转。
wxml
<view> <van-btn bind:tap="gotoMap" type="info">前往使用地图</van-btn> </view>
首先我们需要为按钮添加一个点击事件,这里我们可以处理很多事情;接下来让我们来看看js代码吧!
// 引入所需的工具函数 const app = getApp(); const {qqmapsdk} = app.require('utils/util'); Page({ /** * 地图开始位置 */ // 点击按钮跳转到地图页面 gotoMap(){ wx.showLoading({ title: "正在跳转至地图页" }) // 跳转前要做几件事情提高用户体验性 // 1. 要验证用户是否开启了定位,没有的话就引导 // 2. 还需验证程序的定位权限,没有的话就引导 // 3. 做好上面的两点才可以开始跳转了 wx.getLocation({ success(res){ wx.navigateTo({ url: "/pages/map/index" }) }, fail(e){ if (e && (e.errCode == 2 || e.errCode == 404)) { wx.showModal({ title: "提示", content: '位置信息获取失败,请检查手机“位置信息”是否未开启', showCancel: false }) } else if (e && ((e.errMsg.indexOf('getLocation:fail auth deny') != -1) || (e.errMsg.indexOf('system permission denied') != -1))) { showModal({ title: "提示", content: '位置信息获取失败,请检查微信是否有定位权限', confirmText: "重新获取", success(res){ if(res.confirm === true){ detectSettings() } else if(res.cancel == true){ return; } } }) } else if(e.errMsg.indexOf("频繁") !== -1){ wx.showModal({ title: "提示", content: "位置信息接口调用太频繁了,请等10-30秒后再操作。", showCancel: false }) } }, complete(){ wx.hideLoading() } }) // 引导开启微信定位权限 function detectSettings(){ wx.getSetting({ success(res){ if(res && (res.authSetting["scope.userLocation"] !== undefined && res.authSetting["scope.userLocation"] !==true)){ wx.showModal({ title: "提示", content:"小程序没有定位权限,请前往设置微信小程序的定位权限。", confirmText: "前往设置", success(res){ if(res.cancel == true){ return } else if (res.confirm === true){ wx.openSetting({ success(result){ if(result && (result.authSetting["scope.userLocation"] !== undefined && result.authSetting["scope.userLocation"] ===true)){ wx.navigateTo({ url: "/pages/map/index" }) } else { wx.navigateTo({ url: "/pages/index/index" }) } }, }) } }, fail(){ wx.navigateTo({ url: "/pages/index/index" }) } }) } else { wx.navigateTo({ url: "/pages/map/index" }) } }, complete(){ wx.hideLoading() } }) } } })
看完代码就看看效果吧,我们这里着重说明没有符合跳转的条件,效果如下GIF所示:
上面的GIF没有对手机定位系统未开做处理,这个演示在这个方面的处理比较简单,仅仅是提示一下就没了,日常开发中一般会有其他的更好的处理方式,未开的效果如下:
2.4 跳转后的处理
2.4.1 页面初始化
经过上一步的处理我们已经已经确定了,手机的两个权限都给到了,那么我们开始处理地图选址页面的处理,开始之前先看看成品是什么样的,如下:
wxml
<!--pages/map/index.wxml--> <view class="fixed top"> <van-search bind:search="searchSchool" placeholder="请输入学校名称" model:value="{{schoolName}}" /> <view class="school-nav"> <text class="left">附近的学校</text> <view class="right" bind:tap="changeCity"> <van-icon name="location-o" /> <text>{{city || "北京市"}}</text> </view> </view> </view> <view class="addr-cell" bindtap="subData"> <block wx:for="{{options}}" wx:key="index"> <van-cell data-chooseOpt="{{item}}" title-width="70vw" title="{{item.title}}" value="" label="{{item.address}}" /> </block> <view id="txt" class="btm"> <text wx:if="{{options.length}}">{{count>0 ? "下拉刷新获取更多信息" : "已经到底了"}}</text> <text class="no-data" wx:else>没有获取到相关的数据。。。</text> </view> </view>
整体框架就如上面的wxml所示,如果将数据全部提供就会像上图所示。那么接着说明一下他的逻辑实现吧!
// 引入所需的工具函数 const app = getApp(); const {qqmapsdk,key} = app.require('utils/util'); // 初始化生命周期函数 onLoad: function (options) { _this = this; _this.init() },
下面的函数不仅仅在加载时用到,在后面也会用到,我用传入的参数来区别。如果是在加载时调用,他仅仅是为了获取到用户的当前位置,获取到的位置用于显示;如果传入一个地址就将用于地址逆解析的。
// 你地址解析和获取当前位置 init(location){ let query = { success(res){ console.log(res) if(res.status === 0) { // console.log(res.result.location) app.globalData.adInfo = res.result.ad_info; _this.setData({ city: res.result.ad_info.city, lat: res.result.location.lat, lng: res.result.location.lng, }) _this.qqSearch(); } else { wx.showModal({ title: '提示', content:res.message || "获取地理位置信息失败。", showCancel: false }) } }, fail(e){ console.log(e) } } location && (query.location = location); qqmapsdk.reverseGeocoder(query); }
2.4.2 搜索功能实现
// 如果输入的是一个城市,就只会显示城市而不会显示学校 searchSchool(e){ // 没输入或者输入空格 if(e && (!e.detail || e.detail.trim() === '')){ wx.showToast({ title: "请输入有效的学校名称", icon: 'none', duration: 2000 }) return } _this.setData({ options:[], count: -2 }) _this.qqSearch(e.detail); }, qqSearch(name){ // 输入框输入的学校名称 wx.showLoading({ title: "正在获取信息" }) const mks = []; let count, boundary= `nearby(${_this.data.lat},${_this.data.lng},1000)`; search(name) function search(name){ const opts = { keyword: '大学', //搜索关键词 page_size: 15, page_index: _this.data.pageIndex, // 获取更多 key: key, boundary }; if(name){ opts.boundary = `region(${_this.data.city})` opts.keyword = name } // 这里主要是避免高频调用接口而导致的错误,所以只能使用URL获取相关信息 wx.request({ url: "https://apis.map.qq.com/ws/place/v1/search", method: "get", data:{ ...opts }, success: function (res) { //搜索成功后的回调 console.log(res) if(res.statusCode !== 200 || (res.data && res.data.status !== 0)) return; // 初始化和其他状态 // 计算可以下滑几次获取更多 if(_this.data.count === -1 || _this.data.count === -2){ count = res.data.count && Math.floor(res.data.count/10); }else { count = --_this.data.count; } for (let i = 0; i < res.data.data.length; i++) { mks.push({ // 获取返回结果,放到mks数组中 title: res.data.data[i].title, address: res.data.data[i].address, }) } }, fail: function (e) { console.log(e) wx.showToast({ title: JSON.stringify(e) || "获取地图信息失败", icon: "none", duration: 3000 }) }, complete: function (){ setTimeout(()=>{ wx.hideLoading() mks.push(..._this.data.options); _this.setData({ //设置markers属性,将搜索结果显示在地图中 options: mks, count }) },1000) } }); } },
2.4.3 下滑到底获取更多
// 下滑到底生命周期函数 onReachBottom: function () { _this.data.pageIndex = ++_this.data.pageIndex; _this.data.count && _this.qqSearch(); },
2.4.4 提交数据
对于提交数据这里就不多做处理了,选择的话就提示一下,在实际开发中一般都需要将数据存到数据库中另作他用。
subData(e){ const data = e.target.dataset.chooseopt; // 处理点击提示文字的情况 if(!data) return; wx.showModal({ title: "提示", content: `您所在学校是【${data.title}】吗?`, success(res){ // 取消 if(res.cancel) { return; } else if (res.confirm){ // 确定 // 向后端请求添加或者修改,一般需要详细的地址,这里简单处理 wx.showToast({ title: data.title, icon: "none" }) } }, fail(){ wx.showToast({ title: "失败", icon: "error" }) } }) }
2.4.5 切换城市
changeCity(){ _this.setData({ options:[], count:-2, // 简易的双向数据绑定,进入就清空输入框的内容 schoolName: '' }) wx.chooseLocation({ latitude:_this.data.lat, longitude:_this.data.lng, success(res){ if(res.errMsg === "chooseLocation:ok"){ // 获取到选择的位置,会通过地址逆解析去解析经纬度 _this.init(`${res.latitude},${res.longitude}`); } }, // 按取消按钮 fail(e){ if(e.errMsg === "chooseLocation:fail cancel"){ _this.init(); } }, complete(){ } }) }
到此,微信小程序学校选择就全部完成了,此次实战一步一步慢慢实现下来逻辑并不复杂。
总结
加载全部内容