超详细小程序定位地图模块全系列开发教学


Posted in Javascript onNovember 24, 2020

前言:如果想最大化吸取本文经验,须有小程序开发基础,本文细节比较多(多看注释的提醒内容),请耐心理解,多动手尝试,收获会更加丰富

1.定位系统使用场景及概述

如美团外卖小程序

超详细小程序定位地图模块全系列开发教学

点定位

超详细小程序定位地图模块全系列开发教学

点搜索

超详细小程序定位地图模块全系列开发教学

显而易见,随便一个电商小程序都需要用到定位服务,那么今天我们做一个类似的定位模块
定位模块总览
外部页面

超详细小程序定位地图模块全系列开发教学

内部页面(下文说的内外部页面就是指这两个)

超详细小程序定位地图模块全系列开发教学

好了接下来我们开始动手

2.定位外部模块样式

效果

超详细小程序定位地图模块全系列开发教学

代码

//wxml
<view bindtap="getLocation" class="location">
 <image src="../../img/location.png"></image>
 <view>{{location}}</view>
</view>
//wxss
.location{
 font-size: 17px;
 width: 100%;
 background:rgb(196, 228, 123);
 display: flex;
 /* 对于两个块元素 */
 /* 垂直居中 */
 align-items: center;
 /* 水平居中 */
 justify-content: center;
}
.location image{
 width: 23px;
 height: 23px;
}

先不用管上面的{{location}},它是我们之后要从全局变量传过来的位置信息,定位符号是用image图片放进去的,我们用flex布局让图片和文字在同一行居中显示(见注释)

3.定位模块内部样式

效果

超详细小程序定位地图模块全系列开发教学

代码(分五个小模块,见注释)

//wxml
//搜索模块
<view class="header">
 <view class="search">
<image src="../../img/sousuo.png"></image>
 </view>
 <view class="input">
<input type="text" placeholder=" 请输入你想要的内容" placeholder-class="placeholder" bindinput="bindInput" bindfocus="bindFocus" auto-focus="{{autoFocus}}"></input>
 </view>
</view>
//定位模块
<view class="dw">
<button size="mini" bindtap="getCity">
 <image src='../../img/location.png'></image>
 <text>定位</text>
 </button>
</view>
//当前位置模块
<view >当前所在位置</view>
<button size="mini" bindtap="nowCity" class='nowcity'>{{city}}</button>
//热门城市模块
<view class="hotcity">热门城市</view>
<view wx:for="{{hotcity}}" wx:key='index' class="hotcity1">
 <!-- 用了view循环之后要把view设置为inline元素,不然5个view会分成5行显示 -->
<button size="mini" bindtap="hotCity" data-hotcityindex='{{index}}'>{{item.cityName}}</button>
</view>
//地图模块
<view class="map">
<map longitude="{{longitude}}" latitude="{{latitude}}" scale="14"></map>
</view>

由于我的搜索框是用了自定义组件里面的搜索组件,我是在组件的基础上改出来的,原组件是这样的

超详细小程序定位地图模块全系列开发教学

我们需要把搜索图标隐藏,我们直接设置它的透明度为0,然后把我们的定位文字跟图标通过定位直接定位到搜索框的左边,所以样式的代码如下(代码太多不好找的话可以Ctrl+F直接搜索)

//wxss
.dw{
 color:rgb(0, 0, 0);
 position: absolute;
 top: 14px;
 left: -2px;
}
.dw button{
 background: white;
 padding-right: 0;
 display: flex;
 align-items: center;
 font-weight: 600 !important;
}
.nowcity{
 font-weight: normal;
}
.dw image{
 width: 23px;
 height: 23px;
}
page{
 padding: 10px;
}
.hotcity1 button{
 margin: 10px;
 margin-bottom: 0;
 font-weight: 500 !important;
  border-radius: 10px !important;
}
.hotcity{
 margin-top: 6px;
 
}
.map_container{
 position: absolute;
 top: 0;
 bottom: 0;
 left: 0;
 right: 0;
}
.header{
 display: flex;
}
.search{
flex:1;
height: 40px;
text-align: center;
background: #fff;
}
.input{
 flex:9;
 height: 40px;
 background: #fff;
}
.input input{
 background: #f1f1f1;
height: 30px;
margin-top: 5px;
margin-bottom: 5px;
margin-right: 8px;
border-radius: 10px;
}
.search image{
 width: 70%;
 height: 25px;
 padding-top: 9px;
 padding-left: 5px;
}
.placeholder{
 font-size: 14px;
}
.search image{
 opacity: 0;
}
.input{
 flex:4;
}
.input input{
position: relative;
right: 0px;
}
.hotcity1{
 display: inline;
}
.map{
 position: relative;
}
map{
 border:5px solid green;
 text-align: center;
 margin: 10px auto;
position: relative;
right: 10px;
 width: 90%;
 height: 150px;
}

