Skip to content

云函数调用与打包上线(二) ​

本页对应 云函数调用与打包上线,共 7 段视频,约 1 小时 23 分。

学习目标 ​

  • 能配置地图组件的 center、scale、markers、polyline 属性,并说明经纬度、缩放范围、标记点和路线数据的结构要求。
  • 能从物流接口返回的 logisticsInfo 中提取起点和终点,将对象转换为逗号拼接字符串后传入路线规划接口,并验证参数类型正确。
  • 能根据路线坐标选取地图中心点,并同步设置卡车标记位置,使路线、起终点标记和车辆位置在地图中正确显示。
  • 能说明 QQ 互联中 APP ID、APP Key 与 redirect URI 的作用,能拼接 QQ 授权地址并通过 location.href 跳转唤起 QQ 登录或扫码页面。
  • 能将本地服务器端口改为 80、路由模式改为 history,并验证页面可通过 80 端口访问且 URL 中不再出现 #。
  • 能使用 SwitchHosts 以管理员权限配置本地域名映射到 127.0.0.1,并验证通过该域名可访问本地项目且满足 QQ 回调域名要求。

知识点 ​

地图组件与路线展示的整体思路 ​

这一节的目标,是把前面通过地图服务拿到的经纬度数据,真正渲染到小程序的 map 组件上,让用户看到订单的运输路线、起点、终点以及卡车当前位置。为什么需要单独讲这一节?因为地图组件虽然只有一行标签,但它的属性多、数据格式要求严格,任何一个字段传错,页面要么不显示路线,要么直接报错。怎么想?先把地图组件当成一个“画布”:中心点决定你看哪里,scale 决定放大倍数,markers 决定画哪些图标,polyline 决定画哪条线。怎么做?按“先静态跑通、再换成接口数据”的顺序来。

地图组件的核心属性 ​

地图组件常见的属性有:

  • longitude / latitude:地图中心点的经度和纬度;
  • scale:初始缩放级别,取值范围是 3 到 20;
  • markers:地图上的标记点数组;
  • polyline:路线数组,一个单元代表一条线。

为什么中心点重要?因为地图默认只展示中心点附近的区域。如果路线是从北京到上海,而中心点设在了青海,那用户自然看不到这条线。怎么想?中心点应该落在路线上,这样一打开地图就能看见整条路线。怎么做?从路线经纬度数组里取一个点作为中心点,例如取 points[100],再配合 scale: 12 让视野合适。易错点:scale 不要写成 0 或超过 20;中心点字段名不要和 markers 里的经纬度字段混淆。

路线数据从哪来 ​

路线经纬度不是手写的,而是调用腾讯地图的路线规划接口拿到的。转写稿里提到一个现实问题:Key 的额度有限,不同路线类型的额度是分开计算的,驾车、步行、骑行各有各的次数。如果某一种额度用完了,可以换一个参数继续调,因为最终处理的都是经纬度,结果结构一致。怎么做?在请求地址里把 driving 换成 walking 或 bicycling 即可。易错点:不要频繁保存和刷新页面,每刷新一次就可能调一次接口;真实开发中应该把地图数据缓存到数据库,隔几分钟或几小时再取一次,而不是每次打开页面都请求。

polyline 绘制路线 ​

polyline 是一个数组,每个单元是一条线。为什么用数组?因为地图上可能同时存在多条路线。怎么做?先定义一个空数组,等接口返回经纬度后,把结果 push 进去:

js
polyline: []
// 拿到路线经纬度后
this.polyline.push({ points: 路线经纬度数组 })

易错点:如果 polyline 一直是空数组,地图上就不会有线;不要把单个对象直接赋给 polyline,它需要的是数组。

起点终点的格式转换 ​

接口返回的 from 和 to 往往是对象,例如 { lng, lat },但地图服务要求的是“经度,纬度”这样的字符串。为什么需要转换?因为直接传对象,接口无法识别,页面会报错或请求失败。怎么想?把对象里的值取出来,再用逗号拼成字符串。怎么做?

