在vue中使用腾讯地图

最近在做公司后台ERP系统时,用到了腾讯地图,遇到了不少坑,在这里记录下:

用到了几个主要知识点先说下:

1、单例的设计思想(在判断是否有map实例那块)

2、对象深度克隆 (创建门店那块)

3、this指向问题 (有很多,自己看)

 

引入 qqmap

腾讯官方未提供通过npm插件方式来安装腾讯地图,还好有大佬写了一个:

https://www.npmjs.com/package/qqmap

npm install qqmap --save

在vue中导入,导入方式有两种,自己挑一种:

var maps = require('qqmap') //  CommonJS 导入方式
import maps from 'qqmap' // 使用ES module

 

业务逻辑梳理

引入完之后,咱们切入正题:

首先说下业务逻辑,在点击添加门店时,会出现一个tabs标签页,这块用的是element  tabs标签页组件,点击显示腾讯地图,店长可搜索想要添加的门店地址,在地图中标记门店;或直接拖动地图,来标记需要创建的门店,当在地图中标记好地址,对应的地址会显示在输入框中,  这样门店 地址会直接拿到,我会把经纬度坐标、门店地址 发送给后端,公司小程序的地图与后台系统的数据是共用的,大体效果如下:

 上代码:

html模板代码:

<template>
  <div>
     <!-- el-button 添加门店按钮 -->
    <el-button type="primary" @click="createdShop">添加门店</el-button>
    <!-- el-dialog 弹出的蒙层 -->
    <el-dialog title="腾讯地图" :visible.sync="dialogFormVisible" @close="dielogClose">
      <el-tabs type="border-card" v-model="TXMapParams.selectValue" @tab-click="selectTab">
        <!-- tab1一个站位的页 -->
        <el-tab-pane label="站位" name="1"><h1 style="width:200px; height:200px;">站位</h1></el-tab-pane>
        <!-- tab2腾讯地图展示页 -->
        <el-tab-pane label="腾讯地图" name="2">
            <!-- el-select  输入框-->
          <el-select v-model="TXMapParams.searchValue" filterable remote reserve-keyword placeholder="请输入关键词"
            style="width:400px; marginBottom:20px;" :remote-method="searchKeyword"
          >
            <el-option v-for="item in TXMapParams.addressOptions"
              :key="item.name"
              :label="item.name"
              :value="item.name"
            >
            </el-option>
          </el-select>
            <!-- 下边这个div就是地图-->
          <div ref="mapBox" style="width:800px; height:300px;"></div>
        </el-tab-pane>
      </el-tabs>
  </div>
</template>

js代码:

因为js代码有点多,为了方便查看,我分成了几个部分:

// 我在全局定义了一些默认的数据,与地图有关的数据我全部放在这个全局对象中,在data数据对象中用深克隆的方
// 式,赋值给 TXMapParams,之所以要这样做,因为在创建完一个门店时,第二次在创建一个门店,数据是初
// 始化之后的, 而不会是第一次创建的数据。 
const defaultParams = {
    map: null, // 地图实例 (地图)
    marker: '', // 地图的标识(标注的点)(地图)
    appkey: 'xxxxxxxxx', // appkey是开发者key(地图)
    selectValue: '1', // 初始化tabs标签栏,让它默认显示第一栏(element)
    increaseZB:{ // 这个参数是地图的经纬度(地图)
      lat: 37.52, // 纬度
      lng: 121.39 // 经度
    },
    addressOptions: [],// 搜索框的下拉菜单需要渲染的数据(element)
    searchValue: '', // 搜索框中的数据(element)
    searchService: null // 关键字搜索时,搜索周边/相关地域/地址(地图)
}
import maps from 'qqmap' // 引入腾讯地图
export default {
  data() {
    return {
      dialogFormVisible: false,
      TXMapParams: {...defaultParams, increaseZB:{...defaultParams['increaseZB']}}
    }
  }
  methods:{
    // 创建门店的方法
    createdShop() {
      this.dialogFormVisible = true // 蒙层显示
      this.TXMapParams = {...defaultParams, increaseZB:{...defaultParams['increaseZB']}} // 这块是一个深度克隆,上边有解释!
    },
    // 这个方法是监听蒙层关闭的,只要关闭,就初始化地图,这个目的是当点击编辑的时候,每次地图都会先初始化一次,然后在把对应的数据赋值给地图,否则造成的bug是编辑每一行数据,地图信息都会一样的!!!
    dielogClose() {
      this.TXMapParams.selectValue = '1'
      this.TXMapParams.map = null
    },
    // 这个方法是当循环切换tabs时,判断地图是否已经被创建,这块利用了单例的设计思想,如果有map实例,用被存储的,没有则初始化地图,这样实例只会被初始化一次
    selectTab() {
      if(this.TXMapParams.selectValue === '2') {
        this.TXMapParams.map || this.initMap()
      }
    },
  // 初始化地图
  initMap() {
      maps.init(this.TXMapParams.appkey, () => { // 参数一:开发者key,参数二:一个函数
        // 其实这个判断是否有map实例,不写也行,在上边已经判断过了
        if (!this.TXMapParams.map) {
          // createZuoBiao方法是 初始化坐标位置,括号两个参数是经纬度
          const myLatLng = this.createZuoBiao(this.TXMapParams.increaseZB.lat, this.TXMapParams.increaseZB.lng)
          this.TXMapParams.map = new maps.Map(this.$refs.mapBox, { // 实例化地图,赋值给data中的map
            center: myLatLng, // 目前的位置
            zoom: 13,
            draggable: true, // 是否可移动
            scrollwheel: true, // 是否可滚动
            disableDoubleClickZoom: false
          })
        }
        // 初始化marker标识
        this.TXMapParams.marker = new maps.Marker({
          position: this.createZuoBiao(this.TXMapParams.increaseZB.lat, this.TXMapParams.increaseZB.lng), // 坐标位置
          map: this.TXMapParams.map // 实例化的地图
        })
        const _this = this // 修正在事件中的this指向
        // 初始化点击事件,绑定单击事件添加参数,参数一:地图实例,参数二:点击事件,可以通过第三个函数的参数event来拿到每次点击的经纬度。
        maps.event.addListener(_this.TXMapParams.map, 'click', function(event) {
          _this.createdMarker(event) // 提取经纬度的方法
        })
      })
    },
    // 创建经纬度
    createZuoBiao(myLatitude, myLongitude) {
      return new maps.LatLng(myLatitude, myLongitude)
    },
    // 创建marker标识,里边的判断是每次创建判断之前是否有marker,有话先删除,因为只能标识一个门店
    createdMarker(event) {
      if (this.TXMapParams.marker) {
        this.deleteOverlays() // 删除marker的方法
      }
      this.TXMapParams.increaseZB.lat = event.latLng['lat']
      this.TXMapParams.increaseZB.lng = event.latLng['lng']
      // 创建标识
      this.TXMapParams.marker = new maps.Marker({
        position: this.createZuoBiao(this.TXMapParams.increaseZB.lat, this.TXMapParams.increaseZB.lng),
        map: this.TXMapParams.map
      })
      // 根据经纬度调用获取位置方法,这个方法就是根据经纬度解析成地址
      this.geocoder().getAddress(this.createZuoBiao(this.TXMapParams.increaseZB.lat, this.TXMapParams.increaseZB.lng))
    },
    // 删除marker 标识
    deleteOverlays() {
      this.TXMapParams.marker.setMap(null)
    },
    // 经纬度解析地址
    geocoder() {
      const _this = this // 修正下边this指向的问题
      return new maps.Geocoder({
        complete: function(result) {
            // 通过result参数 可以拿到当前点击的位置的详细地址,展开运算符,获取里边的参数 
          const { city, district, province, street, streetNumber, town, village } = { ...result['detail']['addressComponents'] }
          _this.TXMapParams.searchValue = `${province}${city}${district}${street}${town}${village}${streetNumber}` // 参数拼接赋值给搜索框
        }
      })
    },
   // 检索关键字的方法
   searchShop() {
      var _this = this // 修正下边this指向
      var latlngBounds = new maps.LatLngBounds()
      // 设置Poi检索服务,用于本地检索、周边检索
      this.TXMapParams.searchService = new maps.SearchService({
        // 设置搜索范围为烟台
        location: '烟台',
        // 设置搜索页码为1
        pageIndex: 1,
        // 设置每页的结果数为5
        pageCapacity: 5,
        // 设置展现查询结构到infoDIV上
        // panel: document.getElementById('infoDiv'),
        // 设置动扩大检索区域。默认值true,会自动检索指定城市以外区域。
        autoExtend: true,
        // 检索成功的回调函数,result参数是搜索的结果
        complete: function(results) {
          // 把地址相关数据提取出来
          var pois = results.detail.pois 
          if (pois) {
            for (var i = 0, l = pois.length; i < l; i++) {
              var poi = pois[i] 
              _this.TXMapParams.addressOptions = []
              if (poi.address) { // 判断是否有address,因为会有没有搜到的时候
                _this.TXMapParams.addressOptions.push(poi)// 地址数据push到门店下拉菜单
              }
              // 扩展边界范围,用来包含搜索到的Poi点
              latlngBounds.extend(poi.latLng)
            }
          }
          // 调整地图视野
          _this.TXMapParams.map.fitBounds(latlngBounds)
        },
        // 服务请求失败
        error: function() {
          _this.$message({
            type: 'error',
            message: '请正确输入查询结果!',
            duration: 5000
          })
        }
      })
    },
    // 设置搜索的范围和关键字等属性
    searchKeyword(query) {
      this.searchShop()
      // 根据输入的城市设置搜索范围
      this.TXMapParams.searchService.setLocation('烟台')
      // 根据输入的关键字在搜索范围内检索
      this.TXMapParams.searchService.search(query)
    }
  }
}

总结

到这,就已经结束了,实现的功能就是刚开始所看到的那样,其实逻辑一点页不难,因为腾讯地图api上边都有很详细的例子,但是如果你想把它拼起来,形成一个完整的功能,还需要有点耐心的,上边的逻辑不单单是添加店铺,还有点击门店编辑的时候,拿到当前的门店信息直接赋值给地图即可,亲测,无bug,而且抗霍霍!

就到这吧,有啥问题或不懂的地方欢迎小伙伴们留言。。。

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值