vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3地图选点组件

Vue3实现地图选点组件的示例代码

作者:liyfn

这篇文章主要为大家详细介绍了Vue3实现地图选点组件的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

Vue3地图选点组件

实现代码

<template>
  <div style="width: 100%; height: 500px">
    <div class="search-container">
      <el-autocomplete
        v-model="suggestionKeyWord"
        class="search-container__input"
        clearable
        :fetch-suggestions="searchSuggestions"
        placeholder="输入关键字搜索"
        @select="onSuggestionChoose"
      >
        <template #default="{ item }">
          <div class="value">{{ item.name }}</div>
          <span class="link">{{ item.address }}</span>
        </template>
      </el-autocomplete>
      <el-button type="primary" class="search-container__button" @click="doneMap"> 确定 </el-button>
    </div>
    <div class="map-body">
      <div id="container" class="map-body__left"></div>
      <img :class="iconClass" :src="markerSrc" alt="" />
      <!-- poi數據 -->
      <div class="map-body__right ele-map-picker-poi-list">
        <div
          v-for="(poi, index) in poiData"
          :key="index"
          :class="[
            'ele-map-picker-poi-item',
            { 'ele-map-picker-poi-item-active': index === chooseIndex },
          ]"
          @click="choose(index)"
        >
          <el-icon class="ele-map-picker-poi-item-icon el-icon-location-outline"
            ><Location
          /></el-icon>
          <!-- <icon-ep-location class="ele-map-picker-poi-item-icon el-icon-location-outline" /> -->
          <div class="ele-map-picker-poi-item-title">{{ poi.name }}</div>
          <div v-if="poi.address" class="ele-map-picker-poi-item-address">
            {{ poi.address }}
          </div>
          <el-icon v-if="index === chooseIndex" class="ele-map-picker-poi-item-check"
            ><Check
          /></el-icon>
          <!-- <icon-park-check-small
            v-if="index === chooseIndex"
            class="ele-map-picker-poi-item-check"
          /> -->
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted } from 'vue';
  import AMapLoader from '@amap/amap-jsapi-loader';
  import markerSrc from '@/assets/images/location.png';
  import type { Poi } from './type';

  // const props = defineProps({});
  const emit = defineEmits(['done-map']);

  // 中心点位置
  let location: any = reactive([116.4074, 39.9042]);
  // 地图缩放比例
  const chooseZoom = 15;

  // 搜索关键字
  const suggestionKeyWord = ref('');
  // 搜索建议列表
  let suggestionData = reactive([]);
  // 地图实例
  let map: any;
  // 输入建议实例
  let autoComplete = reactive({});
  // 选中的建议
  let chooseSuggestion = reactive<any>({});
  // 地图中心标记点
  let centerMarker = reactive({});
  // poi检索实例
  let placeSearch = reactive({});
  // poi检索的数据
  const poiData = ref<Poi[]>([]);
  // 选中的数据
  const chooseIndex = ref<any>(null);
  // 是否是点击poi列表移动地图
  let isSelMove = false;
  // 图标是否显示跳动动画
  const showIconAnim = ref(false);

  const iconClass = computed(() => {
    return ['ele-map-picker-main-icon', { 'ele-map-picker-anim-bounce': showIconAnim.value }];
  });

  /**
   * @description: 初始化地图
   * @param {*} local
   * @return {*}
   */
  const initMap = (local: any) => {
    AMapLoader.load({
      key: 'xxxxxxxxxxxxx', // 申请好的Web端开发者Key,首次调用 load 时必填
      version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
      plugins: ['AMap.Geocoder', 'AMap.PlaceSearch', 'AMap.AutoComplete'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    }).then((AMap) => {
      map = new AMap.Map('container', {
        zoom: chooseZoom,
        center: location,
      });

      // 输入建议实例
      autoComplete = new AMap.AutoComplete({
        city: '全国',
      });

      // marker实例
      centerMarker = new AMap.Marker({
        icon: new AMap.Icon({
          image: markerSrc,
          size: new AMap.Size(26, 36.5),
          imageSize: new AMap.Size(26, 36.5),
        }),
        offset: new AMap.Pixel(-13, -36.5),
      });
      addMarker(location[0], location[1]);

      // 获取poi检索实例
      placeSearch = new AMap.PlaceSearch({
        type: '', // poi检索兴趣点类别
        pageSize: 30, // poi检索每页数量
        pageIndex: 1,
        extensions: 'all',
      });

      // 地图加载完成事件
      map.on('complete', () => {
        chooseIndex.value = null;
        const center = map.getCenter();
        searchNearBy(center.lat, center.lng, true);
      });

      // 地图移动结束事件
      map.on('moveend', () => {
        const center = map.getCenter();
        addMarker(center.lng, center.lat);
        if (isSelMove) {
          // poi列表点击的移动
          isSelMove = false;
        } else {
          // 拖动或搜索建议的移动
          showIconAnim.value = false;
          nextTick(() => {
            setTimeout(() => {
              showIconAnim.value = true;
            }, 0);
          });
          searchNearBy(center.lat, center.lng);
        }
      });
    });
  };
  /**
   * @description: poi检索
   * @param {*} lat
   * @param {*} lng
   * @param {*} force
   * @return {*}
   */
  const searchNearBy = (lat: any, lng: any) => {
    if (!placeSearch) {
      return;
    }
    // this.poiLoading = true;
    placeSearch.searchNearBy('', [lng, lat], 1000, (status: any, result: any) => {
      // this.poiLoading = false;
      if (status === 'complete') {
        const data = result.poiList.pois.filter((p: any) => p.location !== undefined);
        if (chooseSuggestion) {
          // 如果选中的搜索建议不在poi列表中则添加
          if (data.length === 0 || data[0].name !== chooseSuggestion.name) {
            data.unshift({ ...chooseSuggestion });
          }
          chooseSuggestion = null;
        } else {
          chooseIndex.value = null;
        }

        poiData.value = data;
        // v3.17 标准地址库-地址拼接省市区
        poiData.value.forEach((item) => {
          item.pname = item.pname || '';
          item.cityname = item.cityname || '';
          item.adname = item.adname || '';
          item.address = item.address || '';
          item.address = `${item.pname}${item.cityname}${item.adname}${item.address}`;
        });
      }
    });
  };

  /**
   * @description: poi列表选中
   * @param {*} index
   * @return {*}
   */
  const choose = (index: number) => {
    chooseIndex.value = index;
    isSelMove = true;
    // this.showIconAnim = false;
    // nextTick(() => {
    //     setTimeout(() => {
    //         this.showIconAnim = true;
    //     }, 0);
    // });
    const point = poiData.value[index].location;
    map.setZoomAndCenter(chooseZoom, [point.lng, point.lat]);
  };

  /**
   * @description: 添加marker
   * @param {*} lng
   * @param {*} lat
   * @return {*}
   */
  const addMarker = (lng: string, lat: string) => {
    // centerMarker.setMap(map);
    centerMarker.setPosition([lng, lat]);
    map.add(centerMarker);
  };

  /**
   * @description: 获取搜索数据
   * @param {*} keywords
   * @param {*} callback
   * @return {*}
   */
  const searchSuggestions = (keywords: string, callback: any) => {
    if (!keywords) {
      return callback(suggestionData);
    }
    autoComplete.search(keywords, (status: any, result: any) => {
      if (status === 'complete') {
        suggestionData = result.tips.filter((item) => item.location);

        suggestionData.forEach((item: any) => {
          item.address = item.address || '';
          item.district = item.district || '';
          item.address = `${item.district}${item.address}`;
        });
        callback(suggestionData);
      }
    });
  };

  /**
   * @description: 点击选择
   * @param {*} item
   * @return {*}
   */
  const onSuggestionChoose = (item: any) => {
    suggestionKeyWord.value = item.name;
    chooseSuggestion = item;
    chooseIndex.value = 0;

    const point = item.location;
    if (point) {
      map.setZoomAndCenter(chooseZoom, [point.lng, point.lat]);
      addMarker(point.lng, point.lat);
    }
  };

  /**
   * @description: 确定
   * @return {*}
   */
  const doneMap = () => {
    // 地图中心点
    // const center = { ...map.getCenter() };
    // getByLatLng({ lat: center.lat, lng: center.lng }).then((res) => {
    //   // console.log('接口获取的值', res);
    //   if (res.result) {
    //     location = {
    //       country: res.result?.country?.i18nName,
    //       province: res.result?.province?.i18nName || '',
    //       city: res.result?.city?.i18nName,
    //       district: res.result?.district?.i18nName,
    //       address: res.result.raw?.formattedAddress,
    //       lat: center.lat,
    //       lng: center.lng,
    //     };
    //   }
    //   // 选中则取高德地图返回的address
    //   if (chooseIndex.value || chooseIndex.value === 0) {
    //     location.address = poiData.value[chooseIndex.value].address || '';
    //   }
    //   suggestionKeyWord.value = '';
    //   emit('done-map', location);
    // });

    // TODO 由于数据规范性,需获取经纬度后重新请求三级地址
    if (chooseIndex.value || chooseIndex.value === 0) {
      location.address = poiData.value[chooseIndex.value].address || '';
    }
    console.log('选中的地址', location);
    suggestionKeyWord.value = '';
    emit('done-map', location);
  };

  onMounted(() => {
    setTimeout(() => {
      initMap(location);
    }, 200);
  });
</script>

<style scoped lang="scss">
  #container {
    margin: 0;
    padding: 0;
    width: 100%;
    height: calc(100% - 50px);
  }
  .search-container {
    display: flex;
    justify-content: space-between;
    margin-bottom: 10px;
    :deep(.el-autocomplete) {
      width: 80%;
    }
  }
  .map-body {
    display: flex;
    height: 450px;
    &__left {
      width: 70% !important;
      height: 100% !important;
    }
    &__right {
      flex: 1;
    }
  }

  /* 地图图标跳动动画 */
  .ele-map-picker-anim-bounce {
    animation: elePickerAnimBounce 500ms;
    animation-direction: alternate;
  }

  @keyframes elePickerAnimBounce {
    0%,
    60%,
    75%,
    90%,
    to {
      transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    }
    0%,
    to {
      transform: translate3d(0, 0, 0);
    }
    25% {
      transform: translate3d(0, -10px, 0);
    }
    50% {
      transform: translate3d(0, -20px, 0);
    }
    75% {
      transform: translate3d(0, -10px, 0);
    }
  }

  .ele-map-picker-main-icon {
    width: 26px;
    position: absolute;
    left: 50%;
    bottom: 50%;
    margin-left: -13px;
  }

  /* poi列表 */
  .ele-map-picker-poi-list {
    overflow: auto;
    width: 300px;
  }
  .ele-map-picker-poi-item {
    position: relative;
    padding: 8px 30px 8px 44px;
    border-bottom: 1px solid hsl(0deg 0% 60% / 15%);
    cursor: pointer;
  }
  .ele-map-picker-poi-item:hover {
    background-color: hsl(0deg 0% 60% / 5%);
  }
  .ele-map-picker-poi-item-icon {
    position: absolute;
    top: 50%;
    left: 14px;
    transform: translateY(-50%);
    font-size: 20px;
    opacity: 0.4;
  }
  .ele-map-picker-poi-item-title {
    font-size: 14px;
  }
  .ele-map-picker-poi-item-address {
    margin-top: 2px;
    font-size: 12px;
    opacity: 0.6;
  }
  .ele-map-picker-poi-item .ele-map-picker-poi-item-check {
    position: absolute;
    top: 50%;
    right: 7px;
    display: none;
    font-size: 16px;
    color: #3b74ff;
    transform: translateY(-50%);
  }
  .ele-map-picker-poi-item-active .ele-map-picker-poi-item-check {
    display: block;
  }
</style>
<style lang="scss">
  .map-body {
    .amap-icon {
      display: none;
    }
  }
</style>

到此这篇关于Vue3实现地图选点组件的示例代码的文章就介绍到这了,更多相关Vue3地图选点组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文