Skip to content

图层管理

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

示例

TIP

图层管理是地图应用中的一个重要功能,它允许用户控制不同地图图层的显示和隐藏,以及调整图层的透明度。本示例展示了如何实现基础的图层管理功能。

新标签页预览

代码实现

vue
<template>
  <div class="page-container">
    <div class="layer-container"></div>
    <div id="map"></div>
  </div>
</template>

<script setup>
import { onMounted } from "vue";

onMounted(() => {
  const tdtUrl =
    "http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd";
  const tdtUrl2 =
    "http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=d32c6748c80f81a44acd8633cea41dfd";
  const map = L.map("map").setView([39.094899, 117.33083], 13);
  const tdtMap = L.tileLayer(tdtUrl).addTo(map);

  const layerContainer = document.querySelector(".layer-container");

  const layers = [
    {
      name: "基础图层",
      children: [
        { name: "天地图矢量", id: "tdt1", checked: true },
        { name: "天地图影像", id: "tdt2", checked: false },
      ],
    },
  ];

  function createLayerTree(layers, parent) {
    const ul = document.createElement("ul");
    layers.forEach((layer) => {
      const li = document.createElement("li");
      li.className = "layer-container__item";
      if (layer.children) {
        const span = document.createElement("span");
        span.textContent = layer.name;
        li.appendChild(span);
        li.appendChild(createLayerTree(layer.children, li));
      } else {
        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.id = layer.id;
        checkbox.checked = layer.checked;
        checkbox.onchange = (event) => toggleLayerVisibility(event, layer.id);

        const label = document.createElement("label");
        label.htmlFor = layer.id;
        label.textContent = layer.name;

        const opacitySlider = document.createElement("input");
        opacitySlider.type = "range";
        opacitySlider.min = "0";
        opacitySlider.max = "100";
        opacitySlider.value = "100";
        opacitySlider.className = "opacity-slider";
        opacitySlider.id = `${layer.id}-opacity`;
        opacitySlider.disabled = !layer.checked;
        opacitySlider.onchange = (event) => adjustLayerOpacity(event, layer.id);

        li.appendChild(checkbox);
        li.appendChild(label);
        li.appendChild(opacitySlider);
      }
      ul.appendChild(li);
    });
    return ul;
  }

  const tdt2 = L.tileLayer(tdtUrl2, { maxZoom: 18 });

  const tree = createLayerTree(layers, layerContainer);
  layerContainer.appendChild(tree);

  function adjustLayerOpacity(event, layerId) {
    const opacity = event.target.value / 100;
    const layers = {
      tdt1: tdtMap,
      tdt2: tdt2,
    };

    if (layers[layerId]) {
      layers[layerId].setOpacity(opacity);
    }
  }

  function toggleLayerVisibility(event, layerType) {
    const layerActions = {
      tdt1: {
        add: () => map.addLayer(tdtMap),
        remove: () => map.removeLayer(tdtMap),
      },
      tdt2: {
        add: () => map.addLayer(tdt2),
        remove: () => map.removeLayer(tdt2),
      },
    };

    // 获取对应的透明度滑块
    const opacitySlider = document.getElementById(`${layerType}-opacity`);
    // 根据图层可见性设置滑块状态
    opacitySlider.disabled = !event.target.checked;

    const action = layerActions[layerType];
    if (action) {
      if (event.target.checked) {
        action.add();
      } else {
        action.remove();
      }
    }
  }
});
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

li {
  list-style: none;
}

body {
  width: 100%;
  height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
}

#map {
  width: 100%;
  height: 100%;
}

.page-container {
  display: flex;
  height: 100%;
  width: 100%;
}

.layer-container {
  width: 320px;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  overflow-y: auto;
}

.layer-container__item {
  margin: 12px 0;
  padding: 15px;
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.layer-container__item:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.layer-container__item span {
  font-weight: 600;
  color: #333;
  font-size: 16px;
}

.layer-container__item label {
  margin-left: 8px;
  color: #444;
  font-size: 14px;
}

.layer-container__item input[type="checkbox"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

.opacity-slider {
  width: 100%;
  margin-top: 12px;
  height: 4px;
  background: #e9ecef;
  border-radius: 2px;
  -webkit-appearance: none;
  appearance: none;
}

.opacity-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  background: #4a90e2;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s ease;
}

.opacity-slider::-webkit-slider-thumb:hover {
  transform: scale(1.1);
  background: #357abd;
}

.opacity-slider:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.opacity-slider:disabled::-webkit-slider-thumb {
  background: #999;
  cursor: not-allowed;
}

.hideLayer {
  display: none;
}
</style>
关注公众号