首页 前端知识 vue 借助vue-amap插件对高德地图的简单使用

vue 借助vue-amap插件对高德地图的简单使用

2024-05-26 00:05:42 前端知识 前端哥 281 785 我要收藏

需求:实现点击获取经纬度、定位、对特殊位置标点及自定义信息窗体功能。

高德地图的官网API:概述-地图 JS API 1.4 | 高德地图API

vue-amap的中文文档:组件 | vue-amap

实现: 

1、安装vue-amap插件

npm install vue-amap --save

2、项目引入

在main.js中引入

需要提前申请高德key,步骤附在最后了

// 高德地图配置
import VueAMap from 'vue-amap' // 引入插件
Vue.use(VueAMap) // 使用插件
VueAMap.initAMapApiLoader({ // 初始化插件
  key: '高德申请的key', // 高德key
  plugin: ['AMap.Geocoder', 'AMap.PlaceSearch', 'AMap.Geolocation', 'AMap.CitySearch'], // 插件集合,根据自己的需求添加
  uiVersion: '1.0.11', // 不加会报错,加上吧
  v: '1.4.15' // 默认高德 sdk 版本为 1.4.4
})
// 申请的Web端(JS API)的需要写上下面这段话
window._AMapSecurityConfig = {
  securityJsCode: '高德申请的kedy对应的安全密钥' // 高德Web端安全密钥
}

3、新建一个Map.vue文件

这里直接放我封装的组件

<template>
  <div class="Map">
    <!-- 地图组件 -->
    <el-amap
      vid="amapContainer"
      class="amapClass"
      :zoom="zoom"
      :plugin="plugin"
      :center="center"
      :events="events"
    >
      <!-- 这里用于点击时的标点 -->
      <el-amap-marker
        v-for="(marker, index) in markers"
        :key="index + '1'"
        :position="marker"
      />
      <!-- 这里用于特殊位置的标点 -->
      <el-amap-marker
        v-for="(marker, index) in markerList"
        :key="index + '2'"
        :position="marker.lnglats"
        :icon="getIcon(marker)"
        :events="marker.events"
        :offset="[-24, -24]"
      />
      <!-- 信息窗体 -->
      <el-amap-info-window
        v-if="currentWindow.visible"
        :position="currentWindow.position"
        :visible.sync="currentWindow.visible"
        :content="currentWindow.content"
        :close-when-click-map="false"
        :events="currentWindow.events"
        :offset="[0, -24]"
      />
    </el-amap>
  </div>
</template>

<script>

