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))
})
相关推荐
是上好佳佳佳呀1 小时前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记
莎士比亚的文学花园1 小时前
Linux驱动开发(3)——设备树
开发语言·javascript·ecmascript
CDN3602 小时前
排查实录:网站偶发502/504错误?360CDN回源超时配置与日志分析技巧
前端·数据库
之歆2 小时前
Day07_CSS盒子模型 · 样式继承 · 用户代理样式
前端·css
01漫游者2 小时前
JavaScript函数与对象增强知识
开发语言·javascript·ecmascript
DanCheOo2 小时前
AI 应用的安全架构:Prompt 注入、数据泄露、权限边界
前端·人工智能·prompt·安全架构
We་ct3 小时前
深度剖析浏览器跨域问题
开发语言·前端·浏览器·跨域·cors·同源·浏览器跨域
weixin_427771614 小时前
前端调试隐藏元素
前端
threelab4 小时前
Three.js 代码云效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
爱上好庆祝5 小时前
学习js的第五天
前端·css·学习·html·css3·js