整理vue3项目接入高德地图

接入之前的准备工作:

可以在自己的项目中接入了:

  • 先安装依赖:

    • npm方式: npm i @amap/amap-jsapi-loader --save
    • yarn方式: yarn add @amap/amap-jsapi-loader --save
  • 引入下载的依赖包:import AMapLoader from '@amap/amap-jsapi-loader'

  • 在页面中想放地图的地方加 <div id="替换自己的id"></div>并加上CSS宽高,不加页面会看不到

  • onMounted中初始化地图:这时在页面就可以看到简单地图了

    window._AMapSecurityConfig = {
      securityJsCode: '替换自己的安全密钥', // 安全密钥
    }
    // AMapLoader => 加载器 资源加载完成后就会触发 then
    AMapLoader.load({
      key: '替换自己的key', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
      plugins: [
        // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        'AMap.ToolBar', // 缩放工具条
        'AMap.Scale', // 比例尺
        'AMap.Geolocation', //定位,提供了获取用户当前准确位置、所在城市的方法
        'AMap.Geocoder', // 坐标 -> 地址
        'AMap.ElasticMarker', // 灵活点标记
        'AMap.AutoComplete', // 输入提示
        'AMap.PlaceSearch', // 搜索
        'AMap.DistrictSearch', // 行政区查询服务
        'AMap.CitySearch', // 城市获取服务,获取用户所在城市
      ],
    })
      .then((AMap) => {
        //设置地图容器id
        state.map = new AMap.Map('替换自己div的id', {
          zoom: 10, //初始化地图层级
          viewMode: '3D', //是否为3D地图模式
          scrollWheel: true, //鼠标滚轮放大缩小
          doubleClickZoom: true, //双击放大缩小
          keyboardEnable: true, //键盘控制放大缩小移动旋转
        })
        
        // 初始化插件
        // loadPlugin()
        
        // 可写其他逻辑
      })
      .catch(() => {
        Toast('地图加载失败')
      })
    

    在这里插入图片描述

  • 后面就可以利用高德提供的插件来定制化了,在初始化地图成功的回调里初始化插件,插件网址:https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins-list

    const loadPlugin = () => {
      /* 工具条插件 */
      AMap.plugin(['AMap.ToolBar', 'AMap.Scale'], function () {
        //在回调函数中实例化插件,并使用插件功能
        const toolbar = new AMap.ToolBar() //创建工具条插件实例
        state.map.addControl(toolbar) //添加工具条插件到页面
        const scale = new AMap.Scale()
        state.map.addControl(scale)
      })
    
      /* 搜索 */
      AMap.plugin('AMap.PlaceSearch', function () {
        state.placeSearch = new AMap.PlaceSearch({
          map: state.map,
          autoFitView: false,
          showCover: true,
          pageIndex: state.pageIndex,
        })
      })
    
      /* 行政区搜索 */
      AMap.plugin('AMap.DistrictSearch', function () {
        if (!state.district) {
          state.district = new AMap.DistrictSearch({
            subdistrict: 3, //获取边界不需要返回下级行政区
            extensions: 'all', //返回行政区边界坐标组等具体信息
            level: 'district', //查询行政级别为 市
          })
        }
        state.district.setLevel('district')
      })
    
      /* 定位 */
      AMap.plugin('AMap.Geolocation', function () {
        state.geolocation = new AMap.Geolocation({
          enableHighAccuracy: true, // 是否使用高精度定位,默认:true
          timeout: 10000, // 设置定位超时时间,默认:无穷大
          offset: [10, 20], // 定位按钮的停靠位置的偏移量
          zoomToAccuracy: true, //  定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
          position: 'RB', //  定位按钮的排放位置,  RB表示右下
        })
      })
    
      /* 初始化marker */
      state.marker = new AMap.Marker()
    
      /* 使用到了根据经纬度获取地址 */
      AMap.plugin('AMap.Geocoder', function () {
        state.geocoder = new AMap.Geocoder()
      })
    }
    
  • 在插件初始化完之后可以使用插件的方法进行定制化,整理用到的插件网址

