当前位置: 首页 > article >正文

将自定义vue组件加载在Mapbox或Maplibre的marker和popup上

1. 使用场景

在开发WebGIS应用时,我们常需要将自定义UI组件与地图元素结合。本文介绍如何将Vue组件集成到Mapbox/Maplibre的Marker标记点和Popup弹窗中,实现动态交互式的地图功能。

2. 为什么需要特殊处理?

在常规开发中我们大多的处理是

const tipsEle = document.createElement("div")
  tipsEle.setAttribute("class", "tips")
  tipsEle.style.color = "#e73f32"
  tipsEle.style.fontSize = "12px"
  tipsEle.style.fontWeight = "400"
  tipsEle.innerHTML = "删除"
   const tipsOption = {
       element: tipsEle,
       anchor: "left",
       offset: [-45, 30],
    }

new maplibregl.Marker(tipsOption).setLngLat(coords).addTo(map)

这样的写法显而易见维护难,调试难,ui在复杂一点复杂程度也跟着上去了,如果换成组件形式的话,所有问题迎刃而解了。

3. 使用createVNode实现

/**
 * @description: 创建地图Marker 和 Popup 组件, 渲染自定义组件
 * @author: jihai
 * @createTime: 2025/03/05 15:05:01
 */
import {createVNode, render} from "vue";
import * as maplibregl from 'maplibre-gl';

class CreateVNode{
	declare map:any
	declare coordinates:any
	declare markerComponentId: string
    declare marker:any
    declare markerElement: any
	declare popupComponentId: string
    declare popup:any
    declare popupElement: any
    
	constructor(option: {
		map: any,
		coordinates: any
	}) {
		const {map, coordinates} = option
		
    this.map = map
    this.coordinates = coordinates

	this.markerComponentId = `markerComponentId-${performance.now().toString()}`

    this.marker = null

    this.markerElement = null

    this.popupComponentId = `popupComponentId-${performance.now().toString()}`

    this.popup = null

    this.popupElement = null
	}
	
	createMarker(options: {
    component: {
      component: any, // 自定义vue组件
      props: any      // 自定义组件props
    },
    config?: {
      offset: number[],
      anchor: string
    }
  }){
    const { component, config } = options
	const app = createVNode(component?.component, {data: component?.props})
    this.markerElement = document.createElement("div")
    this.markerElement.setAttribute("id", this.markerComponentId)

		this.marker = new maplibregl.Marker({
      element: this.markerElement,
      anchor: config?.anchor ?? 'bottom',
      offset: config?.offset ?? [0, 0]
    }).setLngLat(this.coordinates).addTo(this.map)

		render(app, this.markerElement)
	}

  createPopup(options: {
    component: {
      component: any, // 自定义vue组件
      props: any      // 自定义vue组件props
    },
    config?: {
      offset: number[],
      anchor: string,
      closeButton: boolean
    }
  }){
    const { component, config } = options
    const app = createVNode(component?.component, {data: component?.props})
    this.popupElement = document.createElement("div")
    this.popupElement.setAttribute("id", this.popupComponentId)

    this.popup = new maplibregl.Popup(
      {
        className: 'custom-popup', 
        closeButton: config?.closeButton ?? true, 
        anchor: config?.anchor ?? 'bottom'
      })
    .setMaxWidth('none')
    .setOffset(config?.offset ?? [0, 0]) // 这里设置偏移量
    .setLngLat(this.coordinates)
    .setDOMContent(this.popupElement)
    .addTo(this.map)

		render(app, this.popupElement)
  }
	
	removeMarker(){
		if(this.marker){
			this.marker.remove()
		}
		if(this.markerElement){
			this.markerElement.remove()
		}
	}

  removePopup(){
		if(this.popup){
			this.popup.remove()
		}
		if(this.popupElement){
			this.popupElement.remove()
		}
	}

  remove(){
    this.removeMarker()
    this.removePopup()
  }
}

export default CreateVNode

4. 使用方法

  // 简单使用 具体使用根据业务场景合理清除图层
  let marker = new CreateVNode({
    map: map,
    coordinates: coordinates
  })

  marker.createMarker({
    component: {
      component: markerComp,
      props: markerProps
    },
    config: {
      offset: [0, 120],
      anchor: 'bottom'
    }
  })


  //  图层清除
  marker.removeMarker()
  marker = null

5. 效果展示

红色框里为element组件渲染结果
在这里插入图片描述


http://www.kler.cn/a/573743.html

相关文章:

  • SpringBoot3—场景整合:NoSQL
  • 开源模型应用落地-LangGraph101-探索 LangGraph人机交互-添加断点(一)
  • 准确---Liunx查看出口ip的命令
  • Leetcode 57: 插入区间
  • 快速熟悉JavaScript
  • Linux的一些配置(网络建设与运维)
  • 【软考-架构】9.2、摘要-签名-PKI-访问控制-DOS-欺骗技术
  • 计算机网络(1) 网络通信基础,协议介绍,通信框架
  • 基于微信小程序的小区服务管理系统+论文源码调试讲解
  • 基于SSM+MySQL的二手书籍交易系统
  • wheel_legged_genesis 开源项目复现与问题记录
  • llama.cpp: GGUF格式及模型量化参数介绍
  • 突破传统:用Polars解锁ICU医疗数据分析新范式
  • C语言【指针篇】(四)
  • vueDraggable插件拖拽过程中节点文本不允许选中方案
  • 最新技术趋势与应用解析:未来科技走向
  • 【每日学点HarmonyOS Next知识】动图循环播放、监听tab切换、富文本上下滚动、tab默认居中、a标签唤起拨号
  • AIGC(生成式AI)试用 26 -- 跟着清华教程学习 - 个人理解
  • TCP、UDP、WebSocket 和 HTTP 教程
  • 玩转大模型——Trae AI IDE国内版使用教程