taro 兼容支付宝小程序和微信小程序<四> -- 腾讯地图和高德地图api

背景:taro3 + vue3

项目中用到的功能描述:

  1. 坐标转位置描述(逆地址解析)
  2. 关键词输入提示
  3. 路线规划
  4. 距离计算

方案
微信小程序–>腾讯地图 ----- 腾讯位置服务
支付宝小程序–>高德地图 ----- 高德web服务API

一、经纬度获取
let errorInfo = {
  errMsg: ''
}
Taro.getLocation({
 type,
 isHighAccuracy: true,
 success: res => {
   // do sth.
 },
 fail: error => {
   // 这里支付宝和微信的error是不一样的
   if (isAlipay) {
     const { message } = error
     errorInfo.errMsg = message
   }
   if (isWeapp) {
     errorInfo = error
   }
   // do sth.
 },
 complete: res => {
 }
})
二、引入
// map.js
let mapInstance = null
let secretKey = ''
if (isWeapp) {
  const { key, secretKey: sKey } = TenXunMap
  const QQMapWX = require('../plugin/qqmap-wx-jssdk.min')
  secretKey = sKey
  mapInstance = new QQMapWX({
    key
  })
} else if (isAlipay) {
  const { key } = GaoDeMap
  const GdMap = require('../utils/gdMap').GdMap
  mapInstance = new GdMap({
    key
  })
}

思路:

  1. qqmap-wx-jssdk.min.js是腾讯位置服务的sdk, 而高德地图对于支付宝没有sdk, 需要封装下web api, 这里是封在 utils/gdMap.js
  2. gdMap中封装的方法名与腾讯方法名保持一致,在map.js中就可以直接调用mapInstance .xxx(), 将腾讯和高德的结果以统一的数据格式用回调的方式返回出去,在页面或者别的地方就可以做需要的数据处理
  3. 统一的数据格式 如下
let outRes = {
   originalData: {},  // 原数据
   modifiedData: {}  // 统一的数据
 }
三、逆地址解析(坐标位置描述)

1、参数

// 腾讯
let params = {
  location: `${latitude},${longitude}`, // 也可以是object
  sig: secretKey,
}
// 高德
let params = {
  location: `${longitude},${latitude}`
}

!!!注意:高德的location只能是string, 并且经度在前,纬度在后,而腾讯的string是lat<纬度>,lng<经度>, 两者相反

2、高德

// gdMaap.js
/**
   * 逆地址解析
   * @param location
   * @param success
   * @param fail
   */
  reverseGeocoder({location, success = () => {}, fail = () => {}}) {
    const params = {
      key: this.key,
      location
    }
    Taro.request({
      url: 'https://restapi.amap.com/v3/geocode/regeo',
      data: params,
      header: {
        'content-type': 'application/json'
      },
      method: 'GET',
      success: (data) => {
        const res = data['data']
        success(res)
      },
      fail: (error) => {
        fail(error)
      }
    })
  }

在这里插入图片描述
在这里插入图片描述

3、统一调用, 结果处理成统一格式

// map.js
/**
 * 逆地址解析(坐标位置描述)
 * @param param object {location, success, fail}
 */
reverseCoordinateToTxt(param) {
  const { location: {latitude, longitude }, success, fail } = param
  let params = {}
  let outRes = {
    originalData: {},
    modifiedData: {}
  }
  let dealDataFn = () => {}
  if (isWeapp) {
    params = {
      location: `${latitude},${longitude}`,
      sig: secretKey,
    }
    dealDataFn = data => {
      const { status, message, result } = data

      if (status !== 0 || !result) {
        fail(fail(`status: ${status}, errMsg: ${message}`))
        return
      }
      const { address, address_component, location: { lat, lng } } = result
      const { district, street_number } = address_component
      outRes.originalData = data
      outRes.modifiedData = {
        district,
        street_number,
        address,
        latitude: lat,
        longitude: lng
      }
      success(outRes)
    }
  } else if (isAlipay) {
    params = {
      location: `${longitude},${latitude}`
    }
    dealDataFn = data => {
      const { status, infocode, info, regeocode } = data
      if (status !== '1' || !regeocode) {
        fail(fail(`status: ${status}, infocode: ${infocode}, errMsg: ${info}`))
        return
      }
      const { formatted_address, addressComponent } = regeocode
      const { district, streetNumber: { street, number, location } } = addressComponent
      const locationList = location.split(',')
      outRes.originalData = data
      outRes.modifiedData = {
        district,
        street_number: `${street}${number}`,
        address: formatted_address,
        latitude: locationList[1],
        longitude: locationList[0]
      }
      success(outRes)
    }
  }

  mapInstance.reverseGeocoder({
    ...params,
    success: (res) => {
      dealDataFn(res)
    },
    fail: (error) => {
      fail(error)
    }
  })
}
四、关键词输入提示

1、参数

// 腾讯
let params = {
   keyword,
   sig: secretKey,
   region: '北京',
   region_fix: 1,
   page_size: pageSize,
   page_index: page,
 }
// 高德
let params = {
  keywords: keyword,
  city: '北京',
  offset: pageSize,
  page,
}

