高德地图 自定义infoWindow信息窗体,引入vue组件实现

1,764 阅读2分钟

技术栈 Vue3+vite+Element-Plus

image.png

项目中做气象地图功能,遇到需要在高德地图中弹出信息窗体。实现信息窗动态传入参数,渲染echarts,同时与外部交互采用emit事件。

官方APPI提供自定义信息窗,只需开启isCustom: true,同时content传入HTML代码片段。但信息窗结构复杂,最好的方式是能像写vue组件一样,遂进行了多方搜寻。

参考大佬这篇文章:juejin.cn/post/720773…,思路就是创建div,再把vue组件挂载到div上。实现思路大概一致,大佬采用的是pinia进行通信,我采用h函数传递props和emit,进行组件通信:

  1. 创建一个新的div元素
  2. 引入信息窗vue组件,利用h函数创建组件节点,绑定参数和事件
  3. createApp新建一个vue实例
  4. 将vue实例挂载到div元素上,同时注册pinia(项目中切换主题采用)、plugins(项目中组件插件)
  5. 创建信息窗体,使用创建的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)
  })