官网demo地址:
External map
这篇展示了外部窗口打开地图视图。
首先先初始化地图。
创建了一个UnusableMask类继承Control用来做主页面地图放进小窗口后的遮罩层,设置了自定义属性hidden来控制遮罩层的显隐。
initMap() {
class UnusableMask extends Control {
constructor() {
super({
element: document.createElement("div"),
});
this.element.setAttribute("hidden", "hidden");
this.element.className = "ol-mask";
this.element.innerHTML = "<div>地图不可用</div>";
}
}
this.map = new Map({
target: this.$refs.localMapTarget,
controls: defaultControls().extend([
new FullScreen(),
new UnusableMask(),
]),
layers: [
new TileLayer({
source: new StadiaMaps({
layer: "stamen_watercolor",
}),
}),
],
view: new View({
center: fromLonLat([37.41, 8.82]),
zoom: 4,
}),
});
},
点击按钮时会触发openOutMap函数
使用window.open打开了一个html页面,使用window.open的参数对小窗窗口做一些设置。
openOutMap() {
this.$refs.btn.disabled = true;
this.mapWindow = window.open(
"resources/external-map-map.html",
"MapWindow",
"toolbar=0,location=0,menubar=0,width=800,height=600,top=130"
);
}
这里的external-map-map.html页面我是从openlayers源码中复制出来放到了public下。文件中需要引入一下样式文件。
external-map-map.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Map</title>
<link rel="stylesheet" type="text/css" href="./ol.css">
<style>
body {
margin: 0;
}
.map {
height: 100vh;
width: 100vw;
}
.map.unusable .ol-mask {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
background-color: rgba(0, 0, 0, .7);
color: white;
font: bold 3rem 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.map.unusable .ol-control {
display: none;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
</body>
</html>
openlayers源码下载地址:
GitHub - openlayers/openlayers: OpenLayers
打开external-map-map.html页面之后需要监听一下DOMContentLoaded事件,使用setTarget把小窗口的map容器绑定到map实例上。
小窗关闭的时候需要重新加载一下大地图。
//当初始的HTML文档被完全加载和解析完成后触发,不必等待样式表、图像和子框架的完全加载。
this.mapWindow.addEventListener("DOMContentLoaded", () => {
const externalMapTarget = this.mapWindow.document.getElementById("map");
this.$refs.localMapTarget.style.height = "0px";
this.map.setTarget(externalMapTarget);
if (timeoutKey) {
timeoutKey = clearTimeout(timeoutKey);
}
// 当用户离开当前页面时触发,例如关闭标签页、导航到其他页面或重新加载页面
this.mapWindow.addEventListener("pagehide", () => {
//重新加载大地图
this.resetMapTarget();
//关闭外部窗口
this.closeMapWindow();
});
this.updateOverlay();
});
写一个延时器,如果点击之后小窗口没有加载出来就显示异常文字提醒。
//处理异常情况,点击之后没有打开外部窗口
let timeoutKey = setTimeout(() => {
this.closeMapWindow();
this.resetMapTarget();
blockerNotice.removeAttribute("hidden");
timeoutKey = undefined;
}, 3000);
完整代码:
<template>
<div class="box">
<h1>External map</h1>
<div id="map" ref="localMapTarget"></div>
<input
id="external-map-button"
type="button"
ref="btn"
@click="openOutMap"
value="打开外部窗口"
/>
<span id="blocker-notice" hidden
>无法在外部窗口打开地图。如果您正在使用弹出窗口或广告拦截器,您可能需要禁用它。</span
>
</div>
</template>
<script>
import Map from "ol/Map.js";
import OSM from "ol/source/OSM.js";
import TileLayer from "ol/layer/Tile.js";
import View from "ol/View.js";
import StadiaMaps from "ol/source/StadiaMaps.js";
import {
Control,
FullScreen,
defaults as defaultControls,
} from "ol/control.js";
import { fromLonLat } from "ol/proj.js";
export default {
name: "",
components: {},
data() {
return {
map: null,
mapWindow: "",
};
},
computed: {},
created() {},
mounted() {
this.initMap()
// 当用户离开当前页面时触发,例如关闭标签页、导航到其他页面或重新加载页面
window.addEventListener("pagehide", this.closeMapWindow);
//当页面的可见状态发生变化时触发,例如用户切换到其他标签页或最小化浏览器。
window.addEventListener("visibilitychange", this.updateOverlay);
},
methods: {
initMap() {
class UnusableMask extends Control {
constructor() {
super({
element: document.createElement("div"),
});
this.element.setAttribute("hidden", "hidden");
this.element.className = "ol-mask";
this.element.innerHTML = "<div>地图不可用</div>";
}
}
this.map = new Map({
target: this.$refs.localMapTarget,
controls: defaultControls().extend([
new FullScreen(),
new UnusableMask(),
]),
layers: [
new TileLayer({
source: new StadiaMaps({
layer: "stamen_watercolor",
}),
}),
],
view: new View({
center: fromLonLat([37.41, 8.82]),
zoom: 4,
}),
});
},
//关闭小窗时触发
closeMapWindow() {
if (this.mapWindow) {
this.mapWindow.close();
this.mapWindow = undefined;
}
},
resetMapTarget() {
this.$refs.localMapTarget.style.height = "";
this.map.setTarget(this.$refs.localMapTarget);
this.$refs.btn.disabled = false;
},
updateOverlay() {
if (!this.mapWindow) {
return;
}
const externalMapTarget = this.mapWindow.document.getElementById("map");
if (!externalMapTarget) {
return;
}
if (document.visibilityState === "visible") {
// 显示控件并启用键盘输入
externalMapTarget.classList.remove("unusable");
externalMapTarget.setAttribute("tabindex", "0");
externalMapTarget.focus();
} else {
//隐藏所有控件并禁用键盘输入
externalMapTarget.removeAttribute("tabindex");
externalMapTarget.classList.add("unusable");
}
},
openOutMap() {
const blockerNotice = document.getElementById("blocker-notice");
blockerNotice.setAttribute("hidden", "hidden");
this.$refs.btn.disabled = true;
//处理异常情况,点击之后没有打开外部窗口
let timeoutKey = setTimeout(() => {
this.closeMapWindow();
this.resetMapTarget();
blockerNotice.removeAttribute("hidden");
timeoutKey = undefined;
}, 3000);
// return
this.mapWindow = window.open(
"resources/external-map-map.html",
"MapWindow",
"toolbar=0,location=0,menubar=0,width=800,height=600,top=130"
);
//当初始的HTML文档被完全加载和解析完成后触发,不必等待样式表、图像和子框架的完全加载。
this.mapWindow.addEventListener("DOMContentLoaded", () => {
const externalMapTarget = this.mapWindow.document.getElementById("map");
this.$refs.localMapTarget.style.height = "0px";
this.map.setTarget(externalMapTarget);
if (timeoutKey) {
timeoutKey = clearTimeout(timeoutKey);
}
// 当用户离开当前页面时触发,例如关闭标签页、导航到其他页面或重新加载页面
this.mapWindow.addEventListener("pagehide", () => {
//重新加载大地图
this.resetMapTarget();
//关闭外部窗口
this.closeMapWindow();
});
this.updateOverlay();
});
},
},
};
</script>
<style lang="scss" scoped>
#map {
width: 100%;
height: 500px;
}
.box {
height: 100%;
}
::v-deep #map.unusable .ol-mask {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
background-color: rgba(0, 0, 0, 0.7);
color: white;
font: bold 3rem "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
::v-deep #map.unusable .ol-control {
display: none;
}
</style>