2、高德

// gdMaap.js
/**
  * 关键字搜索poi
  * @param keywords
  * @param city
  * @param page
  * @param offset
  * @param success
  * @param fail
  */
 getSuggestion({keywords, city, page, offset = 20, success = () => {}, fail = () => {}}) {
   const searchParam = {
     key: this.key,
     keywords,
     types: '',
     city,
     citylimit: true,
     children: 0,
     offset,
     page,
     extensions: 'base',
     sig: ''
   }
   Taro.request({
     url: 'https://restapi.amap.com/v3/place/text',
     data: searchParam,
     header: {
       'content-type': 'application/json'
     },
     method: 'GET',
     success: (data) => {
       const res = data['data']
       success(res)
     },
     fail: (error) => {
       fail(error)
     }
   })
 }

在这里插入图片描述
在这里插入图片描述

3、统一调用, 结果处理成统一格式

// map.js
/**
  * 关键字输入提示
  * @param keyword 关键字
  * @param page 当前页
  * @param pageSize  每页条目数
  * @param success 成功
  * @param fail 失败
  */
 searchKeyWord({ keyword, page, pageSize, success = () => {}, fail = () => {} }) {
   let params = {}
   let outRes = {
     count: 0,
     originalData: {},
     modifiedData: []
   }
   let dealDataFn = () => {}
   if (isWeapp) {
     params = {
       keyword,
       sig: secretKey,
       region: '北京',
       region_fix: 1,
       page_size: pageSize,
       page_index: page,
     }
     dealDataFn = (res) => {
       const { status, count, data, message } = res
       if (status !== 0 || !data) {
         fail(`status: ${status}, errMsg: ${message}`)
         return
       }
       outRes.count = count
       outRes.originalData = res
       outRes.modifiedData = data.map(item => {
         const { id, type, title, address, location } = item
         return {
           id,
           title,
           addressStr: type === 1 || type === 2 ? MAP_POI_TYPE[type] : address,
           location
         }
       })
       success(outRes)
     }
   } else if(isAlipay) {
     params = {
       keywords: keyword,
       city: '北京',
       offset: pageSize,
       page,
     }
     dealDataFn = (res) => {
       const { status, info, count, pois } = res
       if (status !== '1' || !pois) {
         fail(`status: ${status}, errMsg: ${info}`)
         return
       }
       outRes.count = +count
       outRes.originalData = res
       outRes.modifiedData = pois.map(item => {
         const { id, name, address, location } = item
         const locationList = location.split(',')
         return {
           id,
           title: name,
           addressStr: address,
           location: {
             lat: locationList[1],
             lng: locationList[0]
           }

         }
       })
       success(outRes)
     }
   }
   mapInstance.getSuggestion({
     ...params,
     success: (res) => {
       dealDataFn(res)
     },
     fail: (error) => {
       fail(error)
     }
   })
 }
五、 路线规划

1、参数

// 腾讯
let params = {
  from: {latitude: xx, longitude: xx},
  to: {latitude: xx, longitude: xx},
  sig: secretKey
}
// 高德
let params = {
  origin: `${longitude},${latitude}`,
  destination: `${longitude},${latitude}`
}

2、高德

// gdMaap.js
/**
 * 路径规划
 * @param origin
 * @param destination
 * @param success
 * @param fail
 */
direction({origin, destination, success = () => {}, fail = () => {}}) {
  const params = {
    key: this.key,
    origin,
    destination,
  }
  Taro.request({
    url: 'https://restapi.amap.com/v3/direction/driving',
    data: params,
    header: {
      'content-type': 'application/json'
    },
    method: 'GET',
    success: (data) => {
      const res = data['data']
      success(res)
    },
    fail: (error) => {
      fail(error)
    }
  })
}

3、统一调用, 结果处理成统一格式

// map.js
/**
 * 路线规划
 * @param from 起点
 * @param to 终点
 * @param success
 * @param fail
 */
direction({ from, to, success, fail }) {
  let params = {}
  let outRes = {
    originalData: {},
    modifiedData: {}
  }
  let dealDataFn = () => {}
  if (isWeapp) {
    params = {
      from,
      to,
      sig: secretKey
    }
    dealDataFn = data => {
      const { status, message, result } = data
      if (status !== 0 || !result) {
        fail(fail(`status: ${status}, errMsg: ${message}`))
        return
      }
      const { routes } = result
      const { polyline } = routes[0]
      outRes.originalData = data
      outRes.modifiedData = {
        polyline: this._getPolylineListInTx(polyline)
      }
      success(outRes)
    }
  } else if (isAlipay) {
    params = {
      origin: `${from.longitude},${from.latitude}`,
      destination: `${to.longitude},${to.latitude}`
    }
    dealDataFn = data => {
      const { status, infocode, info, route } = data
      if (status !== '1' || !route) {
        fail(fail(`status: ${status}, infocode: ${infocode}, errMsg: ${info}`))
        return
      }
      const { route: { paths } } = data
      const { steps } = paths[0]
      const polyline = this._getPolylineListInGd(steps)
      outRes.originalData = data
      outRes.modifiedData = {
        polyline
      }
      success(outRes)
    }
  }
  mapInstance.direction({
    ...params,
    success: (res) => {
      dealDataFn(res)
    },
    fail: (error) => {
      fail(error)
    }
  })
}

