主题
云函数调用与打包上线(二)
本页对应 云函数调用与打包上线,共 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传参报错的问题才被修掉。
常见错误
- 现象:地图上看不到路线。→ 原因:地图中心点仍停留在默认位置,未落在路线附近。→ 修法:从路线坐标中取一个点作为
center,并配合合适的scale。 - 现象:地图接口报参数错误或路线不显示。→ 原因:把
from/to对象直接传给要求字符串的参数。→ 修法:先取对象值,再用逗号拼接成字符串,如Object.values(from).join(',')。 - 现象:地图标记与当前订单无关。→ 原因:
markers/polyline仍使用写死数据或空数组。→ 修法:在物流接口返回后赋值,起点、终点、路线均使用接口数据。 - 现象:QQ登录跳转后提示回调地址不合法。→ 原因:
redirect_uri与 QQ 互联后台配置的回调域不一致。→ 修法:严格按后台已配置的域名、路径、协议、端口拼接授权地址。 - 现象:本地授权后无法回到开发页面。→ 原因:仍使用
localhost、带端口或 hash 路由,与回调配置不匹配。→ 修法:按要求改为 80 端口、history 模式,并用 hosts 配置本地域名访问。 - 现象:调试时地图/路线接口额度很快耗尽。→ 原因:频繁保存、刷新,重复调用收费接口。→ 修法:减少无意义刷新;调试阶段先注释请求;真实项目缓存位置数据并控制调用频率。
练习
- 基于物流接口返回的
logisticsInfo,取首尾点生成地图起点、终点,并传给路线规划接口;要求处理对象到字符串的转换。 - 从路线坐标中任取一个点作为地图
center,同时新增“卡车”标记,并保证卡车标记与center使用同一坐标。 - 为登录页 QQ 图标绑定点击事件,拼接 QQ 授权地址,包含
response_type、client_id、redirect_uri三个参数,并说明每个参数来源。 - 改造本地开发环境:端口改为 80、路由改为 history、配置本地域名映射,使授权回调地址可在本机访问。
- 排查一个“地图有标记但无路线”的页面:列出至少 3 个检查点并给出修复顺序。
课堂画面






原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 优医咨询-地图组件展示路线 | 10:50 |
| 2 | 优医咨询-替换地图组件中的数据-1 | 15:33 |
| 3 | 优医咨询-替换地图组件中的数据-2 | 06:58 |
| 4 | QQ互联介绍 | 05:51 |
| 5 | 优医咨询-唤起QQ客户端 | 14:52 |
| 6 | 配置本地服务器端口 | 07:32 |
| 7 | 为本地服务器配置域名 | 22:04 |
小结
- 地图展示路线时,中心点、缩放级别、路线数据、标记数据要同时正确。
- 地图相关数据必须来源于当前订单接口,不能保留演示用写死数据。
- 起点/终点传给地图服务前,要确认参数类型与文档要求一致。
- 调试收费地图接口时,减少保存和刷新次数,必要时先关闭请求。
- QQ 登录能否成功,关键检查项是授权地址参数完整且回调地址与后台配置一致。
- 本地联调第三方回调时,端口、路由模式、域名映射要一起满足要求。
- 上线前应补充地图数据缓存策略,避免重复调用造成额度和费用浪费。