前言

  • 如果没有了解过高德地图,请勿看这篇文章,因为我不是从头说起的(2020-07-13)

安装引入

  • 使用高德地图组件前,先在index.html中加入以下代码
<script type="text/javascript"
        src="https://webapi.amap.com/maps?v=1.4.15&key=4365df5e295713cc4d8dcbdcef934a0f"></script>
<script src="https://webapi.amap.com/ui/1.0/main.js" type="text/javascript"></script> 

功能使用

为某个区域添加遮罩(即只显示某个区域的地图)

    // data里定义地图实例
  data() {
   	return {
   		amapInstance:{},
   		...
   	}
  }
  methods: {
    // 地图初始化就不贴了
    ...
    // 为地图加载遮罩,只显示默认区域
    mapLoadMask() {
      // 这里一定要捕获this赋值给一个变量,不然在回调函数中调用this不是你想要的this
      const _this = this
      // https://lbs.amap.com/api/javascript-api/reference/search
      // https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.DistrictSearch
      // https://blog.csdn.net/liujucai/article/details/100070540
      AMap.plugin('AMap.DistrictSearch', function() {
        var districtSearch = new AMap.DistrictSearch({
          // 返回行政区边界坐标等具体信息
          extensions: 'all',
          // 设置查询行政区级别为 区
          //level: 'district',
          // 不返回下级行政区
          subdistrict: 0
        })
        districtSearch.search(_this.defaultPara.adcCode, function(
          status,
          result
        ) {
          if (status === 'complete') {
            // 外多边形坐标数组和内多边形坐标数组
            var outer = [
              new AMap.LngLat(-360, 90, true),
              new AMap.LngLat(-360, -90, true),
              new AMap.LngLat(360, -90, true),
              new AMap.LngLat(360, 90, true)
            ]
            var holes = result.districtList[0].boundaries
            var pathArray = [outer]
            pathArray.push.apply(pathArray, holes)
            var polygon = new AMap.Polygon({
              path: pathArray,
              // 线条颜色,使用16进制颜色代码赋值。默认值为#006600
              strokeColor: 'rgb(122,122,122)',
              // 线条宽度
              strokeWeight: 2,
              // 轮廓线透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9
              strokeOpacity: 0.8,
              // 多边形填充颜色,使用16进制颜色代码赋值,如:#FFAA00
              fillColor: 'rgba(250, 250, 250, 0.9)',
              // 多边形填充透明度,取值范围[0,1],0表示完全透明,1表示不透明。默认为0.9
              fillOpacity: 1,
              // 轮廓线样式,实线:solid,虚线:dashed
              strokeStyle: 'dashed',
              // 勾勒形状轮廓的虚线和间隙的样式,此属性在strokeStyle 为dashed 时有效, 此属性在
              // ie9+浏览器有效 取值:
              // 实线:[0,0,0]
              // 虚线:[10,10] ,[10,10] 表示10个像素的实线和10个像素的空白(如此反复)组成的虚线
              // 点画线:[10,2,10], [10,2,10] 表示10个像素的实线和2个像素的空白 + 10个像素的实
              // 线和10个像素的空白 (如此反复)组成的虚线
              strokeDasharray: [0, 0, 0]
            })
            //polygon.setPath(pathArray)
            _this.amapInstance.add(polygon)
            // _this.amapInstance.setLimitBounds(polygon.getBounds())
            console.log('蒙版绘制polygon完成')
            _this.mapMask = polygon
          } else if (status === 'error') {
            _this.$Message(result, 'error')
          }
          _this.loading = false
        })
      })
    }
  }
  • 官网的例子是这么调用的,有一些博客也是这样
    new AMap.DistrictSearch({
        extensions:'all',
        subdistrict:0
    })
    ...
    ...

然后就会报未定义的错
DistrictSearch不是一个构造函数

  • 如果你要这么用,要么在代码或index.html中单独引用DistrictSearch插件
     <script src="https://webapi.amap.com/maps?v=1.4.15&key=c4f16b4da2e9c9023eac7f81d021bb1b&plugin=AMap.DistrictSearch"></script>
  • 要么先调用AMap.plugin引入DistrictSearch插件
      AMap.plugin('AMap.DistrictSearch')

