mapbox的Popup与Vue框架融合使用

主要用于mapbox GL的Popup,Marker 如何与Vue前端框架融合,把popup里面的DOM抽离成vue组件,避免在js中大量拼接DOM写样式绑方法。

创建marker,popup

地图上创建marker时,可以使用dom元素.默认是一个浅蓝色、水滴状的SVG标记。

创建popup时,使用setDOMContent方法将弹窗内容设置为以 DOM 节点形式提供的元素。

1
2
3
4
5
6
7
8
9
10
let el =document.createElement("div");
//创建marker
var marker = new mapboxgl.Marker(el)
.setLngLat(e.lngLat)
.addTo(map);
//创建popup
var popup = new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setDOMContent(el)
.addTo(map);

vue组件中取dom

vue官网上有实例的对象 vm.$el ,可以取到Vue 实例使用的根 DOM 元素。

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue';
var Comp = Vue.extend({
props: ['msg'],
template: '<div>{{ msg }}</div>'
})
//只用于 new 创建的实例时传递 props.
var vm = new Comp({
propsData: {
msg: 'hello'
}
})
let dom =vm.$el;

上面的例子中可以看到如何取到了我们想要的dom节点。

实例使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import Vue from 'vue';
import * as components from './src';
import store from '@/store'


let currentPopup;
let instance;
let Template;
const popovers = [];

const getPopover = function (_str) {
Template = Vue.extend(components[_str]);
};

// 默认回调
const defaultCallback = action => {
if (currentPopup) {
const callback = currentPopup.callback;
if (typeof callback === 'function') {
callback(action);
} else {
closePopover();
}
}
};

// 创建实例
const initInstance = (data) => {
instance = new Template({
propsData: data,//可以是方法,对象
store: store,//必须引用一下,不能使用vuex
el: document.createElement('div'),
});
instance.callback = defaultCallback;
};

/**
* @description: 获取组件的dom
* @param {type} 组件名
* @return:
*/
const getPopoverElement = (type, options) => {
if (!type) return;
getPopover(type);
initInstance(options);
instance.action = '';
if (popovers.length > 0) {
const _options = options;
if (_options.callback === undefined) {
instance.callback = defaultCallback;
}

Object.keys(_options).forEach(prop => {
if (_options[prop]) {
instance[prop] = _options[prop];
}
});

document.body.appendChild(instance.$el);
Vue.nextTick(() => {
instance.visible = true;
});
}
return instance.$el;
};

/**
* @description: 打开弹窗
* @param {type}
* @return:
*/
const showPopover = function (type, map, options = {}) {
if (options.closeLast) {
closePopover();
}

if (!options.coordinates || !options.coordinates[0] || !options.coordinates[1]) {
console.warn('无空间信息!');
return false;
}

const contentHtml = getPopoverElement(type, options);
const popover = new mapboxgl.Popup(Object.assign({}, {
closeButton: true
}, options));
const coords = options.coordinates;
popover.setLngLat(coords)
.setDOMContent(contentHtml)
.addTo(map);

currentPopup = popover;
popovers.push(currentPopup);
//将弹窗位置设置为map中心
if (options.autoCenter) {
map.animateTo({
center: coords
});
}
};

/**
* @description: 关闭弹窗
* @param {type}
* @return:
*/
function closePopover() {
if (currentPopup) {
currentPopup.remove();
currentPopup = null;
instance.$destroy();
}
}

export {
showPopover, closePopover,getPopoverElement
};
赞赏是最好的鼓励!
0%