jjzjj

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

Misha韩 2024-02-19 原文

背景: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
}

有关taro 兼容支付宝小程序和微信小程序<四> -- 腾讯地图和高德地图api的更多相关文章

  1. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  2. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  3. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

  4. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

  5. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  6. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  7. ruby-on-rails - 在 Ruby (on Rails) 中使用 imgur API 获取图像 - 2

    我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path

  8. ruby-on-rails - 使用 HTTParty 的非常基本的 Rails 4.1 API 调用 - 2

    Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"

  9. ruby-on-rails - 是否使用 API - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我的公司有一个巨大的数据库,该数据库接收来自多个来源的(许多)事件,用于监控和报告目的。到目前为止,数据中的每个新仪表板或图形都是一个新的Rails应用程序,在巨大的数据库中有额外的表,并且可以完全访问数据库内容。最近,有一个想法让外部(不是我们公司,而是姊妹公司)客户访问我们的数据,并且决定我们应该公开一个只读的RESTfulAPI来查询我们的数据。我的观点是-我们是否也应该为我们的自己

  10. ruby - Ruby 中的必应搜索 API - 2

    我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是

随机推荐