效果

在这里插入图片描述
https://lbs.amap.com/api/javascript-api/reference/search
https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.DistrictSearch
https://blog.csdn.net/liujucai/article/details/100070540

 
 

自定义信息窗体更完美的方法

一般百度搜到的包括官网例子都是:字符串拼接Html
将拼接好的html赋值给marker的content属性,点击marker时设置infowindow的内容,如下

1.
    var infoWindow = new AMap.InfoWindow({
    	offset: new AMap.Pixel(0, -10)
    });
    for (var i = 0, marker; i < lnglats.length; i++) {
        var marker = new AMap.Marker({
            position: lnglats[i],
            map: map
        });
        marker.content = '<h3>我是第' + (i + 1) + '个XXX</h3>';
        marker.content += '<div>经度:'+lnglats[i][0]+'</div>';
        marker.content += '<div>纬度:'+lnglats[i][1]+'</div>';
        marker.content += '<div><button  class="btn btn-suucess btn-xs">历史轨迹</button>';
        marker.content += '&nbsp;<button class="btn btn-warning btn-xs">实时跟踪&nbsp;</button>';
        marker.content += '&nbsp;<button  class="btn btn-danger btn-xs">设置</button></div>';

        marker.on('click', markerClick);
        marker.emit('click', {target: marker});
    }
    function markerClick(e) {
        infoWindow.setContent(e.target.content);
        infoWindow.open(map, e.target.getPosition());
    }
2.
	let content = [
         '<div class="shipInfoPop">',
         '<div class="head" style="color:#333; font-size:16px; border-bottom: 1px solid #d8d8d8;">',
         ship.title + ' <span style="color:#548CF9;font-size:14px;">详情</span></div>',
         '<ul>',
         '<li>船舶信息</li>',
         '<li>视频监控</li>',
         '<li>天线状态</li>',
         '<li>Modem信息</li>',
         '<li>运动分析</li>',
         '<li>运动轨迹</li>',
         '</ul>',
         '<div class="info">',
         '<p>卫星: '+ ship.satellites +'</p>',
         '<p>时间: '+ ship.dateTime +'</p>',
         '<p>航向: '+ ship.headingAngle +'</p>',
         '<p>航速: '+ ship.speed +'</p>',
         '<p>经度: '+ ship.gpsWVal +'</p>',
         '<p>纬度: '+ ship.gpsJval +'</p>',
         '</div></div>'
        ]; 
...
...

在Vue中咱还这么写,嗯… 看起来很蠢的方法,那咱用的还是vue嘛

  • 既然是Vue,就要利用Vue的特点 – 组件化 + 数据驱动
    接下来就以子组件的形式自定义高德地图的信息窗体
  • 首先建立一个xxx.vue文件,名字自己定义就好,要不要在跟地图组件同一个目录下看你自己了,我这里是infoWindow.vue
    在这里插入图片描述
  • 和写其他vue页面一样,template、script、style,这里就不贴具体代码了
    ps:子组件的props中定义你要绑定的数据,双向绑定可使用value字段
<template>
  <div>

  </div>
</template>

<script>
export default {
  props: {
    deviceInfo: {
      type: Object,
      default: function() {
        return {
          baseInfo: {}
          extend: []
        }
      }
    }
  },
  components: {

  },
  mounted() {

  },
  data() {
    return {

    }
  },
  methods: {

  }
}
</script>

<style lang='scss'>

</style>

  • 在父组件中引用这个子组件
import infowindow from './infoWindow'
export default {
  ...
  components: {
    infowindow
  },
  ...
}
  • 添加到页面中,包裹一层div让它不显示,需要用到ref属性!!
<div style="display:none">
    <infowindow ref="infowindow"
                :deviceInfo="showMarker"
                @close="closeInfoWindow"
                @getprop="getMarkerProp">
    </infowindow>
