不在 App.js 中时反应传单地图位置故障

Posted

技术标签:

【中文标题】不在 App.js 中时反应传单地图位置故障【英文标题】:React leaflet map location glitches when not in App.js 【发布时间】:2021-06-28 04:33:36 【问题描述】:

我试图在我的 React 应用程序中使用 Leaflet 地图,但我遇到了一个奇怪的问题。我告诉我的地图在 whenReady 函数中平移到用户的当前地理位置(如果他们允许访问他们的位置),但是当它这样做时,地图会出现故障。更奇怪的是,只有当我将地图放在从 App.js 路由到的视图中时才会发生这种情况(我想将它与导航栏一起显示)。当它在 App.js 本身中时,不会发生这种情况,并且地图会正确显示我的位置。我附上了图片来说明我的意思:

当地图在 App.js 中时:

当地图在另一个组件中时:

这是我针对这两种情况的代码:

地图在App.js中时的代码:

import React, Component from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import  MapContainer, TileLayer, Marker, Popup  from 'react-leaflet';

class App extends Component 
  constructor() 
    super();
    this.state = 
      markers: [],
      center: [51.505, -0.09]
    ;
    this.addMarker = this.addMarker.bind(this)
  

  fence = L.icon(
    iconUrl: fence,
    iconSize:     [46.3125, 51.5625], // size of the icon
    iconAnchor:   [22, 25], // point of the icon which will correspond to marker's location
    popupAnchor:  [0, -25]
  );
  
  addMarker = (e) => 
    const markers = this.state
    markers.push(this.state.center)
    this.setState(markers)
  

  render() 
    const self = this;
    return (
      <div className="map-container">
        <button onClick=this.addMarker className="btn">+</button>
        <div className="center"></div>
      <MapContainer 
        className="map"
        minZoom= 8
        zoom=20 
        center = this.state.center
        whenReady=(map) => 
          if ('geolocation' in navigator) 
            navigator.geolocation.getCurrentPosition(function (location) 
              console.log(location);
              map.target.panTo(new L.LatLng(location.coords.latitude, location.coords.longitude))

              var marker = L.marker([location.coords.latitude, location.coords.longitude], icon: L.icon(
                iconUrl: pin,
                iconSize:     [24, 38], // size of the icon
                iconAnchor:   [12.5, 40], // point of the icon which will correspond to marker's location
                popupAnchor:  [0, -50]
              ) ).addTo(map.target);
              marker.bindPopup("Your current location")
              marker.openPopup()
            );
          

          map.target.on("drag", function (e) 
            self.setState(center: map.target.getCenter())
          );

          map.target.on("zoom", function (e) 
            self.setState(center: map.target.getCenter())
          )
        
        >
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url='http://s.tile.osm.org/z/x/y.png'
        ></TileLayer>
        this.state.markers.map((position, idx) => 
          <Marker key=`marker-$idx` icon=this.fence position=position>
          <Popup>
            <span>Title<br/></span>
          </Popup>
        </Marker>
        )
      </MapContainer>
      </div>
    );
  


export default App;

地图在另一个视图中时的代码,从 App.js 路由:

//App.js
import React from "react";
import "./App.css";
import  BrowserRouter as Router, Switch, Route  from "react-router-dom";
import MapView from './MapView';
import AddView from './AddView';
import Navbar from './Navbar';

function App() 
  return (
    <div className="App">
      <Router>
      <Navbar/>
        <Switch>
          <Route exact from="/" component=MapView />
          <Route exact path="/new" component=AddView />
        </Switch>
      </Router>
    </div>
  );


export default App;

//MapView.js
import React, Component from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import  MapContainer, TileLayer, Marker, Popup  from 'react-leaflet';