然后我们的搜索里面点击搜索还会跳转到新的搜索页面,效果如下

超详细小程序定位地图模块全系列开发教学

这里我们可以直接复用上面的搜索组件,样式代码就不再贴出来了,这个模块要将搜索自动匹配的地点名称用循环的方式显示出来,代码如下

//wxml
<import src="../templates/search/search" />
<template is="search"></template>
<view bindtouchstart="bindSearch" data-keywords="{{i.name}}"
 class="text_box" wx:for="{{tips}}" wx:for-item="i" wx:key='index'>
 {{i.name}}
</view>
//wxss
@import '../templates/search/search.wxss';
.text_box{
 margin: 10px 25px;
 border-bottom:1px solid #c3c3c3;
 padding-bottom:10px
}

4.外部跳转

当我们点击外部的位置信息,就跳转到内部的定位模块,刚刚我们在上面给外部的标签设置了触摸事件getLocation,接下来只要到js里面设置点击跳转(navigateTo)就可以了,但由于我们的位置信息是用全局变量赋值的,所以我们要在app.js设置一个全局变量,代码如下

//app.js
App({
 globalData: {
  city:'暂未定位',
  userInfo:'无'
 },
 )}
//外部js
// 引入app.js
const app=getApp()
const appG=app.globalData
 data: {
//这里要初始化location,并将全局变量赋值给它
aboutList:'',
location:appG.city
 },
 Page({
 //定义触摸事件
 getLocation(){
 wx.navigateTo({
 //跳转到内部定位页面
  url: '../location/location',
 }) 
},
)}

5.点击定位

做这个功能之前我们需要先考虑用什么地图接口,常用的有百度地图,腾讯地图,高德地图,本文选用高德地图接口作为演示,搜索https://lbs.amap.com/,注册,进入控制台,创建新应用,

超详细小程序定位地图模块全系列开发教学

再添加key

超详细小程序定位地图模块全系列开发教学

这个key就像我们小程序调用接口时的验证码,有了它我们才能从高德调取位置的数据,然后我们点击key后面的设置,再点击微信小程序SDK

超详细小程序定位地图模块全系列开发教学

进去之后点这两个,下载amap-wx.js 文件,然后在你的小程序目录里面创建一个libs文件,把这个amap-wx.js扔进去

超详细小程序定位地图模块全系列开发教学

接下来我们来到内部定位页面的js文件,因为这里要对全局变量进行修改来达到修改页面数据的效果,所以也要引入app.js,并把全局变量初始化到data里面,除此之外我们要引入高德的文件来实现高德接口的调用,在data里面我们这里顺便把等会要用到的热门城市等数据一并初始化了

const app=getApp()
const appG=app.globalData
//key里面填高德控制台里面给你的key
const myAmapFun = new amapFile.AMapWX({key:'xxxxxxxxxx'});
 data: {
city:appG.city,
hotcity:[
 {'cityName':'北京市',longitude:'116.395645038',latitude:'39.9299857781'},
 {'cityName':'上海市',longitude:'121.487899486',latitude:'31.24916171'},
 {'cityName':'广州市',longitude:'113.307649675',latitude:'23.1200491021'},
 {'cityName':'深圳市',longitude:'114.025973657',latitude:'22.5460535462'},
 {'cityName':'武汉市',longitude:'114.316200103',latitude:'30.5810841269'},
],
tips: {},//搜索自动匹配的内容
longitude:'116.4',//经度(初始值在北京)
latitude:'39.9'//纬度(初始值在北京)
}

