我从一个Vue.js项目(版本3)的传单中得到了一个奇怪的错误。
如果关闭弹出窗口并放大/缩小,则在Firefox上会出现此错误:
Uncaught : this._map为空
在Chrome上:
无法读取null的属性“_latLngToNewLayerPoint”
地图组件如下:
<template>
<div id="map"></div>
</template>
<script>
import "leaflet/dist/leaflet.css";
import L from 'leaflet';
export default {
name: 'Map',
data() {
return {
map: null
}
},
mounted() {
this.map = L.map("map").setView([51.959, -8.623], 12);
L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(this.map);
L.circleMarker([51.959, -8.623]).addTo(this.map)
.bindPopup('I am a marker')
.openPopup();
}
}
</script>
<style scoped>
#map {
height: 300px;
width: 100%;
}
</style>如何再现错误:
https://stackblitz.com/edit/vue-gjeznj
能不能只是个窃听器?或者代码中有我遗漏的错误吗?
发布于 2021-03-18 15:03:23
FWIW,这似乎是一个新的问题,因为Vue 3。
在Vue版本2中没有这个问题,并附有传单:https://codesandbox.io/s/fast-firefly-lqmwm?file=/src/components/HelloWorld.vue。
为了确保,这里是CodeSandbox:https://codesandbox.io/s/laughing-mirzakhani-sgeoq?file=/src/components/HelloWorld.vue上使用相同代码( Vue version 3 )的问题的再现
罪魁祸首似乎是Vue代理this.map,这似乎干扰了传单事件(Un)的绑定。它看起来像Vue 3现在自动执行深度代理,而Vue 2是浅的。
如https://v3.vuejs.org/api/basic-reactivity.html#markraw所述
...下面的shallowXXX API允许您选择性地选择退出默认的深反应/只读转换,并在状态图中嵌入原始的、非代理的对象。它们可因各种原因而使用:
...which是传单生成的map对象的例子。
一个非常简单的解决方法是不使用this.map (即不将已构建的map对象存储在组件状态,以防止Vue代理它),而只是在本地存储它(例如,const map = L.map()和myLayer.addTo(map))。
但是,如果我们确实需要存储map对象,通常是为了以后可以重用它,例如,如果我们想在用户操作上添加一些层,该怎么办?
然后,在使用传单之前,确保正确地展开/取消代理this.map,例如使用Vue 3 toRaw utility function
返回
reactive或readonly代理的原始对象。这是一个转义舱口,可用于临时读取而不引起代理访问/跟踪开销,或写入而不触发更改。
import { toRaw } from "vue";
export default {
name: "Map",
data() {
return {
map: null,
};
},
mounted() {
const map = L.map("map").setView([51.959, -8.623], 12);
L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
L.circleMarker([51.959, -8.623])
.addTo(map)
.bindPopup("I am a marker")
.openPopup();
this.map = map;
},
methods: {
addCircleMarker() {
L.circleMarker([
51.959 + Math.random() * 0.05,
-8.623 + Math.random() * 0.1,
])
.addTo(toRaw(this.map)) // Make sure to "unproxy" the map before using it with Leaflet
.bindPopup("I am a marker")
.openPopup();
},
},
}演示:https://codesandbox.io/s/priceless-colden-g7ju9?file=/src/components/HelloWorld.vue
https://stackoverflow.com/questions/65981712
复制相似问题