class MapView extends Component 
  constructor() 
    super();
    this.state = 
      markers: [],
      center: [51.505, -0.09]
    ;
    this.addMarker = this.addMarker.bind(this)
  

  fence = L.icon(
    iconUrl: fence,
    iconSize:     [46.3125, 51.5625], // size of the icon
    iconAnchor:   [22, 25], // point of the icon which will correspond to marker's location
    popupAnchor:  [0, -25]
  );
  
  addMarker = (e) => 
    const markers = this.state
    markers.push(this.state.center)
    this.setState(markers)
  

  render() 
    const self = this;
    return (
      <div className="map-container">
        <button onClick=this.addMarker className="btn">+</button>
        <div className="center"></div>
      <MapContainer 
        id="map"
        className="map"
        minZoom= 8
        zoom=20 
        center = this.state.center
        whenReady=(map) => 
            if ('geolocation' in navigator) 
              navigator.geolocation.getCurrentPosition(function (location) 
                localStorage.setItem('latitude', location.coords.latitude)
                localStorage.setItem('longitude', location.coords.longitude)
                let latitude= location.coords.latitude;
                let longitude= location.coords.longitude;
                console.log(location);

                map.target.panTo(new L.LatLng(latitude, longitude))
  
                var marker = L.marker([latitude, longitude], icon: L.icon(
                  iconUrl: pin,
                  iconSize:     [24, 38], 
                  iconAnchor:   [12.5, 40], 
                  popupAnchor:  [0, -50]
                ) ).addTo(map.target);
                marker.bindPopup("Your current location")
                marker.openPopup()
              );
             else 
                console.log("Ik kom erin bro wtf")
                let latitude = localStorage.getItem('latitude') ?? 51.505
                let longitude = localStorage.getItem('longitude') ?? -0.09

                map.target.panTo(new L.LatLng(latitude, longitude))
            
  
            map.target.on("drag", function (e) 
              self.setState(center: map.target.getCenter())
            );
  
            map.target.on("zoom", function (e) 
              self.setState(center: map.target.getCenter())
            )
          
        >
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url='http://s.tile.osm.org/z/x/y.png'
        ></TileLayer>
        this.state.markers.map((position, idx) => 
          <Marker key=`marker-$idx` icon=this.fence position=position>
          <Popup>
            <span>Title<br/></span>
          </Popup>
        </Marker>
        )
      </MapContainer>
      </div>
    );
  


export default MapView;

//Navbar.js
import  makeStyles  from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import 
    Link
   from "react-router-dom";


const useStyles = makeStyles((theme) => (
    root: 
      flexGrow: 1,
    ,
    menuButton: 
      marginRight: theme.spacing(2),
    ,
    title: 
      flexGrow: 1,
    ,
    bar: 
        height: '7.5vh',
    
  ));

function Navbar() 
    const classes = useStyles();

    return (
        <AppBar position="static" className=classes.bar>
        <Toolbar>
          <IconButton edge="start" className=classes.menuButton color="inherit" aria-label="menu">
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" className=classes.title>
            Work in progress
          </Typography>
          <Link color="inherit" to="/new">Report construction</Link>
          <Button color="inherit">Login</Button>
        </Toolbar>
      </AppBar>
    );
  
  
  export default Navbar;

我对 Leaflet 没有太多了解,因为这是我用它制作的第一个应用程序,所以如果我混淆了这背后的一些理论,请考虑这一点。有谁知道我的代码、我的思维方式是否有问题,或者是否有一些我遗漏的传单理论?我期待听到任何答案。

【问题讨论】:

【参考方案1】:

这是因为您将地图缩放指定为 20,而上限为 19。您可以在 post 上找到更多原因

您所要做的就是在TileLayer 组件上设置maxZoommaxNativeZoom 属性

<TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
     url='http://s.tile.osm.org/z/x/y.png'
     maxNativeZoom=19
     maxZoom=22
 />

【讨论】:

【参考方案2】:

您可能想尝试在 whenReady() 中平移到您的位置之前设置延迟。函数启动时地图可能没有完全呈现,这也许可以解决问题

setTimeout(() =>  this.goToLocation() , 1000);

【讨论】:

以上是关于不在 App.js 中时反应传单地图位置故障的主要内容,如果未能解决你的问题,请参考以下文章

传单:找不到地图容器

反应传单地图上自动打开标记弹出

单击反应传单 v.3.x 中的标记时如何动态更改地图缩放?

反应传单地图不显示

反应传单地图未正确显示

从反应传单中的地图中删除缩放控件