文章目录
-
- [✅ 解决方案:分批加载 GIS 数据(适用于 Vue 2 + Mapbox)](#✅ 解决方案:分批加载 GIS 数据(适用于 Vue 2 + Mapbox))
-
- [🎯 目标](#🎯 目标)
- [✅ 方法一:【推荐】接口支持分页时 ------ 分页加载(Paging)](#✅ 方法一:【推荐】接口支持分页时 —— 分页加载(Paging))
-
- [✅ 前提:](#✅ 前提:)
- [✅ 实现思路:](#✅ 实现思路:)
- [✅ 示例代码(Vue 2):](#✅ 示例代码(Vue 2):)
- [✅ 方法二:前端模拟分批(适用于无法分页的接口)](#✅ 方法二:前端模拟分批(适用于无法分页的接口))
-
- [✅ 前提:](#✅ 前提:)
- [✅ 思路:](#✅ 思路:)
- [✅ 示例代码片段:](#✅ 示例代码片段:)
- [✅ 方法三:空间分块加载(高级方案,适合海量数据)](#✅ 方法三:空间分块加载(高级方案,适合海量数据))
- [✅ 优化建议](#✅ 优化建议)
- [✅ 总结](#✅ 总结)
在 Vue 2 项目中使用 Mapbox 时,如果需要加载的 GIS 数据量过大 ,一次性请求会导致:
- 页面卡顿
- 网络超时
- 内存溢出
- 用户体验差
因此,需要将数据分批加载(分页或分块加载),实现"懒加载"或"按需加载"。
✅ 解决方案:分批加载 GIS 数据(适用于 Vue 2 + Mapbox)
🎯 目标
将"一次性获取全部数据"改为"先加载一部分,再逐步加载剩余部分",提升性能和用户体验。
✅ 方法一:【推荐】接口支持分页时 ------ 分页加载(Paging)
✅ 前提:
后端接口支持分页参数,如:
js
/api/gis-data?page=1&size=1000
✅ 实现思路:
- 先请求第一页数据并加载到 Mapbox。
- 使用
setTimeout
或Promise
逐步请求后续页。 - 每批加载后更新地图。
✅ 示例代码(Vue 2):
vue
<template>
<div id="map" ref="map" style="width: 100%; height: 600px;"></div>
</template>
<script>
import mapboxgl from 'mapbox-gl';
export default {
data() {
return {
map: null,
currentPage: 1,
pageSize: 1000,
hasMore: true,
sourceId: 'gis-data-source',
};
},
async mounted() {
// 初始化 Mapbox
this.map = new mapboxgl.Map({
container: this.$refs.map,
style: 'mapbox://styles/mapbox/light-v10',
center: [104, 30],
zoom: 4,
});
// 添加数据源(空)
this.map.on('load', () => {
this.map.addSource(this.sourceId, {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [],
},
});
this.map.addLayer({
id: 'gis-data-layer',
type: 'fill',
source: this.sourceId,
paint: {
'fill-color': '#007cbf',
'fill-opacity': 0.5,
},
});
// 开始分批加载数据
this.loadNextBatch();
});
},
methods: {
async loadNextBatch() {
if (!this.hasMore) return;
try {
const res = await this.$http.get('/api/gis-data', {
params: {
page: this.currentPage,
size: this.pageSize,
},
});
const features = res.data.features || [];
if (features.length === 0) {
this.hasMore = false;
console.log('所有数据已加载完成');
return;
}
// 获取当前 source 并追加新数据
const source = this.map.getSource(this.sourceId);
const existingData = source._data || { type: 'FeatureCollection', features: [] };
existingData.features.push(...features);
// 更新数据源(触发地图重绘)
source.setData(existingData);
// 下一页
this.currentPage++;
console.log(`已加载第 ${this.currentPage - 1} 页`);
// 继续加载下一批(可加延迟避免卡顿)
setTimeout(() => {
this.loadNextBatch();
}, 100); // 延迟 100ms,让 UI 有喘息时间
} catch (error) {
console.error('数据加载失败:', error);
this.hasMore = false;
}
},
},
};
</script>
✅ 方法二:前端模拟分批(适用于无法分页的接口)
✅ 前提:
接口只提供一个大文件(如 GeoJSON),但数据量太大。
✅ 思路:
- 一次性请求所有数据(但不立即渲染)。
- 将数据切片(chunk),分批添加到地图。
✅ 示例代码片段:
js
async loadDataInChunks() {
const res = await this.$http.get('/api/all-gis-data.json'); // 大文件
const allFeatures = res.data.features;
const chunkSize = 1000;
let index = 0;
const addNextChunk = () => {
if (index >= allFeatures.length) {
console.log('全部数据已加载');
return;
}
const chunk = allFeatures.slice(index, index + chunkSize);
index += chunkSize;
const source = this.map.getSource(this.sourceId);
const currentData = source._data || { type: 'FeatureCollection', features: [] };
currentData.features.push(...chunk);
source.setData(currentData);
// 继续下一帧加载
requestAnimationFrame(addNextChunk);
};
// 开始加载
addNextChunk();
}
使用
requestAnimationFrame
可避免阻塞 UI。
✅ 方法三:空间分块加载(高级方案,适合海量数据)
使用 Web Workers + 瓦片(Tiles) 或 Mapbox Vector Tiles (MVT):
- 将数据发布为 矢量瓦片(Vector Tiles)
- 使用 GeoServer、Tegola、Tippecanoe 等工具切片
- Mapbox 直接加载
.pbf
瓦片,自动按视图范围加载
js
this.map.addSource('vector-tiles', {
type: 'vector',
url: 'http://localhost:8080/styles/my-style/style.json' // MVT 服务
});
this.map.addLayer({
id: 'gis-layer',
type: 'fill',
source: 'vector-tiles',
'source-layer': 'my-layer',
paint: { 'fill-color': '#f00' }
});
⚡ 这是最高效的方式,适合 10万+ 要素。
✅ 优化建议
优化点 | 建议 |
---|---|
数据格式 | 使用 GeoJSON 或更高效的 MVT |
加载时机 | 用户缩放到一定级别(如 zoom > 10 )再加载 |
内存管理 | 避免重复加载,可缓存已加载区域 |
用户提示 | 显示"正在加载..."进度条 |
✅ 总结
场景 | 推荐方案 |
---|---|
接口支持分页 | ✅ 分页 + setTimeout 逐步加载 |
接口返回大文件 | ✅ 前端切片 + requestAnimationFrame |
数据量极大(>10万) | ✅ 使用 Mapbox Vector Tiles (MVT) |
实时性要求高 | 可结合 WebSocket 流式推送 |
👉 推荐优先使用方法一(分页加载),简单、可控、兼容性好。
欢迎给出更好的优化建议。