leaflet在VUE中使用自定义popup弹框

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>

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值