js
const fromStr = Object.values(from).join(',')
const toStr = Object.values(to).join(',')

转写稿里一开始直接传了对象,导致请求报错,后来用 Object.values() 取出值数组,再用 join(',') 拼成字符串才修复。易错点:Object.values() 的顺序依赖对象属性顺序,实际项目中最好明确写 from.lng + ',' + from.lat,避免字段顺序变化带来问题。

markers 标记起点、终点和卡车 ​

markers 里每个标记点需要 id、经纬度、图标路径、宽高。为什么需要 id?因为地图要靠它区分不同标记,只要不重复即可。怎么做?定义三个点:起点、终点、卡车当前位置。卡车的“当前位置”可以直接复用中心点 center,这样卡车永远显示在地图中心,用户一眼就能看到货物走到哪了。易错点:markers 里写死的经纬度只能用于演示,真正上线要换成接口返回的起点和终点;图标路径和宽高不写,标记可能显示不出来。

易错点小结 ​

第一,中心点不在路线上,导致“路线明明有数据却看不见”;第二,from/to 传了对象而不是字符串,请求直接失败;第三,polyline 忘记 push,地图上只有点没有线;第四,频繁刷新浪费接口额度。调试时先看控制台有没有报错,再看请求参数格式,最后看地图中心点和 scale 是否合理。

本节要解决的问题 ​

这一节的目标不是先做登录,而是把“优医咨询”里地图组件真正用起来:先用地图组件把路线显示出来,再把接口返回的物流经纬度替换进去,让地图上的起点、终点、路线和卡车位置与订单产生关系。转写稿里反复强调一个顺序:先让地图能渲染,再替换数据,最后调中心点和缩放比例。如果一上来就接接口,出错时很难判断是组件属性写错、数据格式不对,还是中心点偏了。

地图组件先跑通:属性和空数据 ​

为什么需要先跑通?因为地图组件属性不少,longitude、latitude、scale、markers、polyline 任何一个写错,页面都可能只显示一张“没有路线”的地图。怎么想?把地图当成一个受控组件:中心点由经纬度决定,缩放由 scale 决定,标记由 markers 决定,路线由 polyline 决定。怎么做?转写稿里先保留已有经纬度属性,再补 markers 和 polyline,并先给空数组:

html
<map
  :longitude="center.longitude"
  :latitude="center.latitude"
  :scale="12"
  :markers="markers"
  :polyline="polyline"
></map>
js
data() {
  return {
    center: { longitude: 0, latitude: 0 },
    markers: [],
    polyline: []
  }
}

易错点:scale 的取值范围转写稿明确说是 3 到 20;markers 里每个标记要有不重复的 id,还要有经纬度、图标、宽高;polyline 给空数组时地图上不会出现线,这是正常的,不是组件坏了。

把路线坐标接到 polyline ​

为什么需要?因为接口返回的物流信息里才有真实经纬度,写死的几个点跟订单没有关系。怎么想?转写稿说 polyline 是数组,因为地图上可以有多条线;一条线就是一个单元,所以用 push 把腾讯地图返回的经纬度放进去。怎么做?为了减少请求次数,先把 uniCloud 相关调用注释掉,等代码写好再打开;拿到路线经纬度后执行类似:

js
// 按转写稿整理:polyline 支持多条线,所以 push 一个线路单元
this.polyline.push({
  points: this.point
})

易错点:一是不要频繁保存刷新,转写稿提到腾讯地图 key 有额度,驾车、步行、骑行额度还不一样,保存一次刷一次会消耗调用次数;真实项目应缓存路线数据,不必每次刷新都请求。二是 polyline 不是直接塞一个经纬度对象,而是数组里放线路对象。三是先确认接口返回的路线点数组存在,再 push。

起点终点:对象不能直接当 from/to ​

