Skip to content

使用 Popups

上次更新 2025年8月20日星期三 3:16:20 字数 0 字 时长 0 分钟

示例

新标签页预览

代码实现

vue
<template>
  <div id="map" class="w-full h-96"></div>
  <div id="popup" class="ol-popup">
    <a href="#" id="popup-closer" class="ol-popup-closer"></a>
    <div id="popup-content"></div>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import { fromLonLat } from "ol/proj";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import Circle from "ol/geom/Circle";
import Polygon from "ol/geom/Polygon";
import { Style, Fill, Stroke, Circle as CircleStyle } from "ol/style";
import Overlay from "ol/Overlay";

onMounted(() => {
  // 创建地图
  const map = new Map({
    target: "map",
    layers: [
      new TileLayer({
        source: new XYZ({
          url: "http://{a-c}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
        }),
      }),
    ],
    view: new View({
      center: fromLonLat([-0.09, 51.505]),
      zoom: 13,
    }),
  });

  // 创建弹窗元素
  const container = document.getElementById("popup");
  const content = document.getElementById("popup-content");
  const closer = document.getElementById("popup-closer");

  // 创建弹窗覆盖物
  const overlay = new Overlay({
    element: container,
    autoPan: true,
    autoPanAnimation: {
      duration: 250,
    },
  });
  map.addOverlay(overlay);

  // 关闭按钮点击事件
  closer.onclick = function () {
    overlay.setPosition(undefined);
    closer.blur();
    return false;
  };

  // 创建矢量图层
  const vectorSource = new VectorSource();
  const vectorLayer = new VectorLayer({
    source: vectorSource,
  });
  map.addLayer(vectorLayer);

  // 添加标记点
  const marker = new Feature({
    geometry: new Point(fromLonLat([-0.09, 51.505])),
    name: "A pretty CSS3 popup.<br> Easily customizable.",
  });
  marker.setStyle(
    new Style({
      image: new CircleStyle({
        radius: 6,
        fill: new Fill({
          color: "#3388ff",
        }),
        stroke: new Stroke({
          color: "#ffffff",
          width: 2,
        }),
      }),
    })
  );
  vectorSource.addFeature(marker);

  // 添加圆
  const circle = new Feature({
    geometry: new Circle(fromLonLat([-0.11, 51.508]), 500),
    name: "我是圆",
  });
  circle.setStyle(
    new Style({
      fill: new Fill({
        color: "rgba(255,0,51,0.5)",
      }),
      stroke: new Stroke({
        color: "red",
        width: 2,
      }),
    })
  );
  vectorSource.addFeature(circle);

  // 添加多边形
  const polygon = new Feature({
    geometry: new Polygon([
      [
        fromLonLat([-0.08, 51.509]),
        fromLonLat([-0.06, 51.503]),
        fromLonLat([-0.047, 51.51]),
        fromLonLat([-0.08, 51.509]),
      ],
    ]),
    name: "我是多边形",
  });
  polygon.setStyle(
    new Style({
      fill: new Fill({
        color: "rgba(51,136,255,0.5)",
      }),
      stroke: new Stroke({
        color: "#3388ff",
        width: 2,
      }),
    })
  );
  vectorSource.addFeature(polygon);

  // 点击事件处理
  map.on("click", function (evt) {
    const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
      return feature;
    });

    if (feature) {
      const coordinates =
        feature.getGeometry().getType() === "Point"
          ? feature.getGeometry().getCoordinates()
          : evt.coordinate;

      content.innerHTML = feature.get("name");
      overlay.setPosition(coordinates);
    } else {
      overlay.setPosition(undefined);
    }
  });
});
</script>

<style scoped>
.w-full {
  width: 100%;
}
.h-96 {
  height: 24rem;
}

.ol-popup {
  position: absolute;
  background-color: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  padding: 15px 35px 15px 15px;
  border-radius: 10px;
  border: 1px solid #cccccc;
  bottom: 12px;
  left: -50px;
  min-width: 180px;
}

.ol-popup:after,
.ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}

.ol-popup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}

.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}

.ol-popup-closer {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 20px;
  height: 20px;
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #999;
  border-radius: 50%;
  transition: all 0.2s;
}

.ol-popup-closer:hover {
  background: #f0f0f0;
  color: #666;
}

.ol-popup-closer:after {
  content: "×";
}
</style>
关注公众号