</div>
  • 初始化信息窗体
    createInfoWindow() {
      // https://blog.csdn.net/qq_39512863/article/details/90483781
      this.mapInfoWindow = new AMap.InfoWindow({
        // 是否自动调整窗体到视野内(当信息窗体超出视野范围时,通过该属性设置是否自动平移地图,使信息窗体完全显示)
        autoMove: true,
        // 是否自定义窗体。设为true时,信息窗体外框及内容完全按照content所设的值添加(默认为false,即在系统默认的信息窗体外框中显示content内容)
        isCustom: false,
        anchor: 'bottom-center',
        // 弹出位置偏移量,可根据图标大小修改
        offset: new AMap.Pixel(0, -10)
        // 控制是否在鼠标点击地图后关闭信息窗体,默认false,鼠标点击地图后不关闭信息窗体
        // closeWhenClickMap: true
      })
      // 这里重点了
      this.mapInfoWindow.setContent(this.$refs.infowindow.$el)
      this.mapInfoWindow.on('close', this.infoWindowClosed)
    },
  • OK,内容有了,接下来就是传数据了,前面我们已经给infoWindow绑定了showMarker变量
    那么在创建一个标记点的时候,这么做
    createMarker(para) {
      // https://lbs.amap.com/api/javascript-api/reference/overlay#marker
      var marker = new AMap.Marker({
        position: new AMap.LngLat(para.lng, para.lat),
        offset: new AMap.Pixel(-10, -10),
        icon: this.getMarkerIcon(para),
        //animation: 'AMAP_ANIMATION_BOUNCE',
        title: para.name,
        // 鼠标点击时marker是否置顶
        topWhenClick: true
      })
      // 创建一个属性,缓存你需要的数据
      marker.data = para
      // 绑定点击事件
      marker.on('click',this.markerClick)
      return marker
    },
  • 标记点被点击的事件处理,e.target就是你点击的Marker,具体可看官网
    这里我们获取到之前缓存在marker实例中的data属性,赋值给 showMarker.baseInfo (你传给子组件的参数)
      // 标记点被点击
    async markerClick(e) {
      console.log('markerClick', e.target)
      this.showMarker.baseInfo = e.target.data
      var extend = await markerApi.queryProps(e.target.data.id)
      this.showMarker.extend = extend ? extend : {}
      this.mapInfoWindow.open(this.amapInstance, e.target.getPosition())
    },
  • 弹出的信息窗体
    在这里插入图片描述
  • 个人认为,这样自定义方便多了,组件里还可以用element-ui的组件,css写的也方便,抛事件也方便,简直完美,何必去拼接html呢
  • 差不多就这么多了,至于你要怎么使用绑定值,抛出哪些事件就看你具体要求了
  • 还是贴上代码吧(2020.06.04),各位新手可以改改用,这个开始是在高德中用的,不过为了兼容leaflet改了一些东西,高德很久没有测试过了
