- Before
当查看天地图 中关于信息弹框的案例时,发现其实现方法是插入一 html 片段。若需要在弹框中实现较为复杂的展示或交互的时候,需要通过 内联事件 或者 操作JS 的方法实现。在项目开发中,我们可以借助项目框架自带的响应式组件处理。
- 效果
- 思路:通过 Vue.extend 创建一独立组件,并将实例节点挂载到天地图弹窗
若对 Vue.extend 加 $mount() 独立组件挂载的方式不熟悉,可先熟悉:
这里的项目框架是 vue2 + vue-cli3,为了使效果更加突出,这里在弹框中引入了 ECharts
代码尽可能体现的实现思路,具体业务可在此基础上拓展
可将此代码粘贴至本地运行
详细说明在代码注释中体现
主要实现代码(直接在 app 组件里面写了)
js
<template>
<!-- 天地图 -->
<div id="app">
<div id="map_box" class="mapbox">
</div>
</div>
</template>
<script>
import Vue from 'vue';
import iconPhone from "./assets/phone.svg";
import chartPop from "./components/chartPop.vue"; //引入组件实例
export default {
name: "App",
data() {
return {
map:null
};
},
mounted() {
setTimeout(() => {
this.init();
}, 200);
},
methods: {
init() {
// 初始化一天地图
this.map = new T.Map("map_box", {
// projection: "EPSG:4326",
center: new T.LngLat(116.36783, 39.90579),
zoom: 14,
minZoom: 8,
maxZoom: 18,
});
// 在天地图中插入一个坐标点
let point = {
type: 1,
LngLat: { lng: 116.36783, lat: 39.90579 },
title: "天地图测试一下11111111111111111",
}
// 添加图片标注点
//创建图片对象
let icon = new T.Icon({
iconUrl: iconPhone,
iconSize: new T.Point(41, 50),
iconAnchor: new T.Point(20, 50), //图标偏移,对齐
});
let { lng, lat } = point.LngLat;
//向地图上添加自定义标注
let marker = new T.Marker(new T.LngLat(lng, lat), {
icon: icon, // 自定义图标
});
this.map.addOverLay(marker);
// 在标注上添加文字标注
let latlng = new T.LngLat(lng, lat);
let label = new T.Label({
text: point.title,
position: latlng,
});
label.setBackgroundColor("rgba(0,0,0,0.5)");
label.setFontColor("#fff");
this.$nextTick(() => {
label.setOffset(new T.Point(-label._labelWidth / 2 - 9, 15)); //这段代码是为了让文字在图标的中间位置
});
//创建地图文本对象
this.map.addOverLay(label);
// 信息窗口
let chartPopExtend = Vue.extend(chartPop) // 创建一独立组件
let devicePopEl = new chartPopExtend({
data:{
close:this.infoCallBack //关闭弹框的回调,这里我通过 data 里数据形式将函数声明传入
},
store:this.$store //注意通过 extend 创建独立组件的时候 store 需要传入,不然直接拿不到,若用到 route 或其他拿不到的数据,可以参考
})
let vm = devicePopEl.$mount('') // 此处不直接挂载 VM 是组件实例
// 这里的 vm.$el 实际上就是 templete 的根元素标签
let infoWin = new T.InfoWindow(vm.$el,{ maxHeight:400,minWidth:500,closeButton:false,autoPan:true });
infoWin.addEventListener('open',()=>{ //当弹窗打开,调用组件的 open 函数
vm.open()
})
marker.addEventListener("click", () => {
marker.openInfoWindow(infoWin);
});
this.marker = marker
},
infoCallBack(){
this.marker.closeInfoWindow()
}
},
};
</script>
<style lang="less">
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
* {
box-sizing: border-box;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* text-align: center; */
color: #2c3e50;
/* margin-top: 60px; */
padding: 0;
margin: 0;
width: 100%;
height: 100%;
position: relative;
box-sizing: border-box;
}
.mapbox {
width: 1200px;
height: 800px;
border: 1px solid #000;
margin: 0 auto;
}
</style>
弹框组件代码:
js
<template>
<div class="box">
<div class="main" id="main"></div>
<div class="btn">
<button @click="close">close</button>
</div>
</div>
</template>
<script>
import * as echarts from "echarts";
export default {
data() {
return {};
},
created() {},
computed: {},
methods: {
open() {
var chartDom = document.getElementById("main");
var myChart = echarts.init(chartDom);
var option;
option = {
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
yAxis: {
type: "value",
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: "bar",
},
],
};
option && myChart.setOption(option);
},
close() {
this.infoCallBack(); // 这里调用外层传入的函数声明,关闭弹框
},
},
};
</script>
<style lang="less" scoped>
.box {
width: 500px;
height: 400px;
}
.main {
width: 100%;
height: 350px;
border: 1px solid #000;
}
.btn {
height: 40px;
line-height: 40px;
text-align: center;
}
</style>
- 总结
在弹框组件里面,采用vue组件的形式,使弹框里面的功能实现分离,大大提高了拓展性,由于组件的响应式特征,我们对于弹框内容的自定义性也更好把握,最主要的是,代码写起来方便了。