腾讯和高德的路径规划结果的数据格式差别很大:
高德返回的是路段的集合,经纬度在每个路段中,是string形式, 并且每对用分号隔离

腾讯的直接是集合[经,纬,经,纬,经,纬…],没有分对
在这里插入图片描述
在这里插入图片描述
map组件的polyline属性需要的数据结构是:

points: [{latitude: 0, longitude: 0}, {...}]

分别对腾讯和支付宝的数据转换

// map.js
/**
 * 获取腾讯的路径
 * @param polyline
 * @returns {*[]}
 * @private
 */
_getPolylineListInTx(polyline) {
  const list = []
  // 坐标解压(返回的点串坐标,通过前向差分进行压缩)
  const kr = 1000000
  for (let i = 2; i < polyline.length; i++) {
    polyline[i] = Number(polyline[i - 2]) + Number(polyline[i]) / kr
  }
  // 将解压后的坐标放入点串数组pl中
  for (let i = 0; i < polyline.length; i += 2) {
    list.push({ latitude: polyline[i], longitude: polyline[i + 1] })
  }
  return list
}

/**
 * 获取高德的路径
 * @param steps
 * @returns {*[]}
 * @private
 */
_getPolylineListInGd(steps) {
  const list = []
  for (let i = 0; i < steps.length; i++) {
    const { polyline } = steps[i]
    const arr = polyline.split(';')
    for (let j = 0; j < arr.length; j++) {
      let item = arr[j]
      const idx = item.indexOf(',')
      const lng = item.substring(0, idx)
      const lat = item.substring(idx + 1)
      list.push({
        latitude: +lat,
        longitude: +lng
      })
    }
  }
  return list
}

PS: 支付宝小程序的polyline里面没border属性,而微信是可以设置borderWidth和borderColor

六、距离计算

没有用腾讯和高德的api,这里就不阐述了

/**
 * 获取两经纬度之间距离,返回米 --- 经纬度是GCJ-02
 * @param lat1
 * @param lng1
 * @param lat2
 * @param lng2
 * @returns {number}
 */
export function getLocationDistance(lat1, lng1, lat2, lng2) {
  const radLat1 = lat1 * Math.PI / 180.0
  const radLat2 = lat2 * Math.PI / 180.0
  const a = radLat1 - radLat2
  const b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0
  let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))
  s = s * 6378.137
  s = Math.round(s * 10000) / 10
  return s
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用 Taro 开发小程序,需要首先安装 Taro 的命令行工具。具体可以参考 Taro 官方文档:https://taro-docs.jd.com/taro/docs/GETTING-STARTED。 接下来,可以使用 Taro 提供的组件来实现地图和导航功能。需要注意的是,由于小程序的限制,需要在小程序后台申请地图和导航的 API key,并将其配置在 Taro 的配置文件中。 以下是一个简单的示例代码,实现了在地图上显示两个点之间的路线,并提供导航功能: ```jsx import Taro, { Component } from '@tarojs/taro' import { Map, Polyline } from '@tarojs/components' import QQMapWX from '@/utils/qqmap-wx-jssdk' const qqmapsdk = new QQMapWX({ key: 'your_api_key' }) class MapPage extends Component { state = { polyline: [] } componentDidMount() { this.getRoute() } getRoute = () => { const { startLat, startLng, endLat, endLng } = this.$router.params qqmapsdk.direction({ mode: 'driving', from: { latitude: startLat, longitude: startLng }, to: { latitude: endLat, longitude: endLng }, success: res => { const points = res.result.routes[0].polyline.map(item => ({ latitude: item.latitude, longitude: item.longitude })) this.setState({ polyline: [{ points }] }) } }) } handleNavigate = () => { const { startLat, startLng, endLat, endLng } = this.$router.params Taro.openLocation({ latitude: Number(endLat), longitude: Number(endLng), name: '目的地' }) } render() { const { startLat, startLng, endLat, endLng } = this.$router.params const { polyline } = this.state return ( <Map id="map" latitude={Number(endLat)} longitude={Number(endLng)} scale="14" style={{ width: '100%', height: 'calc(100vh - 80px)' }} > <Polyline points={polyline[0] && polyline[0].points} strokeColor="#0099FF" strokeWidth="4" zIndex="1" /> <Button onClick={this.handleNavigate}>导航</Button> </Map> ) } } export default MapPage ``` 在这个示例中,我们使用了腾讯地图提供的 `direction` API 获取两个点之间的路线,并将其在地图上显示出来。同时,我们还提供了一个导航按钮,点击后可以跳转到小程序自带的导航页面,实现导航功能。 需要注意的是,在 `direction` API 中,我们使用了 `mode: 'driving'` 来指定导航模式为驾车模式。如果需要其他模式,可以将其改为 `'walking'` 或 `'transit'` 等。另外,我们还需要将地图的 `latitude` 和 `longitude` 设置为目的地的坐标,以便地图显示正确的位置。 希望这个示例对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Misha韩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值