为什么需要?物流接口里的起点、终点最终要传给地图路线查询接口,但接口要求 from、to 是字符串,不是对象。怎么想?转写稿里起点取 logisticsInfo[0],终点取 logisticsInfo[logisticsInfo.length - 1],即 ns-1 的位置。怎么做?一开始直接把对象传进去,结果报错;后来用 Object.values 取值再 join 成逗号字符串:

js
const from = Object.values(logisticsInfo[0]).join(',')
const to = Object.values(logisticsInfo[logisticsInfo.length - 1]).join(',')

易错点:不能直接把 { longitude, latitude } 对象传给要求字符串的参数;Object.values 的顺序依赖对象键顺序,实际开发更稳妥的是显式取经纬度再拼接;起点和终点不要取反,终点是最后一条。

中心点与卡车标记 ​

为什么需要改中心点?转写稿举了很清楚的例子:路线从北京到上海,但地图中心点在青海,你当然看不见路线。怎么想?只要让中心点落在这条路线上,就一定能看到线。从路线点数组里任取一个点,比如第 100 个,作为 center,也作为卡车位置。怎么做?

js
const current = this.point[100] // 转写稿:取路线上任意一点即可
this.center = current

this.markers.push(
  { id: 1, longitude: from.longitude, latitude: from.latitude, /* 图标宽高 */ },
  { id: 2, longitude: to.longitude, latitude: to.latitude, /* 图标宽高 */ },
  { id: 3, longitude: current.longitude, latitude: current.latitude, /* 卡车图标 */ }
)

易错点:center 不要重复声明,转写稿里就出现过“前面已经定义过 center,这里应赋值而不是再声明”的低级错误;markers 的 id 要唯一;地图比例太大时把 scale 调到 12 左右再看;卡车位置和中心点用同一个点,用户一眼就能看到货到哪儿了。

调试过程与易错点汇总 ​

转写稿的调试路径很值得复盘:先写死 markers 能看到起点终点;发现没有线,是因为 polyline 还是空数组;把腾讯地图返回的经纬度 push 进去后线出来了;但线可能看不到,是因为中心点不对;把中心点改成路线上的点后,再调 scale,路线、起点、终点、卡车标记就都能看到。最后注意:减少保存刷新,保护地图 key 额度;对象转字符串要按接口要求;中心点必须服务“看见路线”这个目标。

本节要解决的问题 ​

上一节已经把地图组件显示出来了,也能看到一条路线,但这条路线是“写死”的经纬度,和当前订单没有关系。本节要把接口返回的物流轨迹真正替换进地图组件:起点、终点、路线、地图中心点,以及代表卡车当前位置的标记。

为什么需要这一步?因为地图不是静态展示,而是要让用户一眼看到“我的货从哪来、到哪去、现在走到哪”。怎么想?先把物流接口返回的 logisticsInfo 轨迹点取出来,再把起点、终点和路线点分别交给 markers、polyline、center。怎么做?先保证“先请求物流信息,再请求地图路线”,否则拿不到经纬度。易错点:不要一上来就请求地图服务,也不要把写死数据继续留在组件里。

起点和终点不能直接传对象 ​

为什么需要处理?转写中调试时发现,from、to 如果直接使用接口里的对象,地图接口会报错,因为接口要求的是用逗号拼接的字符串。怎么想?物流信息里第一个点是起点,最后一个点是终点;先把对象里的经纬度值取出来,再拼成 经度,纬度。怎么做?转写中用了 Object.values(...).join(',') 的思路:

js
// 关键片段:变量名以实际项目为准
const from = Object.values(logisticsInfo[0]).join(',')
const to = Object.values(logisticsInfo[logisticsInfo.length - 1]).join(',')

调试过程是这样的:一开始直接把对象传给地图接口,控制台报参数错误;回头检查发现接口文档要求字符串,于是用 Object.values 取出值数组,再用 join(',') 拼成字符串。易错点:Object.values 取的是对象的值,顺序要和经纬度顺序一致;不要用 Object.keys 代替;拼完后要确认是 经度,纬度,不是反过来。

