01-用 Leafletjs 10 分钟搭一张水利一张图(Vue3 + Vite 实战)

TL;DR:智慧水利平台第一页那张地图,本质是「底图 + 线状河流 + 点状工程 + 面状范围」四层叠加。本文基于 Leaflet 1.9.4 + Vue3 + Vite,用深圳 mock 数据跑通最小可运行版本。


水利一张图是什么

把物理世界的水利对象按空间位置画到电子地图上,三类要素:

flowchart TD A[水利一张图] --> B[线状要素<br/>河流/堤防/渠道] A --> C[点状要素<br/>水库/水闸/雨量站] A --> D[面状要素<br/>蓄滞洪区/管理范围] B --> B1[L.polyline] C --> C1[L.marker / L.circleMarker] D --> D1[L.polygon]
类型 业务对象 Leaflet API
线状 河流、堤防、渠道 L.polyline
点状 水库、水闸、雨量站、水位站 L.marker / L.circleMarker
面状 蓄滞洪区、河湖管理范围 L.polygon

💡 选型 :正式项目常用 SuperMap / MapGIS / OpenLayers,但展示型一张图、轻量大屏、H5 移动端,Leaflet 足够------gzip 后 ~40KB,开源免费,手势原生。


第一步:起一张底图

纯 HTML 版本(CDN)

map.html

html 复制代码
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<div id="map" style="height: 600px"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

init.js

javascript 复制代码
// 中心 [纬度, 经度],缩放级别 11(深圳市民中心)
const map = L.map('map').setView([22.5431, 114.0579], 11)

// 深色底图:国内推荐 ArcGIS,OSM 加载慢
L.tileLayer(
  'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}',
  { attribution: '&copy; Esri' }
).addTo(map)

⚠️ 国内瓦片坑:不要用 OSM,加载慢且偶尔超时。ArcGIS Dark Gray 在国内可访问,配色也适合大屏。

Vue3 + Vite 版本

bash 复制代码
npm create vite@latest leafletjs-demo -- --template vue
cd leafletjs-demo
npm install leaflet

src/main.js

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import 'leaflet/dist/leaflet.css'

createApp(App).mount('#app')

src/views/Demo01.vue

vue 复制代码
<template>
  <div ref="el" class="demo-map"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import L from 'leaflet'

const el = ref(null)
let map = null

onMounted(() => {
  map = L.map(el.value).setView([22.5431, 114.0579], 11)
  L.tileLayer(
    'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}',
    { attribution: '&copy; Esri' }
  ).addTo(map)
})

onUnmounted(() => map?.remove())
</script>

<style scoped>
.demo-map { position: absolute; inset: 0; }
</style>

⚠️ flex 布局坑 :父容器是 flex 时,.demo-map { height: 100% } 会因为父链高度断裂而塌成 0,地图不显示。改成 position: absolute; inset: 0 最稳。


第二步:画水利要素

河流(Polyline)

javascript 复制代码
// 深圳河(示意坐标)
L.polyline([
  [22.528, 114.045], [22.522, 114.062], [22.515, 114.078],
  [22.508, 114.095], [22.500, 114.112]
], { color: '#1976d2', weight: 3 })
  .addTo(map)
  .bindTooltip('深圳河')

水库(Marker + 自定义图标)

用 divIcon 画水坝 SVG,比默认蓝点专业:

javascript 复制代码
const reservoirIcon = L.divIcon({
  html: `<svg width="22" height="22" viewBox="0 0 22 22">
    <rect x="3" y="7" width="16" height="10" fill="#01579b" stroke="#fff" stroke-width="1.5" rx="2"/>
    <path d="M6 7 L9 3 L13 3 L16 7" fill="none" stroke="#fff" stroke-width="1.5"/>
  </svg>`,
  iconSize: [22, 22],
  iconAnchor: [11, 11],
  className: ''
})

L.marker([22.584, 114.148], { icon: reservoirIcon })
  .addTo(map)
  .bindPopup('<b>深圳水库</b><br/>中型 · 罗湖区')

点击读经纬度

javascript 复制代码
map.on('click', (e) => {
  const { lat, lng } = e.latlng
  console.log(`纬度 ${lat.toFixed(6)},经度 ${lng.toFixed(6)}`)
})

效果预览


⚠️ 三个必踩的坑

1. 地图容器没高度。 Leaflet 容器不会自己撑高,父链任何一环没显式高度就是空白。flex 布局下尤其常见,用 position: absolute; inset: 0 解决。

2. 坐标顺序写反。 Leaflet 所有点坐标都是 [纬度, 经度],但 GeoJSON、CAD 成果给的是 [经度, 纬度]。写反的结果是点全跑非洲去了。

3. 坐标系偏移。 Leaflet 原生只认 Web 墨卡托(EPSG:3857),国内正式数据是 CGCS2000 / GCJ-02,直接叠点位会偏移几百米。下一篇专门讲。


小结

要素 API 一句话
底图 L.tileLayer 瓦片 URL 模板 {z}/{x}/{y}
线状 L.polyline 河流堤防
点状 L.marker 水库测站
交互 bindPopup / bindTooltip 挂业务信息

📦 本文是《智慧水利 GIS 实战》系列第 1 篇,完整 Vue3 demo(10 个场景)见仓库 leafletjs-demo/ 目录,npm run dev 即可跑。

相关推荐
TiDi1 小时前
Pinia优化重复请求
前端
晚安日记wanna1 小时前
Vue2 的 defineProperty 差在哪四层追问筛掉九成候选人
前端·vue.js·面试
TiDi2 小时前
吸顶导航交互实现
前端
kisshyshy2 小时前
从Props透传到自定义Hook:系统梳理React跨层级通信与逻辑复用
前端·架构·代码规范
yume_sibai2 小时前
05-Flutter实战项目
前端·flutter
涛涛ing2 小时前
React 19.3 发布,但真正的赢家是 StyleX:当 AI 成为框架的“第一用户”
前端
zhangminghuan2 小时前
Vue vs React 实战拓展面试题|摒弃基础八股,聚焦业务开发核心难点(2026前端进阶)
前端
IT_陈寒3 小时前
Redis主从切换竟让业务卡了3秒?这个坑我替你踩了
前端·人工智能·后端
天若有情6733 小时前
独立开发复盘:我用 Node.js 做了个在线工具箱
前端·json·工具