然后我们给定位按钮设置点击事件getCity,这里用到高德地图里面的获取地址描述数据方法,教程可以参考刚刚高德控制台微信SDK里面的教程(下面搜索自动匹配提示的教程也一样)

超详细小程序定位地图模块全系列开发教学

此外我们我们还要在小程序后台给高德的接口添加域名,操作步骤为
登录微信公众平台,“设置“?>"开发设置"设置request合法域名,将https://restapi.amap.com 中添加进去,这样我们才能请求到高德的数据

代码

getCity(){
 myAmapFun.getRegeo({
  success: data=>{
   // that.setData({
   //  city:data[0].desc.slice(0,2)
   // })
   appG.city=data[0].desc
   wx.getLocation({
    success:res=>{
this.setData({
  latitude:res.latitude,
  longitude:res.longitude
})
wx.setStorageSync('city', appG.city)
wx.setStorageSync('latitude', res.latitude)
wx.setStorageSync('longitude', res.longitude)
    }
   })
  },
  fail: function(info){
   //失败回调
   console.log(info)
  }
 })
},

getRegeo方法的成功回调函数里的参数包含了定位后的位置信息(可以自己输出一下),我们把它赋值给全局变量,然后再用setData再次把全局变量appG.city赋值给data里面的city(因为appG.city已经改变了,要重新赋值页面才会更新),除此之外我们还要把获取到的位置信息同步缓存起来,下次进入页面的时候在onLoad里面先判断有没有缓存的数据,如果有就直接使用缓存的数据,没有就用默认值,代码如下

onLoad: function (options) {
  // 进页面先看有无缓存数据,如果没有再读默认值,onLoad里面可以取到this.data
  const latitude=wx.getStorageSync('latitude')
  const longitude=wx.getStorageSync('longitude')
  const city=wx.getStorageSync('city')
  //用了三目运算符,不习惯也可以使用if
  latitude&&longitude&&city?
  this.setData({
   latitude:latitude,
   longitude:longitude
  }):false
 },

6.未定位时弹出定位框

给当前位置标签添加点击事件,判断当位置信息为初始值暂未定位时,弹出是否定位的选择框,当用户点击确定时,执行一次getCity函数即可,效果如下

超详细小程序定位地图模块全系列开发教学

代码

nowCity(){
 if(this.data.city!='暂未定位'){
  wx.switchTab({
   url: '../about/about',
  })
 }else{
  wx.showModal({
   title: '暂未定位',
   content: '现在要进行定位吗',
   success: (res)=>{
    if (res.confirm) {
     this.getCity()
    } else if (res.cancel) {
     return false
    }
   }
  })
 }
},

7.热门城市点击跳转,更新数据

超详细小程序定位地图模块全系列开发教学

当我们点击热门城市里面的按钮时,跳转到外部页面,并且把对应热门城市名称更新到全局的city来传到外部页面显示,同时还要更新全局中的经纬度数据,对于经纬度只要更新缓存即可,下一次进入内部定位页面时再判断缓存中有无定位数据,如果有就直接用,city数据是更新+缓存,代码如下

hotCity(e){
 const index=e.currentTarget.dataset.hotcityindex
 //更新
 appG.city=this.data.hotcity[index].cityName
 //缓存
  wx.setStorageSync('city', appG.city)
 wx.setStorageSync('latitude', this.data.hotcity[index].latitude)
 wx.setStorageSync('longitude', this.data.hotcity[index].longitude)
 //跳转
wx.reLaunch({
 url: '../about/about',
 success:()=>{
  // 不要把数据的更新写在这里,要在跳转之前就写好,因为这个回调函数是在跳转的页面所有函数
  // 执行完之后才执行的,会导致数据两次跳转次才更新
 }
})
},

上述代码中注意要在热门城市的循环标签用data-hotcityindex="{{index}}"把下标传到js中,再在js中用e.currentTarget.dataset.hotcityindex去取出来用,这个下标用来对应热门城市数组的每一个对象,这样我们就可以用this.data.hotcity[index].cityName来获取被点击的城市的名称,再把它更新到appG.city中,注意跳转的时候不能用wx.switchTab,因为从外部页面进来的时候已经打开了外部页面,那么用wx.switchTab的时候只会执行外部页面的onShow函数,而不会执行onLoad,会导致页面数据无法更新

