您想在您的Nextjs应用程序中包括交互式地图吗?然后,您一定遇到过Leafletjs。尽管Leafletjs的使用非常简单,但是在使用Nextjs构建服务器端渲染(SSR)应用程序时,它有时会有些烦人。但是,您不用担心我已经找到了解决方法。
要设置场景,首先让我们知道👇
为什么选择Leafletjs?
Leaflet是领先open-source
的mobile-friendly
交互式地图JavaScript库。它仅重约39 KB的JS,它具有mapping features
开发人员所需要的所有内容。
Leaflet的目的是尽可能轻巧,并专注于一组核心功能,而扩展其功能的一种简单方法是使用第三方插件。感谢Leaflet背后的强大社区,实际上有数百个不错的插件可供选择。在本文后面的示例中,我们将使用其中一个插件。
讲解
请注意,在本教程中,我假设您已经有一个现有的Next.js项目正在运行。如果不这样做,请先遍历Next.js文档。
安装所需的依赖项
npm i leaflet leaflet-defaulticon-compatibility leaflet-geosearch react-leaflet
注意:如果使用TypeScript,请确保安装,@types/leaflet
否则在示例中使用的某些属性上会出现编译错误。
我将在本教程中进一步使用它们时解释它们的需求。
创建地图组件
在您的应用程序中,在component文件夹中创建一个map.jsx文件./component/Map.jsx
。
此代码与嵌入页面的文件位于单独的文件中非常重要,因为否则您将收到窗口未定义的错误,稍后我们将对此进行讨论。
旁注:对于Typescript用户,该文件称为map.tsx。
在文件内部放入以下代码
import { MapContainer, TileLayer,Marker,Popup } from 'react-leaflet'
import 'leaflet/dist/leaflet.css'
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css'
import "leaflet-defaulticon-compatibility";
const Map = () => {
return (
<MapContainer center={[40.8054,-74.0241]} zoom={14} scrollWheelZoom={false} style={{height: "100%", width: "100%"}}>
<Marker
position={[40.8054,-74.0241]}
draggable={true}
animate={true}
>
<Popup>
Hey ! you found me
</Popup>
</Marker>
</MapContainer>
)
}
export default Map
在上面的示例中,我使用了react-leaflet的一些基本属性来初始化地图。
center
:以所提供的纬度和经度为中心。zoom
:地图的初始缩放范围为0到18。scrollWheelZoom
:是的,这正是听起来的样子。position
:设置标记的位置。draggable
:有助于将标记拖放到地图上。animate
:如果为true,则平移将始终保持动画状态。
react-leaflet文档中提供了许多功能和示例。
设置Mapbox API
在上面的示例中,我们将使用Mapbox API将自定义标题图层添加到地图中。
传单静静地支持Mapbox插件,它还为您提供了许多自定义映射样式,您甚至可以在其工作室中创建自己的样式,因为本教程的这一部分将使用默认样式。
设置自定义Mapbox样式的第一件事是拥有一个帐户。我不会指导您完成该过程,但是您可以转到Mapbox的网站,免费注册。
为了生成令牌,我们将使用令牌来提供对地图的访问权限。
- 转到Mapbox信息中心的“帐户”部分,您可以通过单击导航栏右上部分的个人资料来访问它。
- Mapbox为您提供了一个“默认”令牌,您可以在应用程序中使用它。您可以随意使用它,但是我建议您创建一个新令牌,以提供唯一的名称。
配置我们的自定义端点
在本教程中,我们将使用Mapbox的Static Tiles服务。您可以从此处复制端点,如下所示。
https://api.mapbox.com/styles/v1/{username}/{style_id}/tiles/256/{z}/{x}/{y}@2x?access_token={access_token}
这里需要了解一些参数:
username
:这将是您的Mapbox帐户的用户名style_id
:这将是您使用的样式的IDz, x, y
:这些是Leaflet以编程方式交换的参数,因此我们希望保留它们不变access_token
:这是您在上方创建的Mapbox键
对于示例的这一部分,我们使用的是Mapbox本身提供的样式。您也可以在Mapbox中创建自己的样式,但现在将使用streets-v11
from here。
更新端点参数后,最终的tilepoint URL将如下所示:
https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=MY_ACCESS_TOKEN
由于样式是由mapbox提供的,因此URL中的用户名将替换为mapbox,如果您使用自己的样式,则将其替换为您自己的用户名。
向React Leaflet添加自定义TileLayer
你的里面<MapContainer>
在map.jsx组件,您有一个<TileLayer>
组件,它定义了世界的形象,你的基础在地图。
React Leaflet主页上的示例使用OpenStreetMap的公共版本作为TileLayer,这是一个由世界各地的人们创建和更新的开源地图项目。
<MapContainer center={position} zoom={13}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
</MapContainer>
这为您提供了基本的地图,但是我们希望在Mapbox中进行交换,以便我们可以为地图设置自定义外观。
要添加自定义样式,我们将要更新TileLayer组件的url
和attribution
属性。
对于URL,它只是我们之前创建的自定义样式终结点,因此在我的示例中,它看起来像:
https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=MY_ACCESS_TOKEN
对于归因,我们希望将Mapbox归功于服务,因此我们希望将归因设置为:
Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>
插入TileLayer后,我们的map.jsx现在应如下所示:
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
const Map = () => {
return (
<MapContainer
center={[40.8054, -74.0241]}
zoom={14}
scrollWheelZoom={false}
style={{ height: "100%", width: "100%" }}
>
<TileLayer
url={`https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}@2x?access_token=MY_ACCESS_TOKEN`}
attribution='Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
/>
<Marker position={[40.8054, -74.0241]} draggable={true} animate={true}>
<Popup>Hey ! I live here</Popup>
</Marker>
</MapContainer>
);
};
export default Map;
最后,让我们渲染地图
如您所知,全局window
对象在SSR中不可用,如果尝试在其中使用它,则会收到ReferenceError。
现在,为了避免这种情况,我们可以利用Nextjs的动态加载优势,这将有助于防止SSR。
在内部./pages/index.js
嵌入您的Map组件,如下所示:
import React from "react";
import dynamic from "next/dynamic";
export default function Home() {
const MapWithNoSSR = dynamic(() => import("../component/map"), {
ssr: false
});
return (
<main>
<div id="map">
<MapWithNoSSR />
</div>
</main>
);
}
这就是您的好选择
总结思想
我希望这个快速教程对您有所帮助。我知道如果在执行Next.js + leafletjs路径之前进行此操作,它将为我节省很多工作。一旦一切顺利,别忘了向我提供宝贵的反馈意见。祝你好运!👍