题目的意思是,arcgis for js 4.X自定义气泡,点击地图对象弹出对话框,而不是弹出气泡。对话框是vue页面组成的自定义对话框,不是地图页面的对象。
基本思路:
1)气泡模板(PopupTemplate)的内容类型设为函数
2)该函数向地图页面的父页面发送消息,然后关闭气泡
3)地图页面的父页面接收到消息后,弹出对话框
整个过程,气泡一闪而过,甚至根本无法察觉,就好像点击地图对象,直接弹出了对话框。
在arcgis for js 3.X时代,类似的功能我也搞过,原理为气泡内容是一个iframe,在iframe页面触发对话框弹出,然后关闭气泡。相关文章:
arcgis for js 3.X通用百变气泡解决方案
在arcgis for js 4.X,也可以这么搞。但iframe嵌入的页面(是一个VUE页面)有个身份验证问题,就想采用消息通知的机制,可能更灵活些。
上代码:
1、地图页面
//popupTemplate.content可以是一个函数,有意思:
var popupIt = _getPopup(mapView, function (name) {
//弹出对话框
_emit({
target: "bathPop",
data: {
name: name,
},
});
});
//定义气泡等
var options = {
id: "起一个好记的名字",
url: "地图服务地址",
sublayers: [//4.X的ImageMapLayer,也就是3.X的动态图层ArcGISDynamicMapServiceLayer
{
id: 31,//地图服务某子图层的ID
outFields: ["*"],
popupTemplate: {
title: "{name}",
content: popupIt,//这是上面定义的函数
},
},
],
};
_addLayer(mapView, options);
function _addLayer(mapView, options) {
require(["esri/layers/MapImageLayer"], function (MapImageLayer) {
var layer = new MapImageLayer(options);
mapView.map.add(layer);
});
}
function _emit(json) {
//地图是用iframe嵌入到vue页面的,因此要通知vue
//postMessage只负责发送消息,不传递数据。如果要传递数据,只能自己序列化成字符串,放在第一个参数
window.parent.postMessage(JSON.stringify(json), "*");
}
function _getPopup(mapView, callback) {
return function () {
new Promise(function (resolve) {
var timer1 = setInterval(function () {
//需要获得被点击地图对象的信息
//为了保证能获取到,使用了定时器,直到获取成功才转到下一步,否则循环等待
//应该还有其他更好的途径,但我还不知道
if (!mapView.popup.content.title || mapView.popup.content.title === "") {
return;
}
clearInterval(timer1);//清除定时器
if (callback && typeof callback === "function") {
callback(mapView.popup.content.title);
}
resolve();//转向下一步
}, 200);
}).then(function () {//这就是所谓的下一步
mapView.popup.close();
});
};
}
2、地图页面的父页面
<template>
<page-container navi="map" noFooter="true">
<iframe
ref="mapIframe"
src="地图页面"
class="mapIframe"
frameborder="0"
scrolling="false"
allowfullscreen="true"
/>
</page-container>
<pop></pop>
</template>
<script setup>
import { ref, onMounted, nextTick } from "vue";
const init = () => {
//监听消息
window.addEventListener("message", popIt.bind(this));
function popIt(ev) {
const data = ev.data;
try {
if (data && data.indexOf("{") === 0) {//是json
//弹出对话框
}
} catch (ex) {
console.log(ex);
}
}
};
onMounted(() => {
nextTick(() => {
init();
});
});
</script>
<style scoped>
.mapIframe {
width: 100%;
height: calc(100vh - 50px);
}
</style>