import LED0 from '@/assets/imgs/LED-0.png'
import LED1 from '@/assets/imgs/LED-1.png'
import lamppost0 from '@/assets/imgs/lamppost-0.png'
import lamppost1 from '@/assets/imgs/lamppost-1.png'
import tourGuide0 from '@/assets/imgs/tourGuide-0.png'
import tourGuide1 from '@/assets/imgs/tourGuide-1.png'
export default {
  name: 'Map',
  props: {
    zoom: { // 地图缩放比例。zoom值越小,越宏观、越大,越微观。
      type: Number,
      default: 14
    },
    center: {
      type: Array,
      default: () => [120.147076, 30.245426] // 西湖风景区的经纬度
    },
    markers: {
      type: Array,
      default: () => []
    },
    markerList: {
      type: Array,
      default: () => []
    },
    currentWindow: {
      type: Object,
      default: () => ({
        position: [],
        visible: false,
        content: '测试'
      })
    }
  },
  data() {
    const self = this
    return {
      LED0,
      LED1,
      lamppost0,
      lamppost1,
      tourGuide0,
      tourGuide1,
      address: null,
      loaded: false,
      events: {
        init(o) {
          console.log('地图初始化', o)
          // ... 初始地图的一些操作
        },
        complete(){
          // ... 地图渲染完成后的一些操作
        }
        // 点击地图
        click: self.click
      },
      // 一些工具插件
      plugin: [
        {
          pName: 'Geocoder',
          events: {
            init(o) {
              console.log('Geocoder', o.getAddress())
            }
          }
        },
        {
          // 定位
          pName: 'Geolocation',
          events: {
            init(o) {
              // o是高德地图定位插件实例
              o.getCurrentPosition((status, result) => {
                // 会存在失败的时候,官网回答:https://lbs.amap.com/faq/js-api/map-js-api/position-related/43361/
                console.log('查询成功定位信息', status, result)
                if (result && result.position) {
                  // 根据经纬度设置坐标 --不想替换掉默认的center的可以先注释
                  self.$emit('update:center', [result.position.lng, result.position.lat])
                  // self.$emit('update:markers', [[result.position.lng, result.position.lat]])
                  // load
                  self.loaded = true
                  // 页面渲染好后
                  self.$nextTick()
                }
              })
            }
          }
        },
        {
          // 搜索 --我这里没用到
          pName: 'PlaceSearch',
          events: {
            init(instance) {
              console.log('搜索', instance)
            }
          }
        },
        {
          // 定位城市
          pName: 'CitySearch',
          events: {
            init(o) {
              // o是高德地图定位插件实例
              o.getLocalCity(function(status, result) {
                if (status === 'complete' && result.info === 'OK') {
                  // 查询成功,result即为当前所在城市信息
                  console.log('查询成功,当前所在城市信息', result)
                }
              })
            }
          }
        }
      ]
    }
  },
  methods: {
    // 点击地图获取经纬度和具体位置
    click(e) {
      const { lng, lat } = e.lnglat
      this.$emit('update:center', [lng, lat])
      this.$emit('update:markers', [[lng, lat]])
      console.log('[lng, lat]', [lng, lat])

      // 这里通过高德 SDK 完成。获取具体地址的
      const geocoder = new AMap.Geocoder({
        radius: 1000,
        extensions: 'all'
      })
      const that = this
      geocoder.getAddress([lng, lat], function(status, result) {
        if (status === 'complete' && result.info === 'OK') {
          if (result && result.regeocode) {
            that.address = result.regeocode.formattedAddress
            console.log('具体位置:', result.regeocode.formattedAddress)
            that.$nextTick()
          }
        }
        that.$emit('getLocation', { lng, lat, address: that.address })
      })
    },
    getIcon(item) {
      if (item.mediaTypeName === '灯杆屏') {
        return item.status ? this.lamppost0 : this.lamppost1
      } else if (item.mediaTypeName === '导览屏') {
        return item.status ? this.tourGuide0 : this.tourGuide1
      } else return item.status ? this.LED0 : this.LED1
    }
  }
}
</script>
<style lang="scss" scoped>
/* 指定地图的宽高 */
.amapClass, .Map {
  width: 100%;
  height: 100%;
}
</style>
 关于el-amap-marker的属性:

1、position:为marker点的坐标(经纬度),接收数组

2、icon:自定义图标地址

3、events:事件集合对象,click、dblclick、rightclick、mouseover、mouseout等

events: {
    click: (e) => {
        // ...点击操作
    },
    dblclick: (e) => {
        // ...双击操作
    },
    ...
}

4、offset:偏移量

其他我没用到的还有:

5、clickable:true允许用户可点击marker点(默认也是true)

6、animation:marker点的动画效果

      marker点弹跳效果:设置值为 AMAP_ANIMATION_BOUNCE

7、label:点显示的简略信息

8、content可以是文字字符串也可以是html

关于el-amap-info-window信息窗体的属性

静态属性

名称类型说明
vidString组件的ID。
isCustomBoolean是否自定义窗体。设为true时,信息窗体外框及内容完全按照content所设的值添加(默认为false,即在系统默认的信息窗体外框中显示content内容)
autoMoveBoolean是否自动调整窗体到视野内(当信息窗体超出视野范围时,通过该属性设置是否自动平移地图,使信息窗体完全显示)
closeWhenClickMapBoolean控制是否在鼠标点击地图后关闭信息窗体,默认false,鼠标点击地图后不关闭信息窗体
showShadowBooleanBoolean 控制是否显示信息窗体阴影,取值false时不显示窗体阴影,取值true时显示窗体阴影默认值:false
offsetArray相对于基点的偏移量。默认情况是信息窗体的底部中心点(BOTTOM_CENTER) 和基点之间的偏移量

动态属性

名称类型说明
contentString/HTML显示内容。支持字符串和HTML。
templateString支持传入 Vue 模板。v0.4.0 开始支持。
vnodeVNode 或 Funtion: (Instance) => VNode支持 VNode 渲染。v0.4.2 开始支持
contentRenderFunction: (createElement: () => VNode, instance) => VNode支持 VNode render 渲染。v0.4.3 开始支持
sizeSize信息窗体尺寸(isCustom为true时,该属性无效)
positionArray信息窗体显示基点位置(自v1.2 新增)
visibleBoolean信息窗体是否显示。这里需要注意的是,高德地图只支持同时一个信息窗体的显示。所以一旦有窗体显示切换的场景,visible数组的状态需要自行维护。

 ref 可用方法

