48.在 Vue 3 中使用 OpenLayers 实现鼠标悬停显示城市名片
在现代前端开发中,Vue 3 和 OpenLayers 是两个强大的工具。Vue 3 提供了简洁高效的前端框架,而 OpenLayers 则在地图应用领域表现优异。本篇文章将详细介绍如何结合 Vue 3 和 OpenLayers,实现一个简单的鼠标悬停地图上的点位,显示城市名片的功能。
实现效果
- 地图加载成功后,显示中国的部分城市点位,如北京、大连和天津。
- 当鼠标移动到某个城市点位时,会弹出一个包含该城市名称、图片和简介的悬浮窗口。
- 鼠标移出点位时,悬浮窗口会自动关闭。
实现步骤
1. 项目初始化
在开始前,请确保你的项目已经配置好 Vue 3 环境,并安装了 OpenLayers:
npm install ol
2. Vue 3 和 OpenLayers 的代码实现
以下是完整代码,包括地图初始化、点位加载以及鼠标悬停事件处理:
<!--
* @Author: 彭麒
* @Date: 2024/12/28
* @Email: 1062470959@qq.com
* @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。
-->
<template>
<button class="back-button" @click="goBack">返回</button>
<div class="container">
<div class="w-full flex justify-center flex-wrap">
<div class="font-bold text-[24px]">在Vue3中使用OpenLayers移动鼠标显示城市名片</div>
</div>
<div id="vue-openlayers"></div>
<div id="popup-box" class="ol-popup">
<div id="popup-content"></div>
</div>
</div>
</template>
<script setup>
import {ref, onMounted} from 'vue';
import 'ol/ol.css';
import {Map, View} from 'ol';
import Tile from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import Overlay from 'ol/Overlay';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Style from 'ol/style/Style';
import Icon from 'ol/style/Icon';
import Feature from 'ol/Feature';
import {Point} from 'ol/geom';
import dalianImg from '@/assets/OpenLayers/dalian.png';
import beijingImg from '@/assets/OpenLayers/beijing.png';
import tianjinImg from '@/assets/OpenLayers/tianjin.png';
import maker from '@/assets/OpenLayers/maker.png';
import router from "@/router";
const goBack = () => {
router.push('/OpenLayers');
};
const map = ref(null);
const overlayer = ref(null);
const vsource = new VectorSource();
const citys = [
{
name: '大连',
position: [121.63, 38.90],
desc: '滨城、浪漫之都,辽宁省辖地级市、副省级市。',
imgurl: dalianImg
},
{
name: '北京',
position: [116.40, 39.91],
desc: '中华人民共和国的首都、中国政治、文化中心。',
imgurl: beijingImg
},
{
name: '天津',
position: [117.21, 39.09],
desc: '简称“津”,中华人民共和国省级行政区、直辖市。',
imgurl: tianjinImg
},
];
const createCityPointFeatures = () => {
const features = citys.map((city) => {
const feature = new Feature({
geometry: new Point(city.position),
citydata: city
});
feature.setStyle(createPointStyle());
return feature;
});
vsource.addFeatures(features);
};
const createPointStyle = () => {
return new Style({
image: new Icon({
src: maker,
anchor: [0.5, 0.5],
scale: 1
})
});
};
const setupHoverInteraction = () => {
const box = document.getElementById('popup-box');
const content = document.getElementById('popup-content');
overlayer.value = new Overlay({
element: box,
autoPan: {
animation: {
duration: 250
}
}
});
map.value.addOverlay(overlayer.value);
map.value.on('pointermove', (e) => {
if (e.dragging) return;
const feature = map.value.forEachFeatureAtPixel(e.pixel, (feat) => feat);
if (feature) {
const cityInfo = feature.get('citydata');
content.innerHTML = `<h3>${cityInfo.name}</h3><div><img src="${cityInfo.imgurl}"></div> <p>${cityInfo.desc}</p>`;
overlayer.value.setPosition(e.coordinate);
} else {
overlayer.value.setPosition(undefined);
}
});
};
const initializeMap = () => {
const osmLayer = new Tile({
source: new OSM()
});
const cityLayer = new VectorLayer({
source: vsource
});
map.value = new Map({
target: 'vue-openlayers',
layers: [osmLayer, cityLayer],
view: new View({
center: [116.389, 39.903],
zoom: 6,
projection: 'EPSG:4326'
})
});
setupHoverInteraction();
};
onMounted(() => {
initializeMap();
createCityPointFeatures();
});
</script>
<style scoped>
.container {
width: 840px;
height: 590px;
margin: 50px auto;
border: 1px solid #42B983;
}
#vue-openlayers {
width: 800px;
height: 470px;
margin: 0 auto;
border: 1px solid #42B983;
position: relative;
}
.ol-popup {
position: absolute;
background-color: rgba(255, 0, 0, 0.8);
padding: 5px;
border-radius: 5px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
color: #FFFFFF;
min-width: 200px;
}
.ol-popup:after,
.ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: rgba(255, 0, 0, 0.8);
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
</style>
总结
通过本文的学习,你学会了在 Vue 3 中如何结合 OpenLayers 实现鼠标悬停功能,增加了地图的交互性。如果你有更多的扩展需求,比如点击事件、动态加载点位或自定义图层样式,可以基于这个示例继续开发。
希望这篇文章对你有所帮助!如果有疑问或建议,欢迎评论交流。😊