原理
在高德地图中使用Vue组件进行自定义Marker、InfoWindow
new AMap.Marker(opts: MarkerOptions)
new AMap.InfoWindow(opts: InfoOptions)
属性 | 描述 |
---|---|
opts.content 类型:(string | HTMLElement) | 点标记显示内容。可以是HTML要素字符串或者HTML DOM对象。content有效时,icon属性将被覆盖。 |
查看文档可以知道 content
的属性可以接收HTMLElement
元素,我们可以通过创建一个HTMLElement
元素,然后将vue组件挂载到这个元素上。
代码示例
- vue3
- ts
- amap-jsapi-loader
CreateHTML.ts
创建元素
使用createApp
创建vue实例,传入组件
返回元素、vue实例(这个实例返回很重要)
/**
* 创建vue元素
*/
export const createHTML = (comp: Component, props?: Record<string, unknown>) => {
const element = document.createElement('div')
const app = createApp(comp, props)
app.mount(element)
return {
element, app
}
}
vue组件
<script setup lang="ts">
defineOptions({
name: 'Marker'
})
const props = defineProps<{
name: string
}>()
</script>
<template>
<h2>{{ props.name }}</h2>
</template>
<style scoped>
h2 {
background: #115c5c;
padding: 5px 10px;
border-radius: 5px;
}
</style>
创建自定义Marker
拿Marker做个示例 InfoWindow同理
// 创建vue元素
const {app,element} = createHTML(MyComp,{
name: '这是一个自定义的Marker',
})
// 创建覆盖物
const marker = new AMap.Marker({
content: element,
// ...otherConf
})
// 添加到地图
map.add(marker)
这样就创建了一个自定义Marker。我们也可以在vue调试工具中看到这个App实例。
这样本来是没什么问题的,但是……
当我们将marker销毁的时候App实例仍然存在,所以当我们对marker(InfoWindow)进行移除的同时,需要把App的实例也进行销毁。
// 移除标点
marker.remove()
// 销毁app
app.unmount()
扩展
使用pinia 或者组件库
由于我们是创建了一个新的vue实例,如果我们要在组件内使用pinia、或者其他组件库、插件,我们需要再写一遍配置
修改创建HTML方法
/**
* 创建vue元素
*/
export const createHTML = (comp: Component, props?: Record<string, unknown>) => {
const element = document.createElement('div')
const app = createApp(comp, props)
/** 引入pinia 或者其他配置**/
// 引入相同的pinia 可以与其他实例通过pinia进行通信
app.use(pinia)
/** 引入pinia **/
app.mount(element)
return {
element, app
}
}
新的问题
问题1
由于组件动态生成,生成后异步获取数据,元素依旧可能变化,最后生成的元素高度、宽度可能不定,导致Marker、InfoWindow生成的位置不正确。
不完全解决办法
- 固定元素宽高
- 不在组件内异步获取数据,在组件外获取数据后再传入组件,生成Marker