| | |
| | | /* eslint-disable @typescript-eslint/no-dynamic-delete */ |
| | | /** |
| | | * 百度地图 SDK 加载工具 |
| | | * |
| | | * 重要:这里必须直连 getscript,不能用 api?... 地址。 |
| | | * api?v=1.0&type=webgl&ak=xxx 返回的是一段 |
| | | * document.write('<script src="https://api.map.baidu.com/getscript?..."></script>') |
| | | * 而通过 document.body.append(script) 动态插入的脚本里,document.write 会被浏览器拦截 |
| | | * (Chrome 直接提示 "A parser-blocking, cross site script ... invoked via document.write was NOT executed"), |
| | | * 导致真正的 SDK 从未加载、window.BMapGL 一直是 undefined/null。 |
| | | * 但 api 里的 callback 仍会被调用,调用方误以为加载成功,接着执行 new BMapGL.Map() |
| | | * 就抛出「Cannot read properties of null (reading 'Map')」。 |
| | | * |
| | | * getscript 返回的是 875KB 的真实 SDK(已实测 HTTP 200 且含 BMapGL 定义), |
| | | * 直接用 script.src 加载即可,脚本执行完 window.BMapGL 就已就绪。 |
| | | */ |
| | | |
| | | // 扩展 Window 接口以包含百度地图 GL API |
| | |
| | | BMapGL: any; |
| | | } |
| | | } |
| | | |
| | | // 全局回调名称 |
| | | const CALLBACK_NAME = '__BAIDU_MAP_LOAD_CALLBACK__'; |
| | | |
| | | // SDK 加载状态 |
| | | let loadPromise: null | Promise<void> = null; |
| | |
| | | return loadPromise; |
| | | } |
| | | |
| | | const accessKey = String(import.meta.env.VITE_BAIDU_MAP_KEY ?? '').trim(); |
| | | if (!accessKey) { |
| | | return Promise.reject(new Error('未配置 VITE_BAIDU_MAP_KEY')); |
| | | } |
| | | |
| | | loadPromise = new Promise((resolve, reject) => { |
| | | const timeoutId = setTimeout(() => { |
| | | loadPromise = null; |
| | | reject(new Error('百度地图 SDK 加载超时')); |
| | | reject(new Error('百度地图 SDK 加载超时,请检查网络')); |
| | | }, timeout); |
| | | |
| | | // 全局回调 |
| | | (window as any)[CALLBACK_NAME] = () => { |
| | | clearTimeout(timeoutId); |
| | | delete (window as any)[CALLBACK_NAME]; |
| | | resolve(); |
| | | }; |
| | | |
| | | // 创建 script 标签 |
| | | const script = document.createElement('script'); |
| | | script.src = `https://api.map.baidu.com/api?v=1.0&type=webgl&ak=${ |
| | | import.meta.env.VITE_BAIDU_MAP_KEY |
| | | }&callback=${CALLBACK_NAME}`; |
| | | script.addEventListener('onerror', () => { |
| | | script.src = `https://api.map.baidu.com/getscript?type=webgl&v=1.0&ak=${accessKey}&services=&t=${Date.now()}`; |
| | | script.async = true; |
| | | |
| | | script.addEventListener('load', () => { |
| | | clearTimeout(timeoutId); |
| | | if (!window.BMapGL) { |
| | | // ak 无效 / 域名未授权 / 被拦截时,脚本能加载但不会挂载 BMapGL |
| | | loadPromise = null; |
| | | reject( |
| | | new Error('百度地图加载异常:未获取到地图对象,请检查 Key 或域名授权'), |
| | | ); |
| | | return; |
| | | } |
| | | resolve(); |
| | | }); |
| | | |
| | | // 注意:事件名是 error,不是 onerror(写 onerror 永远不会触发) |
| | | script.addEventListener('error', () => { |
| | | clearTimeout(timeoutId); |
| | | loadPromise = null; |
| | | delete (window as any)[CALLBACK_NAME]; |
| | | reject(new Error('百度地图 SDK 加载失败')); |
| | | reject(new Error('百度地图 SDK 加载失败,请检查网络')); |
| | | }); |
| | | |
| | | document.body.append(script); |
| | | }); |
| | | |