地图中心点要落在路线上 ​

为什么需要?路线已经拿到了,但页面可能看不见,因为地图中心点如果不在路线附近,就像“路线从北京到上海,中心点却放在青海”,用户自然看不到线。怎么想?让中心点取路线上的任意一个点,保证地图视野覆盖路线。怎么做?转写中从 points 里取一个点作为 center,例如取第 100 个点:

js
const center = ref({ longitude: 0, latitude: 0 })
// points 为地图服务返回的路线点集合
center.value = points[100]

同时把地图缩放比例 scale 调成 12,避免地图过大或过小。易错点:points[100] 只是示意,取 0、100、200 都可以,但必须在这条路线上;真实开发中应使用司机真实位置,转写中因为接口没给,所以临时取路线点。scale 的取值范围是 3 到 20。

markers 要放起点、终点和卡车 ​

为什么需要?只有一条线不够,用户还需要看到起点、终点和卡车当前位置。怎么想?markers 是数组,一个标记就是一个对象;起点、终点、卡车各放一个对象,id 不重复即可。怎么做?转写中先把原来写死的 markers 清空,等物流接口返回后再组装;卡车位置直接复用 center.value:

js
markers.value = [
  { id: 1, longitude: fromPoint.longitude, latitude: fromPoint.latitude, iconPath: '...', width: 30, height: 30 },
  { id: 2, longitude: toPoint.longitude, latitude: toPoint.latitude, iconPath: '...', width: 30, height: 30 },
  { id: 3, longitude: center.value.longitude, latitude: center.value.latitude, iconPath: '...', width: 30, height: 30 }
]

polyline 则用 push 放路线点,因为地图上可能有多条线,所以它是数组套数组的结构。易错点:markers 的 id 不能重复;polyline 不要漏掉外层数组;图标宽高和图片路径要配对;卡车点要和中心点保持一致,这样卡车移动时地图中心也跟着移动。

调试顺序和额度问题 ​

为什么要注意?转写中反复强调:地图 Key 有调用额度,保存代码后自动刷新、反复刷新页面都会消耗次数。怎么想?先把接口请求注释掉,等组件数据写好再打开;调试时减少无意义刷新。怎么做?先写 markers、polyline、center 的初始空数据,确认页面不报错,再接入物流接口数据。易错点:不要一边改一边频繁保存刷新;接口顺序必须是“先物流信息,后地图路线”;如果地图线看不见,先检查 center 是否在路线上,再检查 polyline 是否有数据。

本节最终效果是:地图中心点落在路线上,起点和终点有标记,卡车标记位于中心位置,路线由接口返回的经纬度数组绘制出来。

代码示例 ​

示例一:地图组件模板(把 markers / polyline / center / scale 绑到 map 上) ​

html
<template>
  <view class="map-page">
    <!-- 地图组件:一行代码就能把地图渲染出来 -->
    <map
      class="map"
      :longitude="center.longitude"
      :latitude="center.latitude"
      :scale="scale"
      :markers="markers"
      :polyline="polyline"
    />
  </view>
</template>

<style>
.map-page {
  width: 100%;
  height: 100vh;
}
.map {
  width: 100%;
  height: 100%;
}
</style>

关键行与易错点

  • longitude / latitude:地图初始中心点的经纬度;不传就看不出路线在哪。
  • scale:初始缩放比例,取值范围 3 ~ 20;路线太长时给 12 左右比较合适。
  • markers:地图上的标记点(起点、终点、卡车),每项必须有 id(不重复)、longitude、latitude、iconPath,还可以指定图标 width / height。
  • polyline:路线的经纬度集合,是一个数组(一个元素=一条线),所以要用 push 往里塞,不能直接赋值成单个对象。
  • polyline 一开始写成空数组 [],所以地图上只看到起终点图标、看不到线,这是正常的——等路线数据回来再 push。

