223 lines
5.0 KiB
Vue
Raw Normal View History

2026-03-31 18:10:34 +08:00
<template>
<div class="chongqing-map-container">
<div ref="mapContainer" class="map-container"></div>
<div v-if="loading" class="loading-overlay">
<div class="loading-spinner"></div>
<span class="loading-text">地图加载中...</span>
</div>
<div v-if="error" class="error-overlay">
<span class="error-text">{{ error }}</span>
<button class="retry-btn" @click="loadMapData">重试</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const mapContainer = ref(null)
const loading = ref(false)
const error = ref(null)
let mapInstance = null
// 重庆地图GeoJSON API地址
const GEOJSON_URL = 'https://geo.datav.aliyun.com/areas_v3/bound/500000_full.json'
// 加载地图数据
const loadMapData = async () => {
loading.value = true
error.value = null
try {
const response = await fetch(GEOJSON_URL)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const geoJsonData = await response.json()
// 初始化地图
initMap(geoJsonData)
} catch (err) {
console.error('加载地图数据失败:', err)
error.value = '地图数据加载失败,请检查网络连接'
} finally {
loading.value = false
}
}
// 初始化地图
const initMap = (geoJsonData) => {
if (!mapContainer.value) return
try {
// 清除旧地图实例
if (mapInstance) {
mapInstance.remove()
}
// 创建地图实例
mapInstance = new window.L.Map(mapContainer.value, {
center: [29.563, 106.551], // 重庆中心坐标
zoom: 8,
minZoom: 7,
maxZoom: 18,
zoomControl: false,
attributionControl: false
})
// 添加瓦片图层
const tileLayer = new window.L.TileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
})
mapInstance.addLayer(tileLayer)
// 添加GeoJSON图层
const geoJsonLayer = new window.L.GeoJSON(geoJsonData, {
style: {
fillColor: '#1E3A8A',
weight: 2,
opacity: 0.8,
color: '#3B82F6',
fillOpacity: 0.3
},
onEachFeature: (feature, layer) => {
if (feature.properties && feature.properties.name) {
layer.bindPopup(`<div class="map-popup">
<strong>${feature.properties.name}</strong>
</div>`)
}
}
})
mapInstance.addLayer(geoJsonLayer)
// 调整视图以适应重庆边界
mapInstance.fitBounds(geoJsonLayer.getBounds())
} catch (err) {
console.error('初始化地图失败:', err)
error.value = '地图初始化失败'
}
}
// 组件挂载时加载地图
onMounted(() => {
// 检查Leaflet是否已加载
if (typeof window.L === 'undefined') {
// 动态加载Leaflet CSS和JS
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'
link.integrity = 'sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY='
link.crossOrigin = ''
document.head.appendChild(link)
const script = document.createElement('script')
script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js'
script.integrity = 'sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo='
script.crossOrigin = ''
script.onload = loadMapData
document.head.appendChild(script)
} else {
loadMapData()
}
})
// 组件卸载时清理资源
onUnmounted(() => {
if (mapInstance) {
mapInstance.remove()
mapInstance = null
}
})
</script>
<style lang="scss" scoped>
.chongqing-map-container {
width: 100%;
height: 100%;
position: relative;
}
.map-container {
width: 100%;
height: 100%;
background: #0f1c2e;
}
.loading-overlay,
.error-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.7);
z-index: 1000;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #3B82F6;
border-top: 4px solid transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 10px;
}
.loading-text {
color: #fff;
font-size: 14px;
}
.error-text {
color: #ff6b6b;
font-size: 14px;
margin-bottom: 10px;
}
.retry-btn {
background: #3B82F6;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
&:hover {
background: #2563EB;
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
// Leaflet地图样式覆盖
:deep(.leaflet-container) {
background: #0f1c2e !important;
.leaflet-popup-content-wrapper {
background: rgba(64, 169, 255, 0.9);
border-radius: 4px;
.map-popup {
color: #fff;
font-size: 12px;
}
}
.leaflet-popup-tip {
background: rgba(64, 169, 255, 0.9);
}
}
</style>