提供无副作用的同步帮助方法

函数返回说明
$$getInstance()AMap.InfoWindow获取infoWindow实例

事件(也是events里的)

事件参数说明
initObject高德组件实例
change属性发生变化时
open信息窗体打开之后触发事件
close信息窗体关闭之后触发事件

 4、使用地图组件

我把使用的页面也全贴上了,但其实search-box里面的东西大家可以忽略,只是针对markerList的查询过滤

<template>
  <div class="box">
    <div class="search-box">
      <el-form ref="queryForm" label-width="auto" class="searchForm" :model="searchForm" style="padding: 16px 0 0;">
        <el-form-item label="类型" prop="mediaType">
          <el-select v-model="searchForm.mediaType">
            <el-option v-for="item in digitalTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="区域" prop="region">
          <el-select v-model="searchForm.region" clearable>
            <el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label-width="20px">
          <el-button v-permission="['ResourceDistribution:query']" class="search-btn" icon="el-icon-search" type="primary" @click="getDetail">
            查询
          </el-button>
          <el-button class="reset-btn" icon="el-icon-refresh-left" @click="resetForm('queryForm')">
            重置
          </el-button>
        </el-form-item>
        <el-form-item label="设备名称" prop="">
          <el-select v-model="searchKey" filterable clearable placeholder="请输入关键字" @change="quickOrientation">
            <el-option v-for="item in markerList" :key="item.mediaCode" :label="item.mediaName" :value="item.mediaCode" />
          </el-select>
          <!-- <el-input id="search" v-model="searchKey" placeholder="请输入设备名称" /> -->
        </el-form-item>
        <el-form-item label-width="20px" style="width: 100px;">
          <el-button v-permission="['ResourceDistribution:query']" class="search-btn" type="primary" @click="quickOrientation">
            快速定位
          </el-button>
        </el-form-item>
      </el-form>
      <div class="rightType">
        <div v-for="item in digitalTypeOptions" :key="item.value" class="iconItem">
          <svg-icon v-if="item.label === '灯杆屏'" icon-class="lamppost" />
          <svg-icon v-else-if="item.label === '导览屏'" icon-class="tourGuide" />
          <svg-icon v-else icon-class="LED" />
          <span>{{ item.label }}</span>
        </div>
      </div>
    </div>
    <div class="rightBottom">
      <span class="successStatus">已启用</span>
      <span class="errorStatus">已禁用</span>
    </div>
    <!-- 地图组件 -->
    <Map
      :center.sync="center"
      :markers.sync="markers"
      :zoom.sync="zoom"
      :marker-list="markerList"
      :current-window="currentWindow"
      @getLocation="getLocation"
    />
  </div>
</template>

