欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

自动导航项目 - 微信小程序实践

最编程 2024-03-28 16:16:37
...

笔记来源:拉勾教育 - 大前端就业集训营

文章内容:学习过程中的笔记、感悟、和经验

提示:项目实战类文章资源无法上传,仅供参考

开发高德地图小项目

截屏2021-08-19 15.12.11

申请高德地图开发者

截屏2021-08-19 15.15.08

  • 注册高德地图开发者账号:官网地址
  • 创建应用:管理应用 => 我的应用 => 创建新应用
  • 创建应用密钥:应用不同,密钥不同(安卓 / ios / web / 小程序)

详解高德微信小程序SDK

  • 下载小程序SDK
    • 本质上SDK是wx.requestWEB服务API的封装,无论哪个平台兼容性有保障
    • 小程序的运行环境实际上就是内置的浏览器环境
    • 截屏2021-08-19 15.36.24

高德小程序SDK部分常用接口

API 描述
getWxLocation 获取位置信息(通过高德API获取)
getRegeo 获取地理描述信息(将经纬度转成行政区划名称)
getWeather 当前位置的天气信息,数据较少建议使用和风天气
getPoiAround 查询周围兴趣点(POI: Point of Interest),例如搜索
getStaticmap 获取静态地图(不能拖动)
getInputtips 获取输入提示词(关键字查询)
getWalkingRoute 步行路线规划
getDrivingRoute 驾车路线规划
getRidingRoute 骑行路线规划
getTransitRoute 公交地铁路线规划(和前三个参数有区别)

高德地图的SDK中的接口函数大部实际上就是将小程序的云API进行二次封装的产物

首页接入高德地图

  • 小程序启动时获取当前位置,并存到本地
  • 拷贝高德SDK文件到项目中,并创建高德SDK配置文件
  • 创建高德SDK实例对象,写入KEY,最后导出实例对象
  • 首页页面加载时进行逆地址解析(高德 - getRegeo)获取实际地址
  • 书写map地图组件,添加相关属性
  • 首页js文件中解析之前存在本地的经纬度数据
  • 直接使用高德返回的数据做定位点数据
  • 调整样式,让地图全屏显示
  • 添加底部地址栏,绝对定位,使用getRegeo返回数据
// app.json
{
  "pages": [
    // 添加一个页面
    "pages/home/home",
    "pages/index/index",
    "pages/logs/logs"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "Weixin",
    "navigationBarTextStyle": "black"
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json",
  // 获取当前位置
  "permission": {
    "scope.userLocation": {
      "desc": "尝试获取位置信息"
    }
  },
  // 设置底部导航
  "tabBar": {
    "list": [{
      "pagePath": "pages/home/home",
      "text": "首页",
      "iconPath": "./static/images/featured.png",
      "selectedIconPath": "./static/images/featured-actived.png"
    }, {
      "pagePath": "pages/index/index",
      "text": "欢迎",
      "iconPath": "./static/images/featured.png",
      "selectedIconPath": "./static/images/featured-actived.png"
    }, {
      "pagePath": "pages/logs/logs",
      "text": "日志",
      "iconPath": "./static/images/featured.png",
      "selectedIconPath": "./static/images/featured-actived.png"
    }]
  }
}
// app.js
App({
  onLaunch() {
    // 展示本地存储能力
    const logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登录
    wx.login({
      success: res => {
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
    // 获取当前位置
    wx.getLocation({
      type: 'gcj02',
      // 成功后存储经纬度到本地
      success (res) {
        wx.setStorageSync('latitude', res.latitude)
        wx.setStorageSync('longitude', res.longitude)
      }
     })
  },
  globalData: {
    userInfo: null
  }
})
// utils/amap-config.js  高德地图SDK配置

// 引入高德SDK
const amapfile = require('./amap-wx.130')

// 创建实例
const map = new amapfile.AMapWX({
  key: '842828a8a2bce6537a91450390dd5471'
})

// 导出
module.exports = {
  map
}
// pages/home/home.js

const amap = require('../../utils/amap-config')
Page({

  /**
   * 页面的初始数据
   */
  data: {
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 存储this指向
    const that = this
    // 读取本地位置信息,存储进data
    that.setData({
      longitude: wx.getStorageSync('longitude'),
      latitude: wx.getStorageSync('latitude')
    })
    // 调用高德逆地址解析,获取坐标的位置信息
    amap.map.getRegeo({
      // 成功调用
      success: res => {
        console.log(res);
        // 使用数据作为标记信息
        // 设置标记使用图片
        res[0].iconPath = '/static/images/location.png'
        // 存储标记数据到本地
        that.setData({
          markers: res
        })
      },
      // 失败打印失败信息
      fail: err => {
        console.log(err)
      }
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
<!--pages/home/home.wxml-->
<view class="container">
  <!-- 地图组件,设置经纬度、标记点信息 -->
  <map class="map" name="" longitude='{{longitude}}' latitude='{{latitude}}' markers='{{markers}}' scale="14"></map>
  <!-- 底部浮动位置展示 -->
  <view class="map-text">
    <text>{{markers[0].name}}</text>
    <text>{{markers[0].desc}}</text>
    <view class="button-sp-area">
			<a class="weui-btn weui-btn_mini weui-btn_primary">按钮</a>
		</view>
  </view>
</view>
/* pages/home/home.wxss */
/* // 首页单独设置样式 */
.container {
  height: 100vh;
  width: 100vw;
}

/* 地图 */
.map {
  width: 100%;
  height: 100%;
}

/* 底部文本 */
.map-text {
  position: relative;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  background-color: #fff;
  /* text-align: center; */
}
.map-text > text {
  display: block;
  margin: 10px 20px;
}
.map-text > text:nth-child(2) {
  font-size: 14px;
  color: #666;
}
.map-text > .button-sp-area {
  position: absolute;
  right: 20px;
  top: 50%;
  margin-top: -16px;
}

输入提示

截屏2021-08-20 10.22.20

使用高德地图API - getInputtips()

  • 搜索框使用WEUI搜索框组件,拷贝js和WXML
  • 在输入事件中添加逻辑,使用输入的内容调用API获取输入提示
  • 可以把这个逻辑单独封装为一个函数
  • 存储拿到的提示数据到data中
  • 使用weUI的列表组件展示输入提示数据,如果有提示数据才显示
  • 遍历数据列表,创建结构
  • 可能会和之前写的文字提示冲突,把底部文字提示改成固定定位即可
  • 添加判断条件,如果输入内容为空,清空数据,不为空才请求数据
  • 记得取消按钮也要清空数据
/**app.wxss**/
/* 引入WeUI */
@import './weui.wxss';

.container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  /* padding: 200rpx 0; */
  box-sizing: border-box;
}
<!--pages/home/home.wxml-->
<view class="container">
  <!-- 顶部搜索框 -->
  <view class="page__bd">
    <view class="weui-search-bar {{inputShowed ? 'weui-search-bar_focusing' : ''}}" id="searchBar">
      <form class="weui-search-bar__form">
        <view class="weui-search-bar__box">
          <i class="weui-icon-search"></i>
          <input type="text" class="weui-search-bar__input" placeholder="搜索" value="{{inputVal}}"
            focus="{{inputShowed}}" bindinput="inputTyping" />
          <span class="weui-icon-clear" wx:if="{{inputVal.length > 0}}" bindtap="clearInput"></span>
        </view>
        <label class="weui-search-bar__label" bindtap="showInput">
          <i class="weui-icon-search"></i>
          <span class="weui-search-bar__text">搜索</span>
        </label>
      </form>
      <view class="weui-search-bar__cancel-btn" bindtap="hideInput">取消</view>
    </view>
    <view class="weui-cells searchbar-result" wx:if="{{inputVal.length > 0}}">
      <!-- 遍历数据创建搜索提示结果 -->
      <view class="weui-cell weui-cell_active weui-cell_access" wx:for="{{tips}}" wx:key='{{item.id}}}'>
        <view class="weui-cell__bd weui-cell_primary">
          <view>{{item.name}}</view>
        </view>
      </view>
    </view>
  </view>
  <!-- 地图组件,设置经纬度、标记点信息 -->
  <map class="map" name="" longitude='{{longitude}}' latitude='{{latitude}}' markers='{{markers}}' scale="14"></map>
  <!-- 底部浮动位置展示 -->
  <view class="map-text">
    <text>{{markers[0].name}}</text>
    <text>{{markers[0].desc}}</text>
    <view class="button-sp-area">
			<a class="weui-btn weui-btn_mini weui-btn_primary">按钮</a>
		</view>
  </view>
</view>
/* pages/home/home.wxss */
/* // 首页单独设置样式 */
.container {
  height: 100vh;
  width: 100vw;
}

/* 地图 */
.map {
  width: 100%;
  height: 100%;
}

/* 底部文本 */
.map-text {
  position: relative;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  background-color: #fff;
  /* text-align: center; */
}
.map-text > text {
  display: block;
  margin: 10px 20px;
}
.map-text > text:nth-child(2) {
  font-size: 14px;
  color: #666;
}
.map-text > .button-sp-area {
  position: absolute;
  right: 20px;
  top: 50%;
  margin-top: -16px;
}

/* 搜索框 */
.page__bd {
  width: 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1;
}

.searchbar-result {
  margin-top: 0;
  font-size: 12px
}

.searchbar-result .weui-cell {
  padding: 10px;
}
.searchbar-result .weui-cell__bd {
  padding: 0 0 0 20px;
  color: #999;
}

.searchbar-result:before {
  display: none
}
// pages/home/home.js

const amap = require('../../utils/amap-config')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    inputShowed: false,
    inputVal: ""
  },
  // 点击电视搜索框时间事件函数
  showInput: function () {
    this.setData({
      inputShowed: true
    });
  },
  // 取消按钮点击事件函数
  hideInput: function () {
    this.setData({
      inputVal: "",
      inputShowed: false
    });
  },
  // 清空按钮点击事件函数
  clearInput: function () {
    this.setData({
      inputVal: ""
    });
  },
  // 文本框输入事件
  inputTyping: function (e) {
    //存储输入内容
    this.setData({
      inputVal: e.detail.value
    });
    // 调用方法获取提示数据
    this.getTips(e.detail.value)
  },
  // 获取输入提示数据
  getTips: function (keywords) {
    // 存储this指向
    const that = this
    // 调用高德方法获取输入提醒
    amap.map.getInputtips({
      // 输入内容
      keywords,
      // 位置信息
      location: that.data.longitude + ',' + that.data.latitude,
      // 成功后调用
      success: (res) => {
        // 如果获取成功存储数据
        if(res && res.tips) that.setData({tips: res.tips})
        console.log(that.data.tips);
      }
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 存储this指向
    const that = this
    // 读取本地位置信息,存储进data
    that.setData({
      longitude: wx.getStorageSync('longitude'),
      latitude: wx.getStorageSync('latitude')
    })
    // 调用高德逆地址解析,获取坐标的位置信息
    amap.map.getRegeo({
      // 成功调用
      success: res => {
        console.log(res);
        // 使用数据作为标记信息
        // 设置标记使用图片
        res[0].iconPath = '/static/images/location.png'
        // 存储标记数据到本地
        that.setData({
          markers: res
        })
      },
      // 失败打印失败信息
      fail: err => {
        console.log(err)
      }
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

查找周围兴趣点

截屏2021-08-20 16.39.08

调用高德地图 getPoiAround()方法获取兴趣点数据

  • 选中一个点:展示当前点文本信息、高亮当前点、导航到该点(后续再说)

  • 另起一页:借助WeUI的九宫格组件,给出一些常用关键词,设置图标图片、尺寸

  • 在新页面下另起一页,放置兴趣点地图

  • 给九宫格添加点击事件,跳转兴趣点地图

    • 跳转需要传参,使用data-参数名,读取使用e.currentTarget.dataset.属性名
    • 书写点击事件,判断是否有关键词属性,有则跳转 - navigateTo,使用?传参
  • 页面接受参数,使用onLader中参数可以获取

  • 将关键字设置为标题 - setNavigationBarTitle

  • 使用高德地图API - 查找周围兴趣点

    • 页面引入高德地图,调用API,传递参数,获取数据
  • 返回的markers可以作为定位点标记数据,注意保存一份全局数据,以便后期使用

  • 存储定位点标记和当前位置经纬度数据到data

  • 书写地图标签,展示地图,绑定数据 (参考首页地图)

  • 添加两个函数:

    • 展示当前点信息,存储到data中,然后绑定给底部展示区,记得绑定位置,后面导航需要用
    • 修改当前点图标:更改当前点图标,恢复其他点图标,保存新的标记数据到data - markers
  • 添加点击标记点事件 - bindmarkertap:参数e带有当前点信息,从里面获取id,再次调用上面的展示当前点信息和修改当前点图标两个方法

{
  "pages": [
    // 新页面
    "pages/index/index",
    // 二级页面
    "pages/index/around",
    "pages/home/home",
    "pages/logs/logs"
  ],
  ...............
}
<!--index.wxml-->
<view class="page" data-weui-theme="{{theme}}">
	<view class="page__hd">
		<view class="page__desc">查找周边</view>
	</view>
  <!-- 宫格组件 -->
	<view class="weui-grids">
  <!-- 遍历数据创建宫格组件,添加点击事件跳转,设置自定义属性方便携带参数 -->
		<a class="weui-grid" wx:for="{{around_title}}" wx:key="key" bindtap="toAround" data-keyword="{{item}}">
			<view class="weui-grid__icon">
				<image src="../../static/images/featured.png" alt></image>
			</view>
			<view class="weui-grid__label">{{item}}</view>
		</a>
	</view>
</view>
// index.js
const app = getApp()

Page({
  data: {
    // 创建宫格使用的文本
    around_title: ['美食','酒店','加油站','医院','药店','银行','地铁','公交站','厕所']
  },
  onLoad() {
  },
  // 点击事件函数
  toAround: (e) => {
    // 微信跳转API
    wx.navigateTo({
      // 给路由携带参数
      url: `around?keyword=${e.currentTarget.dataset.keyword}`,
    })
  }
})
/**index.wxss**/
.weui-grid image {
  height: 30px;
  width: 30px;
}
.page__hd {
  margin-left: 20px;
}
<!--pages/index/around.wxml-->
<view class="container">
<!-- 地图组件,绑定数据,添加点击标记点事件 -->
  <map class="map" name="" longitude='{{longitude}}' latitude='{{latitude}}' markers='{{markers}}' scale="14" bindmarkertap="chagenMarker"></map>
  <!-- 底部浮动位置展示 -->
  <view class="map-text">
  <!-- 绑定数据 -->
    <text>{{info.name}}</text>
    <text>{{info.address}}</text>
    <view class="button-sp-area">
      <a class="weui-btn weui-btn_mini weui-btn_primary">按钮</a>
    </view>
  </view>
</view>
// pages/index/around.js

// 引入高德地图
const {
  map
} = require('../../utils/amap-config')
// 创建全局标记点数据,后面获取到数据存到这
let markersData = []
Page({
  /**
   * 页面的初始数据
   */
  data: {
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 绑定this指向
    const that = this
    // 获取搜索关键词
    const keyword = options.keyword
    // 修改顶部标题
    wx.setNavigationBarTitle({
      title: '周边' + keyword,
    })
    // 调用高德API获取兴趣点
    map.getPoiAround({
      // API参数 - 关键词
      querykeywords: keyword,
      // 成功后调用
      success: res => {
        // 存储获取数据
        markersData = res.markers
        // 如果获取到内容
        if (markersData.length > 0) {
          // 保存数据到data
          that.setData({
            markers: markersData,
            // 经纬度
            latitude: wx.getStorageSync('latitude'),
            longitude: wx.getStorageSync('longitude')
          })
        }
        // 调用方法修改文字,默认选中第一个数据
        that.saveInfo(markersData, 0)
        // 调用方法修改选中图标,默认选中第一个数据
        that.chagenIcon(markersData, 0)
      }
    })
  },
  // 修改底部文字方法
  // 参数:数据源、索引值
  saveInfo: function (data, index) {
    // 直接修改data中的数据
    this.setData({
      info: {
        name: data[index].name,
        address: data[index].address,
        id: data[index].id
      }
    })
  },
  // 修改图标方法
  // // 参数:数据源、索引值
  chagenIcon: function (data, index) {
    // 创建空数组获存放新数据
    let newMarkersData = []
    // 遍历数据源
    for (let i = 0; i < data.length; i++) {
      // 数据
      const markerItem = data[i]
      // 修改选中数据的图标,把其他图标恢复成默认
      if (i === index) {
        markerItem.iconPath = '../../static/images/marker_checked.png'
      } else {
        markerItem.iconPath = '../../static/images/marker.png'
      }
      // 将数据存放到数组
      newMarkersData.push(markerItem)
    }
    // 最后保存新数据修改data
    this.setData({
      markers: newMarkersData
    })
  },
  // 点击标记点事件函数
  chagenMarker: function (e) {
    // 获取id
    const id = e.detail.markerId
    // 直接调用上面两个函数传参即可
    this.saveInfo(markersData, id)
    this.chagenIcon(markersData, id)
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
/* pages/index/around.wxss */
/* // 首页单独设置样式 */
.container {
  height: 100vh;
  width: 100vw;
}

/* 地图 */
.map {
  width: 100%;
  height: 100%;
}

/* 底部文本 */
.map-text {
  position: relative;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  background-color: #fff;
  /* text-align: center; */
}

/* // 底部文本 */
.map-text > text {
  display: block;
  margin: 10px 20px;
}
.map-text > text:nth-child(2) {
  font-size: 14px;
  color: #666;
}
.map-text > .button-sp-area {
  position: absolute;
  right: 20px;
  top: 50%;
  margin-top: -16px;
}

路径规划

步行出行

截屏2021-08-24 13.59.08

使用高德getWalkingRoute

  • 两个点坐标

    • 起点:当前定位
    • 终点:其他方式获取,搜索或者兴趣点
  • 底部可以查看步行导航描述

  • 创建路径规划页面

  • 给搜索框下拉列表绑定点击事件,点击后跳转到路径规划页面 - bindtap

  • 跳转时携带参数,参数为终点坐标

  • 路径规划页面顶部tab菜单使用WeUI - tabbar进行改造

  • tab上面不同的选项跳转到不同的页面(步行、骑行、驾车、公交),所以需要有四个导航页面,给四个tab都添加自定义属性(和页面名称一致),方便之后跳转

  • 设置tab图标,调整样式

  • tab添加点击事件,点击后跳转相应页面,跳转路径不仅要有路径,还要传经纬度

  • 跳转过来时判断是否传递了经纬度,没传递报错

  • 给定起点和终点标记数据(图标、经纬度)

  • 放入地图组件,绑定数据查看起点终点是否加载

  • 起点终点连线使用polyline属性设置,绑定data数据

  • 调用高德地图步行导航接口getWalkingRoute,传递起点和终点坐标,接收数据

  • 返回数据中的steps中的每一个成员的polyline值即为路径每一个经过的点坐标,把所有点坐标拼接(成数组)起来就成为一条线

  • 一个polyline可拆分出多个坐标,最红把这些都拆分成一组组经纬度

  • 最后把这些点数据传递给data,另外设置颜色、宽度

  • 获取导航文本信息,从路径接口返回数据中(保存在data中)

  • 同时还需要把距离、预计时间保存

  • 页面底部添加盒子书写结构 绑定数据

  • 添加一个详情按钮,点击可展开详情,这里建议底部高度使用动态高度,在data里面指定,点击的时候只需要修改值即可

  • 另外,文本列表也可以动态显示,没有点击详情时不显示,点击后才加载

  • 给详情按钮添加点击事件,每次判断当前是否处于展开状态(列表是否显示),进行data修改

  • 最后进行样式调整

// 添加四个页面分别放置四个导航页
"pages": [
  "pages/home/home",
  "pages/index/index",
  "pages/index/around",
  "pages/logs/logs",
  "pages/rout