2022年12月13日新增:贴一个写的比我好的方案,供大家参考:http://t.csdn.cn/fG8WO
问题:
项目中使用了vue框架,其中地图页面用到的是leaflet。需求是需要点击地图上的marker弹出popup框。其中的内容比较复杂,比如视频、echarts等,因为要弹出的内容(视频、echarts等)也是用vue方式写的。因此不适合用html拼接的方式。
解决思路:
1、初始化marker时将vue对象赋值给marker。
2、点击事件可以拿到vue对象。拿到vue中data的数据,更新数据。
4、数据更新完成,等待被弹出的内容的视图更新完成后。将该内容setContent到popup中。
具体实现:
<template>
<div>
<ChartView
ref="foo"
:chartData="chartoption"
/>
</div>
</template>
<script>
// chart的具体内容
import ChartView from "../business/tideStationChartView";
export default {
components: {
ChartView
},
props: {
// 接收map对象
map: {
type: Object,
default: null
},
// 接收marker数据
data: {
type: Array,
default: () => []
}
},
data() {
return {
// 点击的marker对象
selectPoint: { },
// echart配置(后台接口中返回)
chartoption: {},
// 当前聚焦的点(此功能可以忽略)
focusMarker: ``,
};
},
computed: {
},
watch: {
data() {
this.createMarkers({
// marker点数据
data: this.data,
// 自己定义的类别
layertype: `SEA_TIDE`
});
}
},
mounted() {
},
methods: {
// 创建marker的layer
createMarkers(layeropt) {
// 初始化一个layerGroup
let currentLayer = window.L.layerGroup();
currentLayer.layertype = layeropt.layertype;
// 将layer添加到map中
currentLayer.addTo(this.map);
const layerdata = layeropt.data;
this.currentMarkers = [];
layerdata.forEach(d => {
if (d.lttd && d.lgtd) {
const marker = window.L.marker([Number(d.lttd), Number(d.lgtd)], {
icon: window.L.divIcon({
className: `icon-marker`,
html: `<span><svg t='1608433647976' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='2832' width='16' height='16'><path d='M512 512m-442.7 0a442.7 442.7 0 1 0 885.4 0 442.7 442.7 0 1 0-885.4 0Z' fill='#9BBFFD' p-id='2833'></path><path d='M512 512m-263 0a263 263 0 1 0 526 0 263 263 0 1 0-526 0Z' fill='{fillcolor}' p-id='2834'></path></svg></span>`;
}),
title: `${d.stnm || ``}`,
pane: `SEA_TIDE`,
stcd: d.stcd,
lttd: d.lttd,
lgtd: d.lgtd
});
//初始化marker时将vue对象this赋值给marker。
marker.vuecontext = this;
// 赋值marker的具体业务属性
marker.attrdata = d;
// 点击事件
marker.on(`click`, e => {
// marker点击拿到_this为之前赋值的vue对象this
const _this = e.target.vuecontext;
_this.handleClick(e);
});
marker.addTo(currentLayer);
this.currentMarkers.push(marker);
}
});
},
handleClick(e) {
// 请求数据更新弹框内容
this.chartDetail(e.target.attrdata, e, e => {
// 回调函数
const _this = e.target.vuecontext;
// 设置当前选择的marker的数据
_this.selectPoint = e.target.options;
_this.$forceUpdate();
window.L.popup({ maxWidth: 700, maxHeight: 600 })
.setLatLng(e.latlng)
.setContent(_this.$refs.foo.$el.innerHTML)
.openOn(_this.map);
// popup中的内容渲染出来之后再初始化chart
_this.chartoption = Object.assign({}, _this.chartoption);
// 这里设置了chartoption,后面在chart组件中初始化echart即可
});
},
// 获取chart数据
chartDetail(row, e, func) {
const _this = e.target.vuecontext;
// 请求后台数据
_this.$getData.tideForecastList({ stcd: row.stcd }).then(res => {
_this.chartoption = res.data;
// 这里延迟,是因为需要先把上面那个现有的echart初始化完成,才能copy其中的innerHTML
setTimeout(() => {
// 回调
func(e);
}, 200);
});
// 聚焦某一个点
_this.focus(row);
},
// 聚焦某一个点(附加功能,可忽略)
focus(item) {
// 清空本身的dialog
this.currentMarkers.forEach(marker => {
if (item.stcd === marker.options.stcd && item.lttd === marker.options.lttd && item.lgtd === marker.options.lgtd) {
this.isFocus = true;
// 设置中心点
this.map.setView([item.lttd, item.lgtd], 13);
// 模拟点击
if (this.focusMarker) {
this.focusMarker.setLatLng([Number(item.lttd), Number(item.lgtd)]);
} else {
this.focusMarker = window.L.marker([Number(item.lttd), Number(item.lgtd)], {
icon: window.L.divIcon({
className: `icon-marker`,
html: `<span class="pulse red-point"></span>`
})
});
this.focusMarker.addTo(this.map);
setTimeout(() => {
this.map.removeLayer(this.focusMarker);
this.focusMarker = null;
}, 1000);
}
}
});
}
}
};
</script>
<style lang="scss">
.marker-icon {
border-radius: 50%;
font-size: 1rem;
text-align: center;
color: #fff;
background-color: red;
border: 1px solid #666;
}
.red-point{
width: 0.7rem;
height: 0.7rem;
display: block;
border-radius: 50%;
border: 0.1rem solid #ff3939b8;
-webkit-box-shadow: 0rem 0.1rem 0.5rem #ff0000;
box-shadow: 0rem 0.1rem 0.5rem #ff0000;
margin-top: 0.25rem;
}
</style>