<script>
import Map from '@/components/Map'
import { dictList, deviceFilter } from '@/api/resource'
export default {
  name: 'GaodeDituAmap',
  components: { Map },
  data() {
    return {
      searchForm: {
        mediaType: '',
        region: ''
      },
      searchKey: '',
      digitalTypeOptions: [],
      regionOptions: [],
      currentWindow: {
        position: [],
        visible: false,
        content: '',
        events: {}
      },
      markerList: [],
      markers: [],
      center: [121.133858, 30.606042],
      zoom: 14 // 地图缩放比例。zoom值越小,越宏观、越大,越微观。
    }
  },
  mounted() {
    this.getDict()
    this.getDetail()
  },
  methods: {
    // 获取标点信息
    async getDetail() {
      this.currentWindow.visible = false
      const that = this
      const { data } = await deviceFilter(this.searchForm)
      data.forEach(item => {
        item.lnglats = [item.longitude, item.latitude]
        item.events = {
          click(e) {
            console.log('点击标点', e)
            that.center = item.lnglats
            that.currentWindow.content = that.createWinContent(item)
            that.currentWindow.position = item.lnglats
            that.currentWindow.events = {
              close(e) {
                console.log('窗体关闭', e)
                that.currentWindow.visible = false
              }
            }
            that.currentWindow.visible = true
          }
        }
      })
      this.markerList = data
    },
    /**
     * 基础配置信息
     */
    async getDict() {
      const { data: { area, digitalType }} = await dictList('dictNames=area&dictNames=digitalType')
      this.regionOptions = area
      this.digitalTypeOptions = digitalType
    },
    // 重置
    resetForm(formName) {
      this.$refs[formName].resetFields()
      this.zoom = this.$options.data.call(this).zoom
      this.getDetail()
    },
    // 快速定位
    quickOrientation() {
      if (!this.searchKey) {
        this.markers = []
        this.currentWindow.visible = false
        return
      }
      const cur = this.markerList.find(f => f.mediaCode === this.searchKey)
      if (cur) {
        this.center = [cur.longitude, cur.latitude]
        // this.markers = [this.center]
        this.currentWindow.content = this.createWinContent(cur)
        this.currentWindow.position = [cur.longitude, cur.latitude]
        this.currentWindow.visible = true
        this.zoom = 15
      }
    },

    // 获取经纬度及地理位置
    getLocation({ lng, lat, address }) {
      console.log('获取到经纬度和地址啦:', lng, lat, address)
    },
    // 画信息窗
    createWinContent(item) {
      return `
        <div>
          <div style="display: flex;margin-bottom: 12px">
            ${item.src ? `<img src="${item.src}" style="width: 120px;margin-right: 16px;">` : ''}
            <div style="display: flex;flex-direction: column;justify-content: space-around;">
              <strong style="font-size: 18px">${item.mediaName}</strong>
              <div style="margin-top: 6px">
                <span style="font-size: 14px;color: #0082FF;padding: 0px 6px;background: rgba(0,130,255,0.15);border-radius: 4px;">${item.mediaTypeName}</span>
                <span style="font-size: 14px;color: ${!item.status ? '#46A77B' : '#E30000'};padding: 0px 6px;background: ${!item.status ? '#46A77B26' : '#E3000026'};border-radius: 4px;">${!item.status ? '已启用' : '已禁用'}</span>
              </div>
              <div style="margin-top: 8px">
                <i class="el-icon-location" style="color: #0082FF"></i>
                <span style="font-size: 14px;">${item.regionName}</span>
              </div>
            </div>
          </div>
          <div style="font-size: 14px;color: #666666;line-height: 20px;">
            <span>${item.specification},</span>
            <span>${item.supplier},</span>
            <span>${item.supplierContact},</span>
            <span>${item.supplierPhone}</span>
          </div>
        </div>`
    }
  }
}
</script>
<style lang="scss" scoped>
.box {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 0px;
  position: relative;

  .search-box {
    position: absolute;
    background-color: #FFFFFF;
    width: calc(100% - 32px);
    top: 16px;
    left: 16px;
    z-index: 999;
    border-radius: 4px;

    .searchForm .el-form-item {
      margin: 0 0px 16px;
    }

    .tip-box {
      width: 100%;
      max-height: 260px;
      position: absolute;
      top: 30px;
      overflow-y: auto;
      background-color: #fff;
    }
    .rightType{
      position: absolute;
      right: 0px;
      bottom: -24px;
      transform: translateY(100%);
      z-index: 999;
      background: #FFFFFF;
      border-radius: 4px;
      padding: 16px;
      display: flex;
      align-items: center;
      flex-direction: column;
      .iconItem{
        font-size: 14px;
        color: #4A4A4A;
        display: flex;
        align-items: center;
        flex-direction: column;
        .svg-icon{
          width: 24px;
          height: 24px;
        }
      }
      .iconItem+.iconItem{
        margin-top: 24px;
      }
    }
  }
  .rightBottom{
    position: absolute;
    right: 16px;
    bottom: 16px;
    z-index: 999;
    padding: 16px;
    font-size: 14px;
    color: #4A4A4A;
    background-color: #FFFFFF;
    border-radius: 4px;
    .successStatus{
      margin-right: 24px;
    }
    .successStatus::before{
      content: '';
      display: inline-block;
      height: 8px;
      width: 8px;
      background-color: #46A77B;
      border-radius: 50%;
      margin-right: 5px;
    }
    .errorStatus::before{
      content: '';
      display: inline-block;
      height: 8px;
      width: 8px;
      background-color: #FF4747;
      border-radius: 50%;
      margin-right: 5px;
    }
  }
}

/* 指定地图的宽高 */
.amapClass {
  width: 100%;
  height: 100%;
}
</style>

成果大致样式如下:

附:高德Key申请

登录后到这个地址:我的应用 | 高德控制台

1、点击添加key

2、根据自己的需求选择服务平台,可以看看对应的“可使用服务” 来决定,我这里选择Web端

 3、提交后就有一条新增的记录,复制放进代码使用就好啦

参考地址:

vue-amap基于vue的高德地图使用_amap vue-CSDN博客

 1.5.1 信息窗体 - vue-amap 中文文档 - 开发文档 - 文江博客

转载请注明出处或者链接地址:https://www.qianduange.cn//article/9502.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!