示例二:拿到物流信息后,替换地图数据(起点/终点/中心点/卡车标记/路线) ​

js
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'

const scale = ref(12)
const center = ref({ longitude: 0, latitude: 0 }) // 地图中心点
const markers = ref([])                            // 标记点:起点、终点、卡车
const polyline = ref([])                           // 路线:一个元素一条线

onLoad((options) => {
  getLogisticsInfo(options.id)
})

async function getLogisticsInfo(id) {
  // 1. 先查物流信息,拿到 logisticsInfo(里面才有经纬度)
  const { data } = await uni.request({ url: `/api/logistics/${id}` })
  const logisticsInfo = data.logisticsInfo

  // 2. 起点 = 第 0 个,终点 = 最后一个
  const from = logisticsInfo[0]
  const to = logisticsInfo[logisticsInfo.length - 1]

  // 3. 对象不能直接当参数传,必须转成 "经度,纬度" 的字符串
  const fromStr = Object.values(from).join(',')
  const toStr = Object.values(to).join(',')

  // 4. 再调地图服务,拿到这一整条路线的经纬度
  const points = await getMapRoute(fromStr, toStr) // points 是一堆经纬度

  // 5. 路线塞进 polyline(push,不是赋值)
  polyline.value.push({
    points,
    color: '#27BA0F',
    width: 4
  })

  // 6. 中心点从路线上随便取一个点,保证一定能看见路线
  center.value = points[100]

  // 7. 卡车位置 = 地图中心点
  const current = center.value

  // 8. 标记点:起点、终点、卡车
  markers.value = [
    {
      id: 1,
      longitude: from.longitude,
      latitude: from.latitude,
      iconPath: '/static/start.png',
      width: 30,
      height: 30
    },
    {
      id: 2,
      longitude: to.longitude,
      latitude: to.latitude,
      iconPath: '/static/end.png',
      width: 30,
      height: 30
    },
    {
      id: 3,
      longitude: current.longitude,
      latitude: current.latitude,
      iconPath: '/static/truck.png',
      width: 30,
      height: 30
    }
  ]
}
</script>

关键行与易错点

  • 顺序变了:必须先拿到 logisticsInfo 才可能知道经纬度,所以“查地图路线”的代码要挪到“查物流信息”的回调里面。
  • logisticsInfo[0] 是起点、logisticsInfo[logisticsInfo.length - 1] 是终点,文档里没明确标注,是比对数据得出的。
  • 最容易错的一行:from / to 是对象,而地图接口要的是 "经度,纬度" 的字符串,直接传会报错。用 Object.values(from).join(',') 转换。
  • center 前面已经 ref 定义过,后面只能赋值,不能再 const center = ...,否则就是 Identifier 'center' has already been declared 的语法错误。
  • center.value = points[100]:取第 100 个点(1、10、100 都行,只要在这条线上),目的是让中心点落在路线上,否则中心点写死在北京、路线在上海,就“看不见线”。真实开发中这个点应由后端返回司机真实位置。
  • polyline.value.push(...):polyline 是数组(可以有多条线),所以用 push;直接 = 会覆盖。
  • 卡车标记的经纬度必须用 current 的,如果还写死成别的坐标,车就不会跟着中心点走。
  • 省钱提醒:地图接口有调用额度,开发时尽量少刷新、少保存自动刷新;真实项目要把路线结果缓存(如存库,5 分钟/1 小时调一次),并且驾车/步行/骑行额度是分开的,改参数(driving → walking)即可切换。

示例三:Object.values / Object.keys 与 join 的转换(可直接在浏览器跑) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Object.values 转字符串</title>
</head>
<body>
  <script>
    // 模拟从物流信息里取到的起点(对象形式)
    const from = { longitude: 116.397, latitude: 39.909 };

    // Object.values:只把值取出来,放进一个数组
    console.log(Object.values(from)); // [116.397, 39.909]

    // Object.keys:只把键取出来,放进一个数组
    console.log(Object.keys(from));   // ['longitude', 'latitude']

    // 数组再用逗号 join,得到地图接口要的 "经度,纬度"
    const fromStr = Object.values(from).join(',');
    console.log(fromStr);             // "116.397,39.909"
  </script>