8.搜索跳转和输入自动匹配地名

搜索跳转新页面(给内部定位页面设置聚焦事件)

bindFocus(e){
 wx.navigateTo({
  url: '../locationSearch/locationSearch',
 })
},

注意内部页面的搜索框不是自动聚焦的,而跳转到新的搜索页面的搜索框是会自动聚焦的,这一点我们可以通过在搜索组件的input标签添加auto-focus="{{autoFocus}}",再控制autoFocus的值来控制是否自动聚焦,代码如下

<template is="search" data="{{autoFocus}}"></template>

注意data="{{xxx}}"是自定义组件特有的传参方式,可以把js里面的值传到组件中使用不过我们得先在搜索页面的js的data中给autoFocus赋值,这里顺便把保存自动匹配的地名的值tips也初始化了

data: {
autoFocus:true,
tips:{}
 },

接下来我们写输入自动匹配地名,同样在搜索页面的js引入全局变量和高德js文件

const amapFile = require('../../libs/amap-wx.js');
const app=getApp()
const appG=app.globalData
const myAmapFun = new amapFile.AMapWX({key:'0c2c8f2007702caa7e0498d6ad072f83'});

然后我们来监听用户的输入行为,设置为bindInput函数

<input type="text" placeholder=" 请输入你想要的内容" placeholder-class="placeholder"
 bindinput="bindInput" bindfocus="bindFocus" auto-focus="{{autoFocus}}"></input>

搜索页面的js中定义bindInput

bindInput(e){
 myAmapFun.getInputtips({
  // keywords为必填,不然无法获得tips,也就不会进入success函数
  keywords:e.detail.value,
  success:data=>{
 this.setData({
  tips:data.tips
 })
  }
 })
},

上面的getInputtips就是我们第5点中讲到的微信小程序SDK中的获取提示词里面的方法,可以自己去看高德的教程,此处不再赘述,上面的keywords的值就是用户输入的内容,接口会根据这个去寻找对应匹配的地名并返回在success函数的参数中,我们只需要在成功回调函数中更新tips就可以了,那么此时假如我们输入武汉,效果如下

超详细小程序定位地图模块全系列开发教学

那么当我们点击自动匹配的地名的时候,需要返回到外部页面,并且更新数据,更新缓存,思路和上面的跳转方法是一样的,代码如下

