☰
官方那个 5KB 的地图加载器,和一行从 DOM 里掏出 Vue 实例的代码
2026/10/8 6:49:36 网站建设 项目流程

午休好。今天三道:一个高德官方给 npm 包、专治"页面里多个组件抢着加载地图脚本"的加载器,一个在没装 Vue Devtools 时也能摸到组件实例的控制台小技巧,以及一段关于"同一个经纬度为什么对不上"的冷知识。

@amap/amap-jsapi-loader:把加载 JSAPI 这件事交给官方

手工在 HTML 里塞<script src="https://webapi.amap.com/maps?v=2.0&key=...">是很常见的做法,一旦组件化就开始出乱子:两个组件各自判断if (!window.AMap)再插脚本,异步竞争之下 AMap 可能"有了但插件没装全";更糟的是页面里同时混进 1.4 和 2.0 两个版本。

高德开放平台其实提供了一个官方 npm 包来管这件事(仓库名amap/amap-jsapi-loader,README 里自称"高德官网提供的地图 JSAPI 的加载器")。我本地装了一份看:

npmi @amap/amap-jsapi-loader--save# 1.0.1,MIT,dist/index.js 5268 字节
importAMapLoaderfrom'@amap/amap-jsapi-loader'// 2021-12-02 之后申请的 key 必须配安全密钥,官网文档要求写在前面window._AMapSecurityConfig={securityJsCode:'你申请的安全密钥'}AMapLoader.load({key:'你的 Web 端开发者 Key',// 首次调用必填version:'2.0',// 不写的话默认加载 1.4.15plugins:['AMap.Scale','AMap.ToolBar'],}).then((AMap)=>{constmap=newAMap.Map('container',{zoom:11})})

它的index.d.ts里除了plugins,还能顺手带上 AMapUI(默认 1.1)和 Loca(默认 1.3.2):

AMapLoader.load({key:'xxx',version:'2.0',AMapUI:{version:'1.1',plugins:['overlay/SimpleMarker']},Loca:{version:'1.3.2'},})

值不值的,看它 README 里那两条承诺就够了:“允许多次执行加载操作,网络资源不会重复请求,便于大型工程模块管理”,以及**“对于加载混用多个版本 JSAPI 的错误用法给予报错处理”**。前者意味着你可以在每个地图组件的mounted里各写一次load(),由它去合并;后者意味着版本混用会直接抛错,而不是等你查半小时白屏。5KB 换一个"加载时序不用自己管",我觉得划算。

小技巧:el.__vue__,从 DOM 节点直接拿到组件实例

调试 Vue 2 组件时,如果没装 Devtools 扩展(或者线上环境根本没法装),控制台里其实有个后门:

constvm=document.querySelector('.map-wrapper').__vue__ vm.$data.center// 读vm.setZoom&&vm.setZoom(14)// 组件的 methods 直接挂在实例上,能调

这个属性不是猜的。Vue 2.7.16 的源码里就有赋值动作(// update __vue__ reference注释下面一行):

vm.$el.__vue__=vm;

而且它写在渲染流程里,不在 dev-only 分支里——生产构建vue.min.js中同样存在这一处赋值,所以打包上线后照样能用。另外源码里还有一行销毁时清理的逻辑(vm.$el.__vue__ = null),也就是组件beforeDestroy之后你手上那个引用就取不到新值了,别把它当长期缓存。

如果只知道组件name、不知道 DOM 类名,可以从根实例递归找:

constfind=(vm,name)=>vm.$options.name===name?vm:vm.$children.reduce((hit,c)=>hit||find(c,name),null)find(document.querySelector('#app').__vue__,'MapPanel')

注意$children是只读的"直接子组件"数组(官方 API 文档原话:Read only,The direct child components of the current instance),所以只有一层,得靠递归往下钻。这个技巧用来干什么都最爽?——验证"我那个地图实例到底进 data 没有"、“点了半天这个 ref 里存的是啥”,比在模板里加一堆{{ }}快得多。

冷知识:为什么你手上的经纬度在高德底图上偏了一截

前端做地图迟早会撞上一次" marker 落在马路对面"。原因不在代码,在坐标系:

  • WGS-84:GPS 原始坐标系,浏览器navigator.geolocation返回的就是它。
  • GCJ-02:俗称"火星坐标系",由 WGS-84 加密偏移而来,国内公开发布的地图服务按监管要求必须做这层加密。高德、腾讯走的都是它。
  • BD-09:百度在 GCJ-02 之上又加密偏移了一次,所以百度的坐标只有它自己认。

偏移量级是"几十到几百米",所以拿 GPS 原始坐标直接当高德的 marker 点位,一定会肉眼可见地偏——两套坐标系里,同一个数字指向的不是同一个地点。中间必须过一次转换。

顺带一个容易忽略的点:地图上的距离、面积、围栏判定,本质都建立在"数据同源"这个前提上。你从后端拿的门店坐标是 GCJ-02,用户上传的签到点是 WGS-84,混着算就会得到那种"看起来没问题但客户投诉说画歪了"的结果。

最后

今天这三件东西看着不相关,其实都在处理同一类问题:你看不见的那一层,正在决定你算错的那一步。

加载 JSAPI 时,你不看的是脚本插入的时序和版本,于是"有时候地图能出来";调试组件时,你不看的是实例上真实挂着的 data,于是靠加模板变量猜状态;做地图时,你不看的是坐标系,于是同一个116.397在两套体系里差出一条街。

这三层的共同解法也一致:让隐性的变成显性的——加载交给会报错的工具,状态从实例上直接读,坐标系在代码注释里写死一行"这里的数字是 GCJ-02"。地图前端的 bug,多数不是代码逻辑错,是"两个东西其实不同源却被当成同源"。下次先问这个,通常比 debug 快。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询