技术栈 Vue3+vite+Element-Plus
项目中做气象地图功能,遇到需要在高德地图中弹出信息窗体。实现信息窗动态传入参数,渲染echarts,同时与外部交互采用emit事件。
官方APPI提供自定义信息窗,只需开启isCustom: true,同时content传入HTML代码片段。但信息窗结构复杂,最好的方式是能像写vue组件一样,遂进行了多方搜寻。
参考大佬这篇文章:juejin.cn/post/720773…,思路就是创建div,再把vue组件挂载到div上。实现思路大概一致,大佬采用的是pinia进行通信,我采用h函数传递props和emit,进行组件通信:
- 创建一个新的div元素
- 引入信息窗vue组件,利用
h函数创建组件节点,绑定参数和事件 createApp新建一个vue实例- 将vue实例挂载到div元素上,同时注册
pinia(项目中切换主题采用)、plugins(项目中组件插件) - 创建信息窗体,使用创建的div元素
// 创建一个自定义内容的 infowindow 实例
const createInfoWindow = val => {
// 获取当前城市标记点坐标
const lnglat = new mapProps.AMap.LngLat(val.x, val.y)
// 创建窗口div
const element = document.createElement('div')
// 定义vue组件 传入参数
const searchFrom = {
adcode: val.adcode,
name: val.NAME_CHN,
searchTime: props.modelValue.searchTime,
time: props.modelValue.time,
layer: props.modelValue.layer
}
// 创建组件节点VNode 绑定参数 和 事件 相当于 <InfoWindow :searchFrom="searchFrom" @Test="moreInfo"/>
const _InfoWindow = h(InfoWindow, {
searchFrom,
onTest: moreInfo
})
// 将InfoWindow组件挂载到div 同时挂载整个项目的组件插件和pinia 否则不能使用element和公共组件
const app = createApp(_InfoWindow)
app.use(pinia).use(plugins).mount(element)
// 创建信息窗
mapProps.infoWindow = new mapProps.AMap.InfoWindow({
isCustom: true, // 是否自定义窗体
autoMove: true, // 是否自动调整窗体到视野内
position: lnglat, // 基点位置
offset: new mapProps.AMap.Pixel(0, -10),
content: element
})
// 打开
mapProps.infoWindow.open(map)
}
这样,就可以自定义编写vue信息窗体组件,正常接收props参数和传递emit事件即可。
Tip:echarts渲染还出现一点小问题,因为项目里对echarts做了很好的Hooks封装,主题切换、监听侧边栏、显示隐藏等的自适应宽度,但是发现采用这种方式实现的弹窗组件,内部在document.getElementById(id)获取dom的时候,找不到,遂采用ref从形式:
nextTick(() => {
// 因为此弹窗是独立挂载 导致document.getElementById找不到dom 而且直接使用项目的echart组件和hooks/echarts报错 还未解决 所以引用原生echarts
dataProps.chart = echarts.init(curveRef.value, appStore.theme)
dataProps.chart.setOption(dataOptions, true)
})