Atlaslog
Atlaslog / Examples / Leaflet / Basemap Switch
Leaflet · Runnable Example

Basemap Switch

Swap street, light and dark basemaps without losing markers or overlays.

Open standalone → Chinese notes All Leaflet examples
/demos/leaflet-basemap-switch.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/leaflet-basemap-switch.html
<!--
  示例:多底图切换
  要点:三套公开瓦片、保留中心与缩放、版权信息随图层自动更换、按钮组互斥
  依赖:Leaflet 1.9.4 · jsDelivr CDN + Esri 公共瓦片
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="robots" content="noindex,follow">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>多底图切换</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css">
<style>
  html,body{height:100%;margin:0}
  body{display:flex;flex-direction:column;overflow:hidden;
       font:13px/1.6 -apple-system,"Segoe UI","PingFang SC",sans-serif}
  .bar{flex:0 0 auto;padding:8px 12px;background:#f6f7f9;border-bottom:1px solid #e3e6ea;
       display:flex;gap:8px;align-items:center;font-size:12px;color:#58606e}
  .bar .lab{font-weight:600;color:#16181d}
  .bar button{font:inherit;font-size:12px;padding:4px 12px;border-radius:4px;cursor:pointer;
       border:1px solid #ccd1d9;background:#fff;color:#16181d}
  .bar button:hover{background:#eef0f3}
  .bar button.is-on{background:#1f5fd0;border-color:#1f5fd0;color:#fff}
  .bar .spacer{flex:1 1 auto}
  #map{flex:1 1 auto;min-height:0}
  .pin{width:14px;height:14px;border-radius:50%;background:#c2410c;
       border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.25)}
</style>
</head>
<body>
<div class="bar">
  <span class="lab">底图</span>
  <button type="button" class="base is-on" data-base="osm">街道</button>
  <button type="button" class="base" data-base="light">浅色</button>
  <button type="button" class="base" data-base="dark">深色</button>
  <span class="spacer"></span>
  <span id="status">缩放 12</span>
</div>
<div id="map"></div>
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
(function () {
  'use strict';

  var map = L.map('map', {
    center: [39.907359, 116.391263],
    zoom: 12
  });

  var layers = {
    osm: L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
      maxZoom: 19,
      attribution: 'Tiles © Esri'
    }),
    light: L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
      subdomains: 'abcd',
      maxZoom: 20,
      attribution: 'Tiles © Esri'
    }),
    dark: L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
      subdomains: 'abcd',
      maxZoom: 20,
      attribution: 'Tiles © Esri'
    })
  };

  var current = 'osm';
  layers[current].addTo(map);

  /* 一个标记与一个圆,验证切换底图时上层内容不受影响 */
  L.circle([39.907359, 116.391263], {
    radius: 1200,
    color: '#c2410c',
    weight: 1,
    fillColor: '#c2410c',
    fillOpacity: 0.1
  }).addTo(map);

  L.marker([39.907359, 116.391263], {
    icon: L.divIcon({
      className: '',
      html: '<div class="pin"></div>',
      iconSize: [14, 14],
      iconAnchor: [7, 7]
    })
  }).bindPopup('<b>切换底图不会清除上层图层</b>').addTo(map);

  var buttons = document.querySelectorAll('.base');
  var status = document.getElementById('status');

  function markActive(name) {
    for (var i = 0; i < buttons.length; i++) {
      buttons[i].classList.toggle('is-on', buttons[i].getAttribute('data-base') === name);
    }
  }

  function switchBase(name) {
    if (name === current || !layers[name]) return;
    /* 先移除旧底图:版权信息与瓦片请求会一起清掉 */
    map.removeLayer(layers[current]);
    map.addLayer(layers[name]);
    current = name;
    markActive(name);
    status.textContent = '已切换 · 缩放 ' + map.getZoom();
  }

  for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', function () {
      switchBase(this.getAttribute('data-base'));
    });
  }

  map.on('zoomend', function () {
    status.textContent = '缩放 ' + map.getZoom();
  });
})();
</script>
</body>
</html>
Language: the code and this page are in English; the full tutorial and API notes for this example are in Chinese. The demo itself is the authoritative version — it runs exactly as shown.

More Leaflet examples

Leaflet · EXAMPLEMinimal Scene Leaflet · EXAMPLECoord Pick Leaflet · EXAMPLECustom Control