</body>
</html>

关键行与易错点

  • Object.values(obj) 返回值的数组,Object.keys(obj) 返回键的数组,两者顺序按对象属性定义顺序。
  • Object.values(from) 拿到的是 [116.397, 39.909],还不是字符串,必须再 .join(',') 才是接口要的 "116.397,39.909"。
  • 如果键的顺序被写反(先 latitude 后 longitude),拼出来的就是 "纬度,经度",地图会定位到错误位置——所以对象里的字段顺序要和接口要求一致。
  • 这类“对象 → 字符串”的写法一段时间不用就容易忘,本节里正是因为它,from / to 传参报错的问题才被修掉。

常见错误 ​

  1. 现象:地图上看不到路线。→ 原因:地图中心点仍停留在默认位置,未落在路线附近。→ 修法:从路线坐标中取一个点作为 center,并配合合适的 scale。
  2. 现象:地图接口报参数错误或路线不显示。→ 原因:把 from / to 对象直接传给要求字符串的参数。→ 修法:先取对象值,再用逗号拼接成字符串,如 Object.values(from).join(',')。
  3. 现象:地图标记与当前订单无关。→ 原因:markers / polyline 仍使用写死数据或空数组。→ 修法:在物流接口返回后赋值,起点、终点、路线均使用接口数据。
  4. 现象:QQ登录跳转后提示回调地址不合法。→ 原因:redirect_uri 与 QQ 互联后台配置的回调域不一致。→ 修法:严格按后台已配置的域名、路径、协议、端口拼接授权地址。
  5. 现象:本地授权后无法回到开发页面。→ 原因:仍使用 localhost、带端口或 hash 路由,与回调配置不匹配。→ 修法:按要求改为 80 端口、history 模式,并用 hosts 配置本地域名访问。
  6. 现象:调试时地图/路线接口额度很快耗尽。→ 原因:频繁保存、刷新,重复调用收费接口。→ 修法:减少无意义刷新;调试阶段先注释请求;真实项目缓存位置数据并控制调用频率。

练习 ​

  1. 基于物流接口返回的 logisticsInfo,取首尾点生成地图起点、终点,并传给路线规划接口;要求处理对象到字符串的转换。
  2. 从路线坐标中任取一个点作为地图 center,同时新增“卡车”标记,并保证卡车标记与 center 使用同一坐标。
  3. 为登录页 QQ 图标绑定点击事件,拼接 QQ 授权地址,包含 response_type、client_id、redirect_uri 三个参数,并说明每个参数来源。
  4. 改造本地开发环境:端口改为 80、路由改为 history、配置本地域名映射,使授权回调地址可在本机访问。
  5. 排查一个“地图有标记但无路线”的页面:列出至少 3 个检查点并给出修复顺序。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1优医咨询-地图组件展示路线10:50
2优医咨询-替换地图组件中的数据-115:33
3优医咨询-替换地图组件中的数据-206:58
4QQ互联介绍05:51
5优医咨询-唤起QQ客户端14:52
6配置本地服务器端口07:32
7为本地服务器配置域名22:04

小结 ​

  1. 地图展示路线时,中心点、缩放级别、路线数据、标记数据要同时正确。
  2. 地图相关数据必须来源于当前订单接口,不能保留演示用写死数据。
  3. 起点/终点传给地图服务前,要确认参数类型与文档要求一致。
  4. 调试收费地图接口时,减少保存和刷新次数,必要时先关闭请求。
  5. QQ 登录能否成功,关键检查项是授权地址参数完整且回调地址与后台配置一致。
  6. 本地联调第三方回调时,端口、路由模式、域名映射要一起满足要求。
  7. 上线前应补充地图数据缓存策略,避免重复调用造成额度和费用浪费。