You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Leaflet.js在Vue项目切换多图层时缩放功能异常问题求助

Vue项目中Leaflet切换图层后缩放异常解决方案

问题场景

在Vue项目中使用Leaflet.js渲染地图,多个页面都需要用到两种图层切换功能,但是切换图层后缩放功能出现异常,排除多类常规解决方案后问题仍然存在,一度怀疑是Leaflet 1.7.1版本存在兼容问题。

原始问题代码

<template>
  <div id="mapContainer" class="w-full h-full z-10"></div>
</template>

<script>
import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

import L from 'leaflet';
import 'leaflet-draw';

// import translate from '../translate/MapDraw';

export default {
  props: {
    useUserLocation: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      map: null,
      coords: null,
    };
  },
  methods: {
    async getUserLocation() {
      try {
        const geolocation = await new Promise((resolve, reject) => {
          navigator.geolocation.getCurrentPosition(resolve, reject);
        });

        this.coords = geolocation.coords;
      } catch (error) {
        this.coords = { latitude: -20.7542, longitude: -42.8819 };
      }
    },
  },
  async mounted() {
    if (this.useUserLocation) {
      await this.getUserLocation();
    } else {
      this.coords = { latitude: -20.7542, longitude: -42.8819 };
    }

    const osm = L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      minZoom: 6,
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
    });

    const satellite = L.tileLayer.wms(
      'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
      {
        minZoom: 6,
        maxZoom: 16,
        attribution:
          'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
      },
    );

    // 定义并初始化地图
    this.map = L.map('mapContainer', {
      center: [this.coords.latitude, this.coords.longitude],
      zoom: 15,
      layers: [osm],
      attributionControl: true,
    });

    const baseMaps = {
      'Open Street Map': osm,
      '卫星视图': satellite,
    };

    L.control.layers(baseMaps, null, { position: 'topright', collapsed: true }).addTo(this.map);

  },
  beforeUnmount() {
    if (this.map) {
      this.map.remove();
    }
  },
};
</script>

报错信息

缩放操作时抛出的错误

问题根因

该问题和Leaflet 1.7.1版本无关,根源是Vue data返回的对象会被Proxy代理,和Leaflet构造函数返回的地图这类复杂对象兼容性不好,Proxy的拦截机制会干扰Leaflet内部对地图实例的属性读写,导致缩放、图层切换等操作异常。

可行规避方案

核心思路是避开通过Proxy代理对象操作地图实例,初始化地图时先用局部变量存储原始实例,操作完成后再挂载到data上,销毁时用toRaw获取原始实例再执行销毁操作,修改后的代码如下:

<script>
import { toRaw } from 'vue';

import 'leaflet/dist/leaflet.css';
import 'leaflet-draw/dist/leaflet.draw.css';

import L from 'leaflet';
import 'leaflet-draw';

// import translate from '../translate/MapDraw';

export default {
  props: {
    useUserLocation: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      map: null,
      coords: null,
    };
  },
  methods: {
    async getUserLocation() {
      try {
        const geolocation = await new Promise((resolve, reject) => {
          navigator.geolocation.getCurrentPosition(resolve, reject);
        });

        this.coords = geolocation.coords;
      } catch (error) {
        this.coords = { latitude: -20.7542, longitude: -42.8819 };
      }
    },
  },
  async mounted() {
    if (this.useUserLocation) {
      await this.getUserLocation();
    } else {
      this.coords = { latitude: -20.7542, longitude: -42.8819 };
    }

    const osm = L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      minZoom: 6,
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
    });

    const satellite = L.tileLayer.wms(
      'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
      {
        minZoom: 6,
        maxZoom: 16,
        attribution:
          'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community',
      },
    );

    // 定义并初始化地图,先用局部变量存储原始实例,避免直接操作代理对象
    const map = L.map('mapContainer', {
      center: [this.coords.latitude, this.coords.longitude],
      zoom: 15,
      layers: [osm],
      attributionControl: true,
    });

    const baseMaps = {
      'Open Street Map': osm,
      '卫星视图': satellite,
    };

    L.control.layers(baseMaps, null, { position: 'topright', collapsed: true }).addTo(map);

    this.map = map;
  },
  beforeUnmount() {
    if (this.map) {
      // 取原始实例执行销毁,避免代理对象导致的销毁异常
      toRaw(this.map).remove();
    }
  },
};
</script>

内容的提问来源于stack exchange,提问作者Erick Figueiredo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:45:07