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

将自定义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组件渲染结果
在这里插入图片描述

相关文章:

  • Qt 实现绘图板(支持橡皮擦与 Ctrl+Z 撤销功能)[特殊字符]
  • Spring Boot中对接Twilio以实现发送验证码和验证短信码
  • CAD2025电脑置要求
  • 蓝桥试题:破损的楼梯 3367
  • OSI七层网络结构和TCP/IP四层结构
  • [Windows] 多系统键鼠共享工具 轻松跨系统控制多台电脑
  • 【JavaSE-4】程序逻辑控制
  • SpringMVC请求处理流程:DispatcherServlet工作原理
  • 4.RabbitMQ工作模型
  • Linux中的进程间通信的方式及其使用场景
  • OneTools.online 一站式工具库已上线
  • Linux相关概念和易错知识点(33)(基于阻塞队列和环形队列的生产消费模型实现、sem的应用)
  • android亮灭屏流程分析
  • 基于 HTML、CSS 和 JavaScript 的智能九宫格图片分割系统
  • 机器学习(李宏毅)——Life-Long Learning
  • Java基础12
  • 【Python运维】深入分析Python运维工具:用psutil监控系统性能
  • 金蝶ERP星空对接流程
  • 机器学习11-经典网络解析
  • (1)udp双向通信(2)udp实现文件复制(3)udp实现聊天室
  • 什么软件做网站描述/百度小说
  • 东乡哪里有做网站/seo成功的案例和分析
  • 六十岁一级a做爰片免费网站/成品短视频软件大全下载手机版
  • 网站微信认证费用多少钱/百度一下 你就知道首页官网
  • 建设公司网站多少钱/2024小学生时事新闻十条
  • 商城网站营销系统源码/网络营销概念