全部代码如下:

<template>
  <div id="map"></div>
  <div>
    <div class="flex aic" style="background: #fff">
      <van-search
        id="search"
        v-model.trim="state.keyword"
        class="flex1"
        placeholder="请输入地址关键词"
        shape="round"
        show-action
      >
        <template #action>
          <div @click="onSearch">搜索</div>
        </template>
      </van-search>
      <div style="padding: 0 14px 0 4px; font-size: 14px" @click="sureClose">
        确定
      </div>
    </div>

    <div class="list">
      <van-list
        v-if="!state.empty"
        v-model:error="state.error"
        v-model:loading="state.loading"
        error-text="请求失败,点击重新加载"
        :finished="state.finished"
        finished-text="没有更多了"
        :immediate-check="false"
        @load="nextPageSearch"
      >
        <template v-for="s in state.searchList" :key="s.id">
          <van-cell
            center
            :label="itemLabel(s)"
            style="--van-cell-line-height: 20px"
            :title="`${
              s.address === s.adname && s.adname !== s.name
                ? itemLabel(s)
                : s.name
            }`"
            @click="searchItemClick(s)"
          >
            <template #value>
              <img
                fit="contain"
                height="14"
                :src="
                  state.checkedId == s.id
                    ? require('@/assets/images/mine/checked.png')
                    : require('@/assets/images/mine/noCheck.png')
                "
                width="14"
              />
            </template>
          </van-cell>
        </template>
      </van-list>
      <van-empty
        v-if="state.empty"
        description="暂无数据"
        :image="require('@/assets/images/noData.png')"
        :image-size="[150, 126]"
      />
    </div>
  </div>
</template>

<script setup>
  import AMapLoader from '@amap/amap-jsapi-loader'
  import { Toast } from 'vant'

  const route = useRoute()
  const router = useRouter()
  const state = reactive({
    areaList: computed(() => getters['common/city']),
    loading: false,
    finished: false,
    error: false,
    empty: false,
    keyword: '', // 搜索值
    map: undefined,
    autocomplete: undefined,
    placeSearch: undefined,
    district: undefined,
    polygon: undefined,
    geolocation: undefined,
    marker: undefined,
    geocoder: undefined,
    pageIndex: 1,
    searchList: [],
    checkedId: '',
    selectItem: {},
  })

  const areaList = computed(() => {
    return JSON.parse(window.sessionStorage.getItem('city'))
  })

  const itemLabel = (s) => { // 搜索的数据名字会有重复的需要注意处理
    return `${s.pname === s.cityname ? s.pname : `${s.pname} ${s.cityname}`} ${
      s.name === s.adname ? '' : s.adname
    } ${s.address === s.adname ? '' : s.address}`
  }

  const sureClose = () => {
    // 数据可能和自己库的不一致,需要自己修改,我这里是修改了citycode
    const adcode = ['710000', '810000', '820000'].includes(
      state.selectItem.pcode
    )
      ? state.selectItem.pcode
      : state.selectItem.adcode
    const city = areaList.value.filter((f) => f.id == adcode)[0]
    window.sessionStorage.setItem(
      'gdAddress',
      JSON.stringify({
        ...state.selectItem,
        areaName: city.fullName,
        citycode: city.parentId,
      })
    )
    router.go(-1)
  }
  const onSearch = () => {
    if (!state.keyword) {
      return
    } else {
      clearPolygon()
      state.map.remove([state.marker])
      state.pageIndex = 1
      state.searchList = []
      nextPageSearch()
    }
  }

  const searchItemClick = (s) => {
    state.selectItem = s
    state.checkedId = s.id
    const city = areaList.value.filter(
      (f) => f.name == s.name || f.fullName == s.name
    )
    if (
      city.length !== 0 &&
      ['省', '市', '区', '县'].includes(
        s.name.substring(s.name.length - 1, s.name.length)
      )
    ) { // 进行行政区搜索
      districtSearch(s.adcode)
    } else {
      clearPolygon()
      state.map.setZoomAndCenter(12, [s.location.lng, s.location.lat])
      state.map.remove([state.marker])
      state.marker = new AMap.Marker({
        label: { content: s.name, direction: 'top' }, // 文本标注
        position: new AMap.LngLat(s.location.lng, s.location.lat),
      })
      state.map.add([state.marker])
    }
  }

  const loadPlugin = () => {
    /* 工具条插件 */
    AMap.plugin(['AMap.ToolBar', 'AMap.Scale'], function () {
      //在回调函数中实例化插件,并使用插件功能
      const toolbar = new AMap.ToolBar() //创建工具条插件实例
      state.map.addControl(toolbar) //添加工具条插件到页面
      const scale = new AMap.Scale()
      state.map.addControl(scale)
    })

    /* 搜索 */
    AMap.plugin('AMap.PlaceSearch', function () {
      state.placeSearch = new AMap.PlaceSearch({
        map: state.map, // 会在地图标注
        autoFitView: false, // 地图是否显示能看到搜索结果的所有标注
        showCover: true,
        pageIndex: state.pageIndex,
      })
    })

    /* 行政区搜索 */
    AMap.plugin('AMap.DistrictSearch', function () {
      if (!state.district) {
        state.district = new AMap.DistrictSearch({
          subdistrict: 3, //获取边界不需要返回下级行政区
          extensions: 'all', //返回行政区边界坐标组等具体信息
          level: 'district', //查询行政级别为 市
        })
      }
      state.district.setLevel('district')
    })

    /* 浏览器定位 */
    AMap.plugin('AMap.Geolocation', function () {
      state.geolocation = new AMap.Geolocation({
        enableHighAccuracy: true, // 是否使用高精度定位,默认:true
        timeout: 10000, // 设置定位超时时间,默认:无穷大
        offset: [10, 20], // 定位按钮的停靠位置的偏移量
        zoomToAccuracy: true, //  定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
        position: 'RB', //  定位按钮的排放位置,  RB表示右下
      })
    })

    /* 初始化marker */
    state.marker = new AMap.Marker()
    
    /* 使用到根据经纬度获取地址 */
    AMap.plugin('AMap.Geocoder', function () {
      state.geocoder = new AMap.Geocoder()
    })
  }

  // 清除行政区polygon
  const clearPolygon = () => {
    if (state.polygon) {
      state.map.remove(state.polygon)
      state.polygon = null
    }
  }

  // 添加marker
  const addNewMarker = (lng, lat) => {
    state.map.remove([state.marker]) // 删除标记
    state.marker = new AMap.Marker({
      position: new AMap.LngLat(lng, lat),
    })
    state.map.add([state.marker]) // 添加标记
    state.marker.setPosition([lng, lat])

    lnglatAddress(lng, lat, () => {
      searchKerword()
    }) // 根据经纬度获取地址给marker添加label
  }

  const nextPageSearch = () => { // 滑到底部请求下一页
    AMap.plugin('AMap.PlaceSearch', function () {
      state.placeSearch = new AMap.PlaceSearch({
        map: state.map,
        autoFitView: false,
        pageIndex: state.pageIndex,
      })
    })
    searchKerword()
  }

  // 根据输入内容搜索
  const searchKerword = () => {
    state.placeSearch.search(state.keyword, (status, result) => {
      if (status == 'complete') {
        state.loading = false
        state.searchList =
          state.pageIndex === 1
            ? result.poiList.pois
            : [...state.searchList, ...result.poiList.pois]
        state.checkedId =
          state.searchList.length !== 0 && state.pageIndex === 1
            ? result.poiList.pois[0].id
            : state.checkedId
        if (result.poiList.count && state.searchList.length !== 0) {
          state.empty = false
          state.pageIndex === 1 && searchItemClick(result.poiList.pois[0])
          state.finished = result.poiList.pois.length < 10
          state.pageIndex += 1
        } else {
          state.empty = true
        }
      } else {
        state.finished = true
        state.loading = false
      }
    })
  }

  // 根据经纬度获取地址并建立带有label的maeker
  const lnglatAddress = (lng, lat, fn) => {
    state.geocoder.getAddress([lng, lat], (status, result) => {
      if (status === 'complete' && result.regeocode) {
        state.keyword = result.regeocode.formattedAddress
      } else {
        state.keyword = ''
        Toast('获取地址失败')
      }
      state.map.setZoomAndCenter(12, [lng, lat]) // 地图显示到标记地点
      // 添加地址标注
      state.map.remove([state.marker])
      state.marker = new AMap.Marker({
        label: { content: state.keyword, direction: 'top' }, // 文本标注
        position: new AMap.LngLat(lng, lat),
      })
      state.map.add([state.marker])
      fn && fn(result.regeocode)
    })
  }

  // 获取定位
  const getLocation = () => {
    state.geolocation.getCurrentPosition((status, result) => {
      if (status == 'complete') {
        addNewMarker(result.position.lng, result.position.lat)
      } else {
        Toast('获取定位失败')
      }
    })
  }

  // 行政区搜索
  const districtSearch = (code) => {
    state.map.remove([state.marker])
    state.district.search(code, function (status, result) {
      clearPolygon()
      const bounds = result.districtList[0].boundaries
      if (bounds) {
        // 生成行政区画polygon
        for (var i = 0; i < bounds.length; i += 1) {
          //构造MultiPolygon的path
          bounds[i] = [bounds[i]]
        }
        state.polygon = new AMap.Polygon({
          strokeWeight: 1,
          path: bounds,
          fillOpacity: 0.4,
          fillColor: '#80d8ff',
          strokeColor: '#0091ea',
        })
        state.polygon.on('click', () => {
          clearPolygon()
        })
        state.map.add(state.polygon) 
        state.map.setFitView(state.polygon) //视口自适应
      }
    })
  }

  // 初始化地图
  const initMap = () => {
    window._AMapSecurityConfig = {
      securityJsCode: '替换自己的安全密钥', // 安全密钥
    }
    // AMapLoader => 加载器 资源加载完成后就会触发 then
    AMapLoader.load({
      key: '替换自己的key', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
      plugins: [
        // 需要使用的的插件列表,如比例尺'AMap.Scale'等
        'AMap.ToolBar', // 缩放工具条
        'AMap.Scale', // 比例尺
        'AMap.Geolocation', //定位,提供了获取用户当前准确位置、所在城市的方法
        'AMap.Geocoder', // 坐标 -> 地址
        'AMap.ElasticMarker', // 灵活点标记
        'AMap.AutoComplete', // 输入提示
        'AMap.PlaceSearch', // 搜索
        'AMap.DistrictSearch', // 行政区查询服务
        'AMap.CitySearch', // 城市获取服务,获取用户所在城市
      ],
    })
      .then((AMap) => {
        //设置地图容器id
        state.map = new AMap.Map('替换自己要显示地图元素的id', {
          zoom: 10, //初始化地图层级
          viewMode: '3D', //是否为3D地图模式
          scrollWheel: true, //鼠标滚轮放大缩小
          doubleClickZoom: true, //双击放大缩小
          keyboardEnable: true, //键盘控制放大缩小移动旋转
        })
        state.map.setDefaultCursor('pointer') // 地图小手

        // 初始化插件
        loadPlugin()

        /* 初始化时有keyword就进行行政区搜索根据keyword搜索,没有就获取定位并进行周边搜索 */
        if (state.keyword) {
          searchKerword()
        } else {
          getLocation()
        }
      })
      .catch(() => {
        Toast('地图加载失败')
      })
  }

  onMounted(() => {
    state.keyword = route.query.keyword
    initMap()
  })
</script>

<style lang="scss" scoped>
  #map {
    width: 100%;
    height: 60vh;
    background: #fff;
    transition: all 0.3s ease-in-out;
  }
  .list {
    height: calc(40vh - 56px);
    overflow: scroll;
    :deep(.van-cell--center) {
      justify-content: space-between;
      .van-cell__value {
        flex: none;
        margin-left: 4px;
      }
    }
  }
</style>

图示如下:
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值