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))
})
相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A5 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄5 天前
JavaScript 隐式全局变量解析
javascript
honkun65 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19915 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net