唯杰地图 logo唯杰地图
VJMAP
EN

with-popup

vjmap/references/marker/with-popup.md 4.0 KB149 行
原文

本文回答:Marker 与 Popup 的绑定 —— setPopup / togglePopup / getPopup。

一、基本绑定

const popup = new vjmap.Popup({ offset: [0, -40] })
  .setHTML("<h3>站点 A</h3><p>状态:正常</p>");

const marker = new vjmap.Marker()
  .setLngLat([lng, lat])
  .setPopup(popup);
marker.addTo(map);   // addTo 返回 undefined,勿接链尾

点 Marker 打开 Popup。⚠️ 默认 closeOnClick: true 时再点 Marker 会先关后开(popup 在 preclick 关闭,Marker 随后在 click 里 toggle 又打开,关不掉);要开 / 关切换用 new vjmap.Popup({ closeOnClick: false })。

二、手动打开 / 关闭

marker.togglePopup();    // 切换

// 读
const p = marker.getPopup();
p.isOpen();              // true / false

// 手动 addTo / remove
p.addTo(map);
p.remove();

三、Popup 参数(常用)

new vjmap.Popup({
  closeButton: true,       // 右上 ×
  closeOnClick: true,      // 点击地图任意处(含要素、Marker)即关闭
  closeOnMove: false,      // 地图移动时关闭
  anchor: "bottom",        // 尖尖方向:top/bottom/left/right/top-left/...
  offset: [0, -40],        // 像素偏移
  className: "my-popup",   // 自定义类名
  maxWidth: "300px"
});

四、hover 显示 Popup

const el = marker.getElement();
el.addEventListener("mouseenter", () => {
  if (!popup.isOpen()) marker.togglePopup();
});
el.addEventListener("mouseleave", () => {
  if (popup.isOpen()) popup.remove();
});

五、自定义 Popup 内容

5.1 HTML 字符串

popup.setHTML(`
  <div class="card">
    <img src="/a.jpg"/>
    <h3>站点 A</h3>
    <p>温度:26℃</p>
    <button onclick="alert(1)">详情</button>
  </div>
`);

5.2 setText(纯文本)

popup.setText("纯文本,不解析 HTML");

5.3 setDOMContent(现成 DOM)

const div = document.createElement("div");
div.appendChild(imgEl);
div.appendChild(titleEl);
popup.setDOMContent(div);

六、Popup 样式

.vjmapgis-popup { z-index: 10; }
.vjmapgis-popup-content {
  background: rgba(0,0,0,0.8);
  color: #fff;
  border-radius: 8px;
}
[class*="vjmapgis-popup-anchor-bottom"] .vjmapgis-popup-tip { border-top-color: rgba(0,0,0,0.8); }   /* 含 bottom-left/right;top/left/right 角向同理 */

或用 className:

new vjmap.Popup({ className: "my-popup" });
// .my-popup .vjmapgis-popup-content { ... }

七、按钮动作(setHTML 内)

setHTML 后 DOM 是 vjmap 控制的,事件要在 addTo 之后挂:

popup.setHTML('<button id="btn-x">删除</button>');
popup.on("open", () => {
  document.getElementById("btn-x")?.addEventListener("click", () => {
    marker.remove();
    popup.remove();
  });
});

八、Vue/React 渲染到 Popup

const container = document.createElement("div");
createApp(MyPopupCard, { site: data }).mount(container);
popup.setDOMContent(container);

九、多个 Marker 共享一个 Popup(切换式)

const popup = new vjmap.Popup({ closeButton: false });

markers.forEach(m => {
  m.getElement().addEventListener("click", () => {
    popup.setLngLat(m.getLngLat()).setHTML(m.data.name).addTo(map);
  });
});

好处:只有一个 Popup 对象,性能好,不会累积。

十、常见坑

  1. setPopup 后点 Marker 不开 → Marker 本身是 draggable 时 click 被拖拽拦截;用 clickTolerance。
  2. Popup 位置不对:检查 offset;Marker 用 anchor: bottom,Popup 一般用 offset: [0, -40](向上)。
  3. Popup 内按钮无反应:setHTML 后 popup DOM 还没挂到文档;等 open 事件或用 setDOMContent。
  4. Popup 关了再开内容仍在:remove() 只把 _content 从文档摘除,重开时 _update 会重新 appendChild(_content)——内容不丢,不用重新 setDOMContent/setHTML。
  5. closeOnMove: true 导致 hover 难用 → 设为 false。