leaflet L.popup().setContent中挂载vue组件

思路

Leaflet 的 L.popup().setContent(xxx) 中,xxx 只认 3 种合法值:

  • 纯文本字符串

  • HTML 字符串 (如 <div>船舶信息</div>)

  • 原生 JS DOM 节点 (核心!也是对接 Vue3 h()的关键)

Vue3 的渲染函数 h() 执行后,返回的是 Vue 虚拟节点 (VNode),不是原生 DOM,所以直接写setContent(h('div', {}, '内容')) 一定会报错;

我们的核心思路:把 h() 生成的虚拟节点vnode → 再通过render()挂载成「原生 DOM 节点」 → 再传给 setContent()。

代码

javascript 复制代码
  import PopupShipCompo from '../components/PopupShip/index.vue';
  
    // 获取地图
  function getMap() {
    !Boolean(shipMap) && initMap();
    return shipMap;
  }

  const popupShipInstance = ref<any>(null); // 船舶popup对象
  // 船舶popup中挂载的dom 的创建与销毁
  const popupShip: any = {
    dom: null,
    createDom: function () {
      if (!this.dom) {
        this.dom = document.createElement('div');
      } else {
        render(null, this.dom);
      }
      // 创建
      const vnode = h(PopupShipCompo, {
        // props
        currentClickShip: currentClickShip.value,
        // emit事件: 必须写成 on + 事件名大驼峰 格式!!
        onGoTrack: goTrack, // 子组件emit('goTrack')会触发这个方法
        onShipPopupClose: shipPopupClose
      });
      render(vnode, this.dom);
      return this.dom;
    },
    removeDom: function () {
      if (this.dom) {
        render(null, this.dom);
        this.dom.innerHTML = '';
      }
    }
  };
  // 显示船舶Popup
  const shipPopupShow = (latlng: any) => {
    shipPopupClose();
    popupShipInstance.value = L.popup({
      className: 'popup-ship-info',
      autoClose: false,
      closeOnClick: false,
      closeButton: false
    })
      .setLatLng(latlng)
      .setContent(popupShip.createDom());

    getMap().openPopup(popupShipInstance.value);
  };
  // 关闭船舶Popup
  const shipPopupClose = () => {
    getMap().closePopup(popupShipInstance.value);
  };
  onBeforeUnmount(() => {
    // 销毁dom
    if (popupShip.dom) {
      popupShip.removeDom();
    }
  });

/PopupShip/index.vue

javascript 复制代码
<template>
  ...
</template>

<script setup lang="ts">

  import { CloseOutlined, LineChartOutlined } from '@ant-design/icons-vue';
  import { Space, Steps, Row, Col } from 'ant-design-vue';
  const { Step } = Steps;

  const props = defineProps({
    currentClickShip: { type: Object, default: () => {} }
  });

  const emits = defineEmits(['goTrack', 'shipPopupClose']);

</script>

<style scoped></style>

dom销毁

Leaflet 的弹窗有个特性:手动关闭弹窗 / 切换弹窗时,弹窗的 DOM 会被 Leaflet 从页面移除,但不会自动销毁 Vue 的组件实例,如果不手动销毁,会造成「Vue 组件内存泄漏」,页面卡顿、事件重复触发等问题。

方案1:监听 Leaflet 弹窗关闭事件,销毁 Vue 组件(推荐,精准)

javascript 复制代码
 const leafletPopup = L.popup({...配置})
    .setLatLng(latlng)
    .setContent(popupDom)

  // ✅ 监听弹窗关闭事件,销毁Vue组件
  leafletPopup.on('remove', () => {
    render(null, popupDom) // 核心:传入null,卸载Vue组件,释放所有资源
  })

方案2:全局统一销毁

javascript 复制代码
onUnmounted(() => {
  ...
  allPopupDom.forEach(dom => render(null, dom))
})
相关推荐
软件开发技术深度爱好者2 小时前
JavaScript的p5.js库使用详解(上)
开发语言·javascript
首席拯救HMI官2 小时前
【拯救HMI】HMI容错设计:如何减少操作失误并快速纠错?
大数据·运维·前端·javascript·网络·学习
深蓝电商API2 小时前
Scrapy与Splash结合爬取JavaScript渲染页面
javascript·爬虫·python·scrapy
m0_748254662 小时前
Vue.js 模板语法基础
前端·vue.js·flutter
donecoding2 小时前
AI时代程序员的护城河:让AI做创意组合,用标准化工具守住质量底线
javascript·架构·代码规范
PBitW2 小时前
和AI浅聊了一下SEO —— 真神Astro
前端·seo
胆大如牛白展堂2 小时前
自动刷新token登录
前端·设计模式
Charon_super2 小时前
html语法笔记
前端·笔记·html
JeffreyTaiT2 小时前
根据binlog恢复SQL
前端·mysql