<template>
  <div class="map-infowindow-container">
    <div class="map-infoWindow-header"
         slot="header">
      <div class="map-infoWindow-header-title">
        {{deviceInfo.baseInfo.name}}
      </div>
    </div>
    <div class="map-infoWindow-main">
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag class="device-prop-label"
                  :type="doorState"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.state')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{formmat('state',deviceInfo.baseInfo.state)}}</span>
        </el-col>
      </el-row>
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag class="device-prop-label"
                  :type="lockState"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.lockState')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{formmat('lockState',deviceInfo.baseInfo.lockState)}}</span>
        </el-col>
      </el-row>
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag class="device-prop-label"
                  type="info"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.deptName')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{deviceInfo.baseInfo.deptName}}</span>
        </el-col>
      </el-row>
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag class="device-prop-label"
                  type="info"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.staffName')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{deviceInfo.baseInfo.staffName}}</span>
        </el-col>
      </el-row>
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag type="info"
                  class="device-prop-label"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.location')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{deviceInfo.baseInfo.lng}},{{deviceInfo.baseInfo.lat}}</span>
        </el-col>
      </el-row>
      <el-row class="device-prop">
        <el-col :span="8">
          <el-tag class="device-prop-label"
                  type="info"
                  :effect="tagEffect">
            {{$t('gisMap.map.deviceInfo.desc')}}
          </el-tag>
        </el-col>
        <el-col :span="16">
          <span class="device-prop-value">{{deviceInfo.baseInfo.desc}}</span>
        </el-col>
      </el-row>
      <!-- <el-row class="device-prop"
              type="flex"
              justify="center">
        <el-button class="device-prop-viewextend"
                   type="text"
                   :disabled="!deviceInfo.baseInfo.hasProps">
          {{$t('gisMap.map.viewExtend')}}
          <i class="el-icon-arrow-down" /></el-button>
      </el-row> -->
      <div class="device-extend"
           v-loading="loading.extend">
        <div class="device-extend-succs"
             v-if="showExtend && !isError">
          <el-row class="device-prop"
                  v-for="item in deviceInfo.extend"
                  :key="item.code">
            <el-col :span="8">
              <el-tag class="device-prop-label"
                      type=""
                      :effect="tagEffect">
                {{item.name}}
              </el-tag>
            </el-col>
            <el-col :span="16">
              <span class="device-prop-value">
                {{item.val}} {{item.unit}}
              </span>
            </el-col>
          </el-row>
        </div>
        <span class="device-extend-err"
              v-if="isError">
          {{$t('gisMap.map.getExtendErr')}}
        </span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Map-InfoWindow',
  props: {
    deviceInfo: {
      type: Object,
      default: function() {
        return {
          baseInfo: {
            id: null,
            name: null,
            state: null,
            lockState: null,
            mainType: null,
            subType: null,
            lat: null,
            lng: null,
            desc: null,
            deptName: null,
            staffName: null,
            hasProps: null
          },
          // code
          // name
          // val
          extend: []
        }
      }
    }
  },
  computed: {
    doorState() {
      return this.deviceInfo.baseInfo.state === 0
        ? 'success'
        : this.deviceInfo.baseInfo.state === 1
        ? 'danger'
        : 'warning'
    },

    lockState() {
      return this.deviceInfo.baseInfo.lockState === 0
        ? 'success'
        : this.deviceInfo.baseInfo.lockState === 1
        ? 'danger'
        : 'warning'
    },
    showExtend() {
      return (
        this.deviceInfo.baseInfo &&
        this.deviceInfo.baseInfo.hasProps &&
        this.deviceInfo.extend &&
        this.deviceInfo.extend.length > 0
      )
    }
  },
  data() {
    return {
      tagEffect: 'plain',
      loading: {
        extend: false
      },
      isError: false
    }
  },
  methods: {
    formmat(key, value) {
      switch (key) {
        case 'state':
          return value === 0 ? '关闭' : value === 1 ? '打开' : '未知'
          break
        case 'lockState':
          return value === 0 ? '闭锁' : value === 1 ? '开锁' : '未知'
          break
        default:
          break
      }
    },
    setLoading(name, val) {
      if (this.loading[name] != undefined) {
        this.loading[name] = val
      }
    },
    setError(val) {
      this.isError = val
    }
  }
}
</script>

<style lang="scss">
.map-infowindow-container {
  height: auto;
  width: 230px;
  .map-infoWindow-header {
    height: auto;
    word-wrap: break-word;
    border-bottom: 1px solid lightgray;
    padding: 10px 0px 15px 10px;
    .map-infoWindow-header-title {
      height: auto;
      font-size: 16px;
      color: dimgray;
      font-weight: bold;
    }
  }
  .map-infoWindow-main {
    .device-prop {
      margin-top: 8px;
      .device-prop-label {
        float: right;
      }
      .device-prop-value {
        margin-left: 10px;
        font-size: 12px;
        word-wrap: break-word;
        color: gray;
      }
      .device-prop-viewextend {
        padding: 0 !important;
      }
    }
    .device-extend {
      border-top: 1px;
      padding-top: 5px;
      .device-extend-err {
        color: red;
        font-size: 12px;
        display: flex;
        text-align: center;
        justify-content: center;
      }
    }
  }
}
</style>
  

后语

Logo

前往低代码交流专区

更多推荐