高德地图自定义弹窗内容

需求

使用vue2.x来实现高德地图自定义弹窗内容,可以通过一个按钮来切换不同的样式风格,即改变弹窗内容样式。

分析

高德地图官网为开发者提供了自定义弹窗内容的例子,见这里。官方提供的方式是Dom操作,即createElement、appendChild等方式。我们选择用vue,用vue的方式来实现Dom操作。vue的全局API中第一个是Vue.extend,这个是用来实现一个vue的子类构造器,其实可以看做是一个vue模板对象构造器,其实例化对象类似于Dom中的DocumentFragment接口

由于Vue.extend可以生成一个vue子类构造器,从而可以利用vue的响应式特性和组件化思想,来实现弹窗的内容。弹窗里的内容就是一个vue子类实例。

实现

1 PopupWindow.vue

这里我们定制弹窗里的内容,利用vue单文件组件的写法,可以快速实现一个弹窗模板并实现数据响应绑定。我们甚至可以在里面使用自定义的组件chart。这里我们只列出template的内容:

<template>
  <div class="info-win-container">
    <div class="header-container">
      <div class="title-container">{{deviceAttrInfo.name.value}}</div>
      <div class="status-btn-container">在线</div>
      <i class="el-icon-close" :data-feature-id="deviceAttrInfo.sn.value" @click="closeInfoWindow"></i>
    </div>
    <div class="content-container">
      <el-row>
        <el-col :span="12" v-if="deviceAttrInfo.sn.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">序列号:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.sn.value}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.model.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">型号:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.model.value}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.manufacturer.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">生产厂商:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.manufacturer.value || ''}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.deviceCategory.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">所属类别:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.deviceCategory.value || ''}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.trade.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">所属行业:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.trade.value || ''}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.description.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">设备描述:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.description.value || ''}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.uploadData.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">上报数据:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.uploadData.value||''}}</div>
          </div>
        </el-col>
        <el-col :span="12" v-if="deviceAttrInfo.uploadTime.isShow">
          <div class="content-item-container" :style="itemStyleAjust">
            <div class="item-label">上报时间:</div>
            <div class="item-value" :style="valueStyleAjust">{{deviceAttrInfo.uploadTime.value||''}}</div>
          </div>
        </el-col>
        <el-col :span="24" v-if="controlModelList.includes(deviceAttrInfo.model.value)">
          <div class="item-controller-container" :style="itemStyleAjust">
            <div class="item-label">开关控制:</div>
            <div class="item-value" :style="valueStyleAjust">
              <el-switch v-model="isOpen" size="mini" active-text="" inactive-text=""></el-switch>
            </div>
          </div>
        </el-col>
      </el-row>
      <div class="chart-container" v-if="deviceAttrInfo.model.value === 'demo_video' || deviceAttrInfo.model.value === 'demo_tmp'">
        <img src="/static/assets/map/video_img.png" v-if="deviceAttrInfo.model.value === 'demo_video'" />
        <!--自定义组件-->
        <chart
          class="chart"
          :option="lineChartOption"
          :data="lineChartData"
          v-if="deviceAttrInfo.model.value === 'demo_tmp'"
        ></chart>
      </div>
    </div>
  </div>
</template>

关于里面涉及的数据,由于比较多,就不贴代码了。

2 map.vue

这里是地图组件,可以在这里处理弹窗,我们地图选用的是高德地图,所以调用高德地图弹窗的API,即代码摘录如下:

//初始化地图弹窗实例,采用自定义窗体
initInfoWindow() {
      this.infoWindow = new AMap.InfoWindow({
        isCustom: true,//自定义窗体
        offset: new AMap.Pixel(0, -40)
      })
    },
//点击地图标记物弹窗
handleFeatureClick(e) {
      const feature = e.target
      const featureList = feature.getMap().getAllOverlays('marker')
      const activeFeature = featureList.find(item => item.active === true)
      if (activeFeature) {
        activeFeature.setAnimation('AMAP_ANIMATION_NONE')
        activeFeature.active = false
      }
      feature.setAnimation('AMAP_ANIMATION_BOUNCE')
      feature.active = true
      const content = this.initInfoWindowContent(e)
      this.infoWindow.setContent(content)
      this.infoWindow.open(this.map, e.target.location)
    },

