openlayer - 气泡浮动窗口

核心问题

如果你正常尝试使用 overlay 实现浮动窗口,大概率会遇到这个问题:

使用 overlay 的时候,不论怎样调整 html 的 z-index 都不会生效。

这是因为源码中,父级元素已经固定填 0,子元素无法突破父级的元素堆叠层级。

下一行是关键代码,设置 overlay 的时候,需要调整父级元素的 z-index。

element.parentElement.style.zIndex = 1;

样例代码

VUE3 环境,语法差别不大,按照实际情况调整

<template>
  <div id="map_container" style="width: 100%; height: 100%">
    <div id="map" class="map" style="width: 100%; height: 100%;"></div>
  </div>
</template>

<script setup lang="ts">
import Map from 'ol/Map';
import View from 'ol/View';
import Overlay from 'ol/Overlay';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';

import Style from 'ol/style/Style';
import {onMounted} from "vue";

// 上一次点击的浮动窗口
let pre_overlay = undefined;

/**
 * 创建一个用于浮动的窗口
 *
 * 这里需要复杂设计,每次点击浮动的时候,需要重新渲染内容
 *
 * @returns 浮动窗口
 */
const createPopover: HTMLElement = () => {
    const element = document.createElement('div');
    element.classList.add('float-bottom');
    element.classList.add('sea-arrow-after-top');
    element.innerHTML = '<span>浮动窗口</span>';
    return element;
}

const popover = createPopover();

/**
 * 创建一个浮动层
 *
 * @param map -
 * @param position -
 * @param model -
 * @param zIndex -
*/
const createOverlay = (map, position, model, zIndex: number = 1) => {
    // create overlay
    const element = document.createElement('div');
    element.classList.add('sea-float-box');
    element.innerHTML = `<button class="el-button">${model}</button>`;
    const htmlOverlay = new Overlay({
        position: position,
        element: element,
        positioning: 'top-left'
    });
    map.addOverlay(htmlOverlay);

    // event
    element.addEventListener('click', () => {
        // 恢复上一次浮动层的 z-index
        if (pre_overlay !== undefined) {
            pre_overlay.parentElement.style.zIndex = 0;
        }

        // 记录浮动层,并切换气泡窗口的父级容器
        pre_overlay = element;
        element.appendChild(popover);

        // 重点是这一行代码
        element.parentElement.style.zIndex = zIndex;
    });
}

onMounted(() => {
    let map = new Map({
        view: new View({
            center: [12950000, 4860000],
            zoom: 4
        }),
        layers: [
            // 底图
            new TileLayer({
                source: new XYZ({url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}'})
            })
        ],
        target: 'map'
    });

    // 鼠标点击事件
    map.on('click', function (evt) {
        console.log(evt.pixel);
    });

    createOverlay(map, [12950000, 4860000], 'popover1', 1);
    createOverlay(map, [12950000, 4970000], 'popover2', 1);
})
</script>

<style>
.map {
    width: 100%;
    height: 400px;
}
</style>

气泡窗口的 css 样式

scss语法,可以让 AI 帮忙转换成其他格式

/**
 * 通过 css 相对布局实现的吸附窗口
 * -------------------------------------------------------
 * 优点:通过 css 样式实现的,性能相对较好,更加实用的方式;
 * 缺点:是增加了一层 div,特定场合下,可能会影响界面布局。
 */
// attribute
$float-box-z-index: 100;
$float-box-bg: white;
$float-box-border: 1px solid #ddd;
$float-box-radius: 4px;
$float-box-padding: 12px;
// 阴影预留值
$float-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
$float-box-shadow: $sea-box-shadow;

// base-setting
@mixin float-panel {
  position: absolute;
  padding: $float-box-padding;
  background: $float-box-bg;
  border: $float-box-border;
  border-radius: $float-box-radius;
  box-shadow: $float-box-shadow;
  z-index: $float-box-z-index;
}

.sea-float-box {
  position: relative;
  display: inline-block;

  .float-top {
    @include float-panel;
    left: 0; // 左对齐
    //right: 0; // 右对齐
    bottom: 100%; // 底边对齐
    margin-bottom: 10px;
  }

  .float-bottom {
    @include float-panel;
    left: 0; // 左对齐
    //right: 0; // 右对齐
    top: 100%; // 顶部对齐
    margin-top: 10px;
  }

  .float-left {
    @include float-panel;
    top: 0;
    right: 100%;
    margin-right: 10px;
  }

  .float-right {
    @include float-panel;
    top: 0;
    left: 100%;
    margin-left: 10px;
  }
}

posted on 2025-07-31 17:29  疯狂的妞妞  阅读(34)  评论(0)    收藏  举报

导航