一、最终效果 实现功能点击地图上的多边形Feature列表自动滚动到对应位置当前项高亮显示鼠标悬浮 Feature 变为 pointer 核心体验地图 → 列表联动二、前言在 WebGIS 项目中经常会遇到这样一个需求点击地图上的某个要素Feature右侧列表自动滚动并定位到对应数据项这个交互在以下场景非常常见无人机巡检系统 ✈️电子围栏管理 ️设备点位管理系统 GIS 可视化大屏本篇文章带你用Vue3 OpenLayers实现一个完整、丝滑的联动效果。三、核心实现思路整个功能其实就三步1️⃣ Feature 和列表建立索引关系new Feature({ geometry: item.area, listindex: i, name: item.descName, }); 关键点给每个 Feature 绑定 listindex2️⃣ 点击地图获取 Featureconst feature map.value.forEachFeatureAtPixel( e.pixel, (feature) feature ); OpenLayers 核心 API3️⃣ 滚动到对应 DOMconst el document.getElementById(pos i); el el.scrollIntoView({ behavior: smooth, block: center }); 重点比window.location.hash更优雅四、完整代码实现!-- * Author: 彭麒 * Date: 2026/3/19 * Email: 1062470959qq.com * Description: 此源码版权归吉檀迦俐所有可供学习和借鉴或商用。 -- template div classcontainer div classw-full flex justify-center flex-wrap div classfont-bold text-[24px] Vue3Openlayers点击某feature列表滑动定位到相应的点的列表位置 /div /div div classlist div v-for(item, index) in list :keyindex :idpos index stylemargin: 10px 10px 0; el-link :typeitem.show ? primary : info {{ item.descName }} /el-link /div /div div idvue-openlayers/div /div /template script setup import { ref, onMounted } from vue; import ol/ol.css; import { Map, View } from ol; import TileLayer from ol/layer/Tile; import VectorLayer from ol/layer/Vector; import VectorSource from ol/source/Vector; import XYZ from ol/source/XYZ; import Feature from ol/Feature; import { Style, Fill, Stroke } from ol/style; import { Select } from ol/interaction; import GeoJSON from ol/format/GeoJSON; import fData from /assets/map/china.json; const map ref(null); const source new VectorSource({ wrapX: false }); const select ref(null); const list ref([]); const drawfeatures ref([]); const initload () { drawfeatures.value new GeoJSON().readFeatures(fData, { dataProjection: EPSG:4326, featureProjection: EPSG:4326, }); updateList(); showPolygons(); }; // 更新列表 const updateList () { list.value []; drawfeatures.value.forEach((feature, index) { const g feature.getGeometry(); list.value.push({ descName: 围栏 index, show: true, area: g, }); }); }; // 显示多边形 const showPolygons () { const features list.value.map((item, i) { return new Feature({ geometry: item.area, listindex: i, name: item.descName, }); }); source.addFeatures(features); }; // 点击 feature → 滚动列表 const clickFeature () { map.value.on(click, (e) { const feature map.value.forEachFeatureAtPixel( e.pixel, (feature) feature ); // 鼠标样式 map.value.getTargetElement().style.cursor feature ? pointer : auto; if (feature) { const i feature.get(listindex); // 滚动定位推荐替代 hash const el document.getElementById(pos i); el el.scrollIntoView({ behavior: smooth, block: center }); list.value.forEach((item, index) { item.show index ! i; }); } else { list.value.forEach((item) (item.show true)); } }); }; // 初始化地图 const initMap () { const iconStyle new Style({ stroke: new Stroke({ color: red, width: 2, }), fill: new Fill({ color: rgba(255,0,0,0), }), }); const googleLayer new TileLayer({ source: new XYZ({ url: https://www.google.com/maps/vt?lyrsmglenx{x}y{y}z{z}, crossOrigin: anonymous, }), }); const drawLayer new VectorLayer({ source, style: iconStyle, }); map.value new Map({ target: vue-openlayers, layers: [googleLayer, drawLayer], view: new View({ projection: EPSG:4326, center: [110.4116821, 41.7966156], zoom: 3, }), }); clickFeature(); select.value new Select(); map.value.addInteraction(select.value); }; onMounted(() { initMap(); initload(); }); /script style scoped .container { width: 840px; height: 570px; margin: 50px auto; border: 1px solid #42B983; } #vue-openlayers { width: 620px; height: 460px; margin: 0 auto; border: 1px solid #42B983; float: left; } .list { width: 200px; height: 180px; margin: 0 auto; float: left; overflow-y: auto; } /style五、关键优化点面试加分项✅ 1. scrollIntoView 优于 hash❌ 不推荐window.location.hash #pos i;✅ 推荐el.scrollIntoView({ behavior: smooth });✅ 2. 数据驱动 UIitem.show index ! i; Vue 响应式自动更新 UI✅ 3. Feature 绑定业务数据feature.get(listindex) 地图 → 业务数据的桥梁✅ 4. 解耦设计高级可以进一步抽成useMap()useFeatureClick()useListSync() 适合大型项目六、可扩展功能建议你写进简历 你可以继续升级点击列表 → 地图定位反向联动Feature 高亮选中改变样式hover 提示海量数据优化WebGL / 分层加载地图聚合 / 分组展示七、总结本文实现了一个非常实用的 GIS 交互功能✅ 地图点击✅ 列表联动✅ 平滑滚动定位✅ Vue3 响应式驱动 核心一句话总结“通过 Feature 绑定索引实现地图与列表的双向映射”
192.Vue3 + OpenLayers 实战:点击地图 Feature,列表自动滚动定位
一、最终效果 实现功能点击地图上的多边形Feature列表自动滚动到对应位置当前项高亮显示鼠标悬浮 Feature 变为 pointer 核心体验地图 → 列表联动二、前言在 WebGIS 项目中经常会遇到这样一个需求点击地图上的某个要素Feature右侧列表自动滚动并定位到对应数据项这个交互在以下场景非常常见无人机巡检系统 ✈️电子围栏管理 ️设备点位管理系统 GIS 可视化大屏本篇文章带你用Vue3 OpenLayers实现一个完整、丝滑的联动效果。三、核心实现思路整个功能其实就三步1️⃣ Feature 和列表建立索引关系new Feature({ geometry: item.area, listindex: i, name: item.descName, }); 关键点给每个 Feature 绑定 listindex2️⃣ 点击地图获取 Featureconst feature map.value.forEachFeatureAtPixel( e.pixel, (feature) feature ); OpenLayers 核心 API3️⃣ 滚动到对应 DOMconst el document.getElementById(pos i); el el.scrollIntoView({ behavior: smooth, block: center }); 重点比window.location.hash更优雅四、完整代码实现!-- * Author: 彭麒 * Date: 2026/3/19 * Email: 1062470959qq.com * Description: 此源码版权归吉檀迦俐所有可供学习和借鉴或商用。 -- template div classcontainer div classw-full flex justify-center flex-wrap div classfont-bold text-[24px] Vue3Openlayers点击某feature列表滑动定位到相应的点的列表位置 /div /div div classlist div v-for(item, index) in list :keyindex :idpos index stylemargin: 10px 10px 0; el-link :typeitem.show ? primary : info {{ item.descName }} /el-link /div /div div idvue-openlayers/div /div /template script setup import { ref, onMounted } from vue; import ol/ol.css; import { Map, View } from ol; import TileLayer from ol/layer/Tile; import VectorLayer from ol/layer/Vector; import VectorSource from ol/source/Vector; import XYZ from ol/source/XYZ; import Feature from ol/Feature; import { Style, Fill, Stroke } from ol/style; import { Select } from ol/interaction; import GeoJSON from ol/format/GeoJSON; import fData from /assets/map/china.json; const map ref(null); const source new VectorSource({ wrapX: false }); const select ref(null); const list ref([]); const drawfeatures ref([]); const initload () { drawfeatures.value new GeoJSON().readFeatures(fData, { dataProjection: EPSG:4326, featureProjection: EPSG:4326, }); updateList(); showPolygons(); }; // 更新列表 const updateList () { list.value []; drawfeatures.value.forEach((feature, index) { const g feature.getGeometry(); list.value.push({ descName: 围栏 index, show: true, area: g, }); }); }; // 显示多边形 const showPolygons () { const features list.value.map((item, i) { return new Feature({ geometry: item.area, listindex: i, name: item.descName, }); }); source.addFeatures(features); }; // 点击 feature → 滚动列表 const clickFeature () { map.value.on(click, (e) { const feature map.value.forEachFeatureAtPixel( e.pixel, (feature) feature ); // 鼠标样式 map.value.getTargetElement().style.cursor feature ? pointer : auto; if (feature) { const i feature.get(listindex); // 滚动定位推荐替代 hash const el document.getElementById(pos i); el el.scrollIntoView({ behavior: smooth, block: center }); list.value.forEach((item, index) { item.show index ! i; }); } else { list.value.forEach((item) (item.show true)); } }); }; // 初始化地图 const initMap () { const iconStyle new Style({ stroke: new Stroke({ color: red, width: 2, }), fill: new Fill({ color: rgba(255,0,0,0), }), }); const googleLayer new TileLayer({ source: new XYZ({ url: https://www.google.com/maps/vt?lyrsmglenx{x}y{y}z{z}, crossOrigin: anonymous, }), }); const drawLayer new VectorLayer({ source, style: iconStyle, }); map.value new Map({ target: vue-openlayers, layers: [googleLayer, drawLayer], view: new View({ projection: EPSG:4326, center: [110.4116821, 41.7966156], zoom: 3, }), }); clickFeature(); select.value new Select(); map.value.addInteraction(select.value); }; onMounted(() { initMap(); initload(); }); /script style scoped .container { width: 840px; height: 570px; margin: 50px auto; border: 1px solid #42B983; } #vue-openlayers { width: 620px; height: 460px; margin: 0 auto; border: 1px solid #42B983; float: left; } .list { width: 200px; height: 180px; margin: 0 auto; float: left; overflow-y: auto; } /style五、关键优化点面试加分项✅ 1. scrollIntoView 优于 hash❌ 不推荐window.location.hash #pos i;✅ 推荐el.scrollIntoView({ behavior: smooth });✅ 2. 数据驱动 UIitem.show index ! i; Vue 响应式自动更新 UI✅ 3. Feature 绑定业务数据feature.get(listindex) 地图 → 业务数据的桥梁✅ 4. 解耦设计高级可以进一步抽成useMap()useFeatureClick()useListSync() 适合大型项目六、可扩展功能建议你写进简历 你可以继续升级点击列表 → 地图定位反向联动Feature 高亮选中改变样式hover 提示海量数据优化WebGL / 分层加载地图聚合 / 分组展示七、总结本文实现了一个非常实用的 GIS 交互功能✅ 地图点击✅ 列表联动✅ 平滑滚动定位✅ Vue3 响应式驱动 核心一句话总结“通过 Feature 绑定索引实现地图与列表的双向映射”