高德地图弹窗中的内容是以字符串或者dom对象的形式传入,我们这里采用dom对象方式,那如何将上面的PopupWindow组件转化为dom对象呢?这就要靠Vue.extend的帮助了。代码如下:

createInfoWindowComponent(content) {
      const InfoWindow = Vue.extend(PopupWindow)
      return new InfoWindow()
    },
initInfoWindowContent(e) {
      const { sn, name, model } = e.target
      const { manufacturer, deviceCategoryCode, tradeCode, description } = GLOBAL.deviceModelList.find(deviceModelObj => deviceModelObj.deviceModel === model)
      const selectedCategory = this.categoryOpts.find(categoryObj => categoryObj.code === deviceCategoryCode)
      const deviceCategory = selectedCategory ? selectedCategory.name : ''
      const selectedTrade = this.tradeOpts.find(tradeObj => tradeObj.code === tradeCode)
      const trade = selectedTrade ? selectedTrade.name : ''
      const deviceInfo = {
        sn: {
          value: sn,
          isShow: true
        }, name: {
          value: name,
          isShow: true
        }, model: {
          value: model,
          isShow: true
        }, manufacturer: {
          value: manufacturer,
          isShow: true
        }, deviceCategory: {
          value: deviceCategory,
          isShow: true
        }, trade: {
          value: trade,
          isShow: true
        }, description: {
          value: description,
          isShow: true
        }, uploadData: {
          value: '',
          isShow: true
        }, uploadTime: {
          value: '',
          isShow: true
        }}
      const controlPopInfo = this.$store.state.map.popupInfo
      for (const key of Object.keys(deviceInfo)) {
        deviceInfo[key].isShow = controlPopInfo[key].isShow
      }
      const infoWinCom = this.createInfoWindowComponent()
      infoWinCom.deviceAttrInfo = Object.assign({}, infoWinCom.deviceAttrInfo, deviceInfo)
      infoWinCom.map = this.map
      infoWinCom.itemStyleAjust = this.itemStyleAjust
      infoWinCom.valueStyleAjust = this.valueStyleAjust
      return infoWinCom.$mount().$el
    },

我们每次弹窗显示时,借助Vue.extend()生成一个文档外的片段(DocumentFragment),我们不挂载在任何dom元素上,即 $mount(),这个时候dom对象就已经存在一个轻量版的文档中了,只是没有在正式的文档中,我们也不需要它存在正式文档中,这样它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。然后我们通过 $el 属性即可取出dom元素。

其实在取出dom元素之前,我们可以对组件对象进行一系列的逻辑操作,比如修改数据,调整样式等。这样就给我们提供了当即修改弹窗内容的能力。我们可以调整弹窗内容,也可以调整样式。这个中间的操作可以通过js来实时实现。那自然就可以通过一个按钮,点击按钮执行相应的js操作即可。最终实现了弹窗内容的实时变化。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在使用高德地图API和Vue3实现自定义弹窗样式时,可以参考以下步骤: 1. 首先,初始化地图弹窗实例,并设置isCustom为true,表示使用自定义窗体。可以使用AMap.InfoWindow类来创建地图弹窗实例,并设置偏移量等属性。\[1\] 2. 在处理地图标记物点击事件时,可以通过获取点击的标记物对象,设置动画效果,并获取相应的内容。可以使用AMap.InfoWindow的setContent方法设置弹窗内容,然后使用open方法打开弹窗。\[1\] 3. 可以参考高德地图官方提供的demo样式,该demo展示了自定义弹窗样式。可以在官方demo中查看代码和样式,以便参考和使用。\[2\] 4. 高德地图官网还提供了自定义弹窗内容的例子,使用了Dom操作的方式来实现。可以使用Vue的全局API中的Vue.extend方法来创建一个Vue子类构造器,然后通过实例化该构造器来创建一个Vue对象,类似于Dom中的DocumentFragment接口。这样可以使用Vue的方式来实现自定义弹窗的Dom操作。\[3\] 综上所述,你可以使用高德地图API和Vue3来实现自定义弹窗样式。可以参考高德地图官方提供的demo和文档,根据自己的需求进行相应的代码编写和样式设计。 #### 引用[.reference_title] - *1* *3* [高德地图自定义弹窗内容](https://blog.csdn.net/fredricen/article/details/106172766)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [VUE 高德自定义弹窗样式不生效?(AMap.InfoWindow弹窗样式问题)](https://blog.csdn.net/weixin_39921970/article/details/120744647)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值