尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Vue3 + Vite项目里,我是这样搞定百度地图WebGL版(BMapGL)和鼠标绘制工具的

Vue3 + Vite项目里,我是这样搞定百度地图WebGL版(BMapGL)和鼠标绘制工具的 Vue3 Vite项目中优雅集成百度地图WebGL版与鼠标绘制工具在Vue3和Vite构建的现代化前端项目中地图功能的集成往往面临与传统Webpack环境不同的挑战。本文将带你从零开始在Vite生态中实现百度地图WebGL版(BMapGL)与鼠标绘制工具的高效整合同时解决模块化引入、TypeScript支持和组件封装等实际问题。1. 环境准备与基础配置1.1 创建Vite项目与必要依赖首先确保已安装Node.js 16版本然后通过以下命令创建Vue3项目npm create vitelatest bmapgl-demo --template vue-ts cd bmapgl-demo npm install为支持百度地图的类型定义我们需要安装类型声明包npm install types/bmapgl --save-dev1.2 百度地图API密钥申请访问百度地图开放平台注册开发者账号并创建应用获取AK(API密钥)注意选择浏览器端应用类型提示生产环境务必配置Referer白名单防止密钥被盗用2. 非传统方式引入百度地图资源2.1 动态脚本加载方案在Vite项目中我们采用更现代的动态加载方式替代传统的script标签引入。创建src/utils/loadScript.tsexport const loadScript (url: string): Promisevoid { return new Promise((resolve, reject) { const script document.createElement(script) script.src url script.onload () resolve() script.onerror () reject(new Error(Script load failed: ${url})) document.head.appendChild(script) }) } export const loadBMapGL (ak: string): Promisevoid { return loadScript( //api.map.baidu.com/api?typewebglv1.0ak${ak} ) } export const loadDrawingManager (): Promisevoid { return Promise.all([ loadScript(//mapopen.cdn.bcebos.com/github/BMapGLLib/DrawingManager/src/DrawingManager.min.js), new Promisevoid((resolve) { const link document.createElement(link) link.href //mapopen.cdn.bcebos.com/github/BMapGLLib/DrawingManager/src/DrawingManager.min.css link.rel stylesheet link.onload () resolve() document.head.appendChild(link) }) ]).then(() {}) }2.2 全局类型声明扩展在src/env.d.ts中添加类型声明/// reference typesvite/client / declare global { interface Window { BMapGL: typeof BMapGL BMapGLLib: { DrawingManager: typeof BMapGLLib.DrawingManager } } }3. Composition API封装地图组件3.1 基础地图组件实现创建src/components/BMapGLContainer.vuetemplate div refmapContainer classbmapgl-container/div /template script langts setup import { ref, onMounted, onBeforeUnmount } from vue import { loadBMapGL } from ../utils/loadScript const props defineProps({ ak: { type: String, required: true }, center: { type: Object as () { lng: number; lat: number }, default: () ({ lng: 116.404, lat: 39.915 }) }, zoom: { type: Number, default: 11 } }) const mapContainer refHTMLElement() const mapInstance refBMapGL.Map() onMounted(async () { await loadBMapGL(props.ak) if (!mapContainer.value) return mapInstance.value new window.BMapGL.Map(mapContainer.value, { enableMapClick: false }) const point new window.BMapGL.Point(props.center.lng, props.center.lat) mapInstance.value.centerAndZoom(point, props.zoom) mapInstance.value.enableScrollWheelZoom(true) }) onBeforeUnmount(() { mapInstance.value?.destroy() }) /script style scoped .bmapgl-container { width: 100%; height: 500px; border: 1px solid #dcdfe6; } /style3.2 鼠标绘制工具集成扩展上面的组件添加绘制功能// 在setup函数中添加 const drawingManager refBMapGLLib.DrawingManager() const activeDrawingType refstring() const initDrawingManager () { if (!mapInstance.value) return drawingManager.value new window.BMapGLLib.DrawingManager( mapInstance.value, { enableCalculate: false, enableSorption: true, sorptiondistance: 20, circleOptions: { strokeColor: #5E87DB, fillColor: #5E87DB, strokeWeight: 2, fillOpacity: 0.2 }, // 其他形状样式配置... } ) } const startDrawing (type: string) { if (!drawingManager.value) return activeDrawingType.value type drawingManager.value.setDrawingMode(type) drawingManager.value.open() } // 在onMounted中添加 await loadDrawingManager() initDrawingManager()4. 高级功能与性能优化4.1 自定义控件与UI集成创建自定义工具栏组件MapToolbar.vuetemplate div classmap-toolbar button v-fortool in tools :keytool.type :class{ active: activeType tool.type } clickhandleToolClick(tool.type) span classicon :style{ backgroundImage: url(${tool.icon}) }/span {{ tool.label }} /button /div /template script langts setup defineProps({ activeType: String, tools: Array as () Array{ type: string label: string icon: string } }) const emit defineEmits([tool-click]) const handleToolClick (type: string) { emit(tool-click, type) } /script style scoped .map-toolbar { position: absolute; top: 20px; left: 20px; z-index: 1000; background: white; border-radius: 4px; box-shadow: 0 2px 6px rgba(0,0,0,0.1); } button { display: flex; align-items: center; padding: 8px 12px; background: none; border: none; cursor: pointer; } button.active { background-color: #f0f7ff; } .icon { width: 20px; height: 20px; margin-right: 8px; background-size: contain; } /style4.2 事件监听与数据交互完善绘制完成事件处理// 在setup函数中添加 const emit defineEmits([draw-complete]) const setupEventListeners () { if (!drawingManager.value) return drawingManager.value.addEventListener(overlaycomplete, (e) { const overlay e.overlay let result: any switch (activeDrawingType.value) { case marker: result { type: point, position: overlay.getPosition() } break case circle: result { type: circle, center: overlay.getCenter(), radius: overlay.getRadius() } break case polygon: result { type: polygon, path: overlay.getPath() } break // 其他形状处理... } emit(draw-complete, result) drawingManager.value?.close() }) } // 在initDrawingManager后调用 setupEventListeners()5. 实际应用与问题解决5.1 常见问题解决方案问题1Vite热更新导致地图实例重复创建解决方案在组件卸载时正确销毁地图实例onBeforeUnmount(() { if (drawingManager.value) { drawingManager.value.close() drawingManager.value undefined } mapInstance.value?.destroy() mapInstance.value undefined })问题2TypeScript类型检查报错完善类型声明文件src/types/bmapgl-extend.d.tsdeclare namespace BMapGLLib { class DrawingManager { constructor(map: BMapGL.Map, options?: DrawingManagerOptions) setDrawingMode(mode: string): void open(): void close(): void addEventListener(event: string, handler: Function): void removeEventListener(event: string, handler: Function): void getDrawingMode(): string _isOpen: boolean } interface DrawingManagerOptions { enableCalculate?: boolean enableSorption?: boolean sorptiondistance?: number circleOptions?: OverlayOptions polylineOptions?: OverlayOptions polygonOptions?: OverlayOptions rectangleOptions?: OverlayOptions labelOptions?: LabelOptions } interface OverlayOptions { strokeColor?: string fillColor?: string strokeWeight?: number strokeOpacity?: number fillOpacity?: number } interface LabelOptions { borderRadius?: string background?: string border?: string color?: string fontSize?: string letterSpacing?: string padding?: string } }5.2 性能优化建议按需加载只在需要地图的页面动态加载百度地图资源图层管理合理使用map.clearOverlays()清理不需要的覆盖物防抖处理对频繁触发的地图事件添加防抖逻辑内存管理及时移除不再需要的事件监听器// 示例防抖处理地图缩放事件 import { debounce } from lodash-es onMounted(() { mapInstance.value?.addEventListener(zoomend, debounce((e) { console.log(当前缩放级别:, e.target.getZoom()) }, 300)) })在项目中使用封装好的组件template div classmap-page BMapGLContainer :akyourAk draw-completehandleDrawComplete / MapToolbar :toolstools tool-clickhandleToolClick / /div /template
返回列表