bindSearch(e){
 const location=this.data.tips[e.currentTarget.dataset.searchindex]
 wx.setStorageSync('city', location.name)
 if(location.location.length!=0){
  const longitude=location.location.split(',')[0]
  const latitude=location.location.split(',')[1]
 wx.setStorageSync('latitude', latitude)
 wx.setStorageSync('longitude', longitude)
 wx.reLaunch({
  url: '../about/about',
   success:()=>{
       appG.city=e.currentTarget.dataset.keywords  
  }
 })
 }else{
  wx.reLaunch({
   url: '../about/about',
    success:()=>{
        appG.city=e.currentTarget.dataset.keywords  
        setTimeout(()=>{wx.showToast({
         title: '暂无经纬度数据',
        // 提示延迟时间,不能用字符串
         duration:2000,
         icon:'none'
        })
       },500);
   }
  })
 }

由于不是每一个自动匹配的地点都有经纬度,所以我们对没有经纬度的地名做业务退步处理,仅提醒暂无经纬度的数据,(有时候业务退一小步,技术就有一大步的发挥空间?《大型网站技术架构》——李智慧),细心的你们肯定注意到上面用了定时器,因为如果不使用定时器,这个弹框是不会显示出来的,这个函数在页面加载完成之前就已经执行了,所以我们给他来一个定时器作为异步函数延迟执行,才能有弹框

9.对整个模块的优化和思考

对上述代码,笔者开发完之后发现了如下问题:
代码冗余严重,主要表现在多次使用缓存的api,重复量的地方很多
整个模块内部互相调用复杂,高耦合,低拓展
某些地方把简单的逻辑复杂化了,代码不够整洁
对于上述问题,笔者有如下思考:
通过封装缓存api来减少不必要的代码量,提高代码整洁度
对整个模块重新构思,提高可拓展性和可复用性(由于笔者水平有限,暂时搁置)
模块从开发开始到开发完成需要不断的演化和改进,这个过程才是让开发者成长的关键

到此这篇关于超详细小程序定位地图模块全系列开发教学 的文章就介绍到这了,更多相关小程序定位地图内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
破除一些网站复制、右键限制
Nov 04 Javascript
javascript hashtable 修正版 下载
Dec 30 Javascript
jquery如何获取复选框的值
Dec 12 Javascript
解决html按钮切换绑定不同函数后点击时执行多次函数问题
May 14 Javascript
javascript实现的HashMap类代码
Jun 27 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
Sep 04 Javascript
javascript检测两个数组是否相似
May 19 Javascript
详解JavaScript函数
Dec 01 Javascript
jQuery图片切换动画效果
Feb 28 Javascript
Bootstrap一款超好用的前端框架
Sep 25 Javascript
MVVM框架下实现分页功能示例
Jun 14 Javascript
爬虫利器Puppeteer实战
Jan 09 Javascript
JavaScript实现移动端拖动元素
Nov 24 #Javascript
小程序组件传值和引入sass的方法(使用vant Weapp组件库)
Nov 24 #Javascript
js实现抽奖功能
Nov 24 #Javascript
前端 javascript 实现文件下载的示例
Nov 24 #Javascript
如何使用 JavaScript 操作浏览器历史记录 API
Nov 24 #Javascript
JavaScript实现鼠标移入随机变换颜色
Nov 24 #Javascript
原生js实现表格循环滚动
Nov 24 #Javascript
You might like
《星际争霸II》全新指挥官斯台特曼现已上线
2020/03/08 星际争霸
轻松修复Discuz!数据库
2008/05/03 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
PHP获取数组中重复最多的元素的实现方法
2014/11/11 PHP
Thinkphp5.0框架的Db操作实例分析【连接、增删改查、链式操作等】
2019/10/11 PHP
jQuery 学习第六课 实现一个Ajax的TreeView
2010/05/17 Javascript
JavaScript的类型简单说明
2010/09/03 Javascript
关于COOKIE个数与大小的问题
2011/01/17 Javascript
深入解析contentWindow, contentDocument
2013/07/04 Javascript
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
jquery解析xml字符串示例分享
2014/03/25 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
2016/04/26 Javascript
vue中渐进过渡效果实现
2016/10/27 Javascript
AngularJS表单基本操作
2017/01/09 Javascript
VueJs路由跳转——vue-router的使用详解
2017/01/10 Javascript
jquery滚动条插件slimScroll使用方法
2017/02/09 Javascript
Angular中管道操作符(|)的使用方法
2017/12/15 Javascript
Vue.js 使用v-cloak后仍显示变量的解决方法
2018/11/19 Javascript
[02:45]DOTA2英雄敌法师基础教程
2013/11/25 DOTA
[48:52]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第一局
2016/02/25 DOTA
python进程类subprocess的一些操作方法例子
2014/11/22 Python
Python使用time模块实现指定时间触发器示例
2017/05/18 Python
python flask中静态文件的管理方法
2018/03/20 Python
浅谈pyqt5在QMainWindow中布局的问题
2019/06/21 Python
细说NumPy数组的四种乘法的使用
2020/12/18 Python
python实现马丁策略回测3000只股票的实例代码
2021/01/22 Python
HTML5有哪些新特征
2015/12/01 HTML / CSS
Spartoo荷兰:鞋子、包包和服装
2018/07/12 全球购物
RIP版本1跟版本2的区别
2013/12/30 面试题
成教自我鉴定
2013/10/27 职场文书
新学期校长寄语
2014/01/18 职场文书
阳光体育活动实施方案
2014/05/25 职场文书
不遵守课堂纪律的检讨书
2014/09/24 职场文书
汽车机电维修工求职信
2014/09/30 职场文书
开发者首先否认《遗弃》被取消的传言
2022/04/11 其他游戏