Vue3 + Element-Plus 对接高德地图实现搜索提示选址、点击地图选址、自我定位功能(最新)

Vue3 + Element-Plus 对接高德地图实现搜索提示选址、点击地图选址、自我定位功能(最新)

  • 1、效果展示
  • 2、实现代码
    • 2.1 GaoDeMap.vue
    • 2.2 SystemDialog.vue
    • 2.3 UnusedList.vue.vue

1、效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、实现代码

2.1 GaoDeMap.vue


<template>
  <div style="width: 100%;">
    <div class="search-box">
      <el-select v-model="address" clearable placeholder="请输入位置关键词" style="width: 240px;" :remote-method="remoteMethod"
        filterable remote @change="currentSelect" class="one-text" size="default">
        <el-option v-for="(item, index) in areaList" :key="index" :label="item.district + item.name"
          :value="item.district + item.name">
          <span>{{ item.district }}</span> <span>{{ item.name }}</span>
        </el-option>
      </el-select>

      <el-button type="success" v-if="addressGet" class="address">{{ addressGet.split(",")[0] }}</el-button>
    </div>
    <div id="container" class="map"></div>
  </div>
</template>

<script setup>
import { reactive, ref, toRefs, onMounted, nextTick, defineProps, defineEmits } from 'vue';
import AMapLoader from "@amap/amap-jsapi-loader";
// 定义 props 和 emits
const emits = defineEmits(['address']);
const props = defineProps({
  addressClick: Function,
})
onMounted(() => {
  window._AMapSecurityConfig = {
    securityJsCode: '你的安全密钥', // https://console.amap.com/dev/key/app   绑定的服务为 Web端
  }
  initMap()
})
const addressGet = ref("")

const state = reactive({
  map: null,
  placeSearch: null,
  autoComplete: null,
  marker: null,
  form: {
    address: '',
    lng: '',
    lat: '',
  },
  areaList: [],
  address: ''
})

const { areaList, address } = toRefs(state)
function initMap(arr) {
  AMapLoader.load({
    key: "安全密钥左边的key的值",	// https://console.amap.com/dev/key/app   绑定的服务为 Web端
    version: "2.0",
    plugins: ["AMap.ToolBar", "AMap.ControlBar", 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Geocoder', 'AMap.Marker', 'AMap.Geolocation'],
  }).then((AMap) => {
    state.map = new AMap.Map('container', {
      viewMode: "3D",  //  是否为3D地图模式
      zoom: 15,
      center: arr,
      resizeEnable: true
    });
    // 地图放大缩小插件
    let toolBar = new AMap.ToolBar({
      position: {
        top: '120px',
        right: '51px'
      }
    })
    // 3D地图插件
    let controlBar = new AMap.ControlBar({
      position: {
        top: '20px',
        right: '20px',
      },
    });

    state.geoCoder = new AMap.Geocoder({
      city: '010', //城市设为北京,默认:“全国”
      radius: 1000 //范围,默认:500
    });

    // 正向地理编码
    state.geocoder = new AMap.Geocoder({
      city: state.address
    })
    // 定位
    let geolocation = new AMap.Geolocation({
      enableHighAccuracy: true, // 是否使用高精度定位,默认:true
      timeout: 10000, // 超过10秒后停止定位,默认:5s
      position: {
        top: '300px',
        right: '30px',
      }, // 定位按钮的停靠位置
      buttonOffset: new AMap.Pixel(10, 20), // 定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
      zoomToAccuracy: true, // 定位成功后是否自动调整地图视野到定位点
    });
    // 监听定位按钮的点击事件
    geolocation.on('complete', (result) => {
      console.log('定位成功:', result);
      // 处理定位成功的逻辑
      console.log(result.position.lng, result.position.lat);

      // 使用高德地图 JavaScript API 的坐标转换服务将 WGS84 坐标转换为 GCJ02 坐标
      AMap.convertFrom([result.position.lng, result.position.lat], 'gps', (status, result) => {
        if (status === 'complete' && result.locations.length > 0) {
          const gcj02Lng = result.locations[0].lng;
          const gcj02Lat = result.locations[0].lat;
          // 解析定位结果为中文地址
          let lnglat = [gcj02Lng, gcj02Lat];
          console.log(gcj02Lng, gcj02Lat);
          state.geoCoder.getAddress(lnglat, (status, addressResult) => {
            if (status === 'complete' && addressResult.regeocode) {
              let formattedAddress = addressResult.regeocode.formattedAddress;
              console.log('解析后的地址:', formattedAddress);
              // 在这里处理解析后的地址
              addressGet.value = formattedAddress;
              state.address = formattedAddress;

              // 返回给父组件的值
              emits("address", `${formattedAddress},${gcj02Lng},${gcj02Lat}`);
            }
          });
          // 这里可以继续处理转换后的坐标数据,例如显示标记点等
        } else {
          console.error('Coordinate conversion failed.');
        }
      });
    });

    geolocation.on('error', (error) => {
      console.error('定位失败:', error);
      // 处理定位失败的逻辑
    });

    state.autoComplete = new AMap.AutoComplete({ city: '全国' });
    state.map.setDefaultCursor("pointer"); // 使用CSS默认样式定义地图上的鼠标样式
    state.map.on('click', (e) => { // 点击地图事件
      if (!e && !e.lnglat) {
        return
      }
      state.form.lng = e.lnglat.lng
      state.form.lat = e.lnglat.lat
      removeMarker() // 先删除地图上标记点
      setMapMarker() // 在添加新的标记点
    })
    state.map.addControl(toolBar);   // 添加右上角的放大缩小
    state.map.addControl(controlBar);   // 添加右上角的放大缩小
    state.map.addControl(geolocation);   // 添加右上角的放大缩小
    // 监听定位成功事件
  }).catch((e) => {
    console.error(e);  //加载错误提示
  }).finally(() => {
    removeMarker()
    setMapMarker()
  })

}

function setMapMarker() {
  if (state.form.lng == '' && state.form.lat == '') {
    return
  }
  state.map.setFitView()
  state.marker = new AMap.Marker({
    map: state.map,
    position: [state.form.lng, state.form.lat],
  })
  toGetAddress()
  state.map.setFitView()
  state.map.add(state.marker)
}

function removeMarker() {
  if (state.marker) {
    state.map.remove(state.marker)
  }
}

function toGetAddress() {
  let lnglat = [state.form.lng, state.form.lat]
  state.geoCoder.getAddress(lnglat, (status, result) => {
    if (status === 'complete' && result.regeocode) {
      props.addressClick(result, state.form.lng, state.form.lat) // 返回位置信息以及经纬度
      addressGet.value = `${result.regeocode.formattedAddress},${state.form.lng},${state.form.lat}`
    }
  })
}

function remoteMethod(query) {
  if (query !== '') {
    setTimeout(() => {
      state.autoComplete.search(query, (status, result) => {
        state.areaList = result.tips
      })
    }, 500)
  } else {
    state.areaList = []
  }
}
function currentSelect(val) {
  if (!val) {
    return
  }
  toGetCoordinate(val)
}

function toGetCoordinate(address) {
  state.geocoder.getLocation(address, function (status, result) {
    if (status === 'complete' && result.info === 'OK') {
      initMap([result.geocodes[0].location.lng, result.geocodes[0].location.lat])
      state.form.lng = result.geocodes[0].location.lng
      state.form.lat = result.geocodes[0].location.lat
      state.form.address = `${result.geocodes[0].formattedAddress}`

      // 返回给父组件的值
      emits("address", `${result.geocodes[0].formattedAddress},${result.geocodes[0].location.lng},${result.geocodes[0].location.lat}`);
    }
  })
  nextTick(function () {
    removeMarker()
    setMapMarker()
  })
}

function fixed(lng, lat) {
  initMap([lng, lat])
  state.form.lng = lng
  state.form.lat = lat
}


// 暴露方法
defineExpose({
  fixed,
  toGetCoordinate
});
</script>



<style scoped lang="scss">
.map {
  width: 100%;
  height: 400px;
  padding-top: 20px;
}

#container {
  margin-top: 20px;
  border-radius: 5px;
}

.search-box {
  display: flex;

}

.address {
  margin-left: 20px;
}
</style>

2.2 SystemDialog.vue

<!--
 * @Date: 2024-03-25 16:55:53
 * @LastEditors: zhong
 * @LastEditTime: 2024-04-18 11:21:23
 * @FilePath: \app-admin\src\components\SystemDialog\SystemDialog.vue
-->
<template>
    <div>
        <el-dialog :model-value="props.visible" :title="props.title" :width="props.width + 'px'"
            :height="props.height + 'px'" :before-close="onClose" :close-on-click-modal="false">
            <!-- 内容显示区 -->
            <div class="container" :style="{ height: height + 'px' }">
                <slot name="content"></slot>
            </div>
            <template #footer>
                <div class="dialog-footer">
                    <el-button @click="onClose" type="danger">取消</el-button>
                    <el-button type="success" @click="onConfirm">
                        确认
                    </el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
// 定义弹窗数据类型
interface dialogProps {
    title: string,
    visible: boolean,
    width: number,
    height: number
}

// 接收父组件传递的参数
const props = withDefaults(defineProps<dialogProps>(), {
    title: "新增",
    visible: false,
    width: 630,
    height: 280
})
// 注册事件
const emit = defineEmits(["onClose", "onConfirm"])

// 关闭事件
const onClose = () => {
    emit("onClose");
}
// 提交事件
const onConfirm = () => {
    emit("onConfirm");
}
</script>


<style lang="scss" scoped>
.container {
    overflow-x: inherit;
    overflow-y: auto;
}

:deep(.el-dialog) {
    padding: 0;
    border-top-left-radius: 7px !important;
    border-top-right-radius: 7px !important;

    .el-dialog__header {
        margin-right: 0px;
        padding-top: 10px;
        border-top-left-radius: 7px !important;
        border-top-right-radius: 7px !important;
        background-color: #009688 !important;

        .el-dialog__title {
            padding: 16px;
            color: #FFF;
            font-size: 16px;
            font-weight: 600;
        }
    }

    .el-dialog__headerbtn {
        .el-dialog__close {
            color: #FFF;
        }
    }

    .el-dialog__body {
        padding: 10px;
    }

    .el-dialog__footer {
        border-top: 1px solid #e8eaec !important;
        padding: 10px;
    }
}
</style>

2.3 UnusedList.vue.vue

<template>
    <SystemDialog :title="name" :visible="mapOpen" :height="400" :width="800" @on-close="closeAddress" @on-confirm="commitAddress">
        <template v-slot:content>
              <el-form-item label="宝贝位置">
                  <GaoDeMap :addressClick="addressClick" ref="mapRef" @address="getAddress"></GaoDeMap>
              </el-form-item>
          </template>
        </SystemDialog>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import SystemDialog from '@/components/SystemDialog/SystemDialog.vue';
import GaoDeMap from '@/components/Map/GaoDeMap.vue'

const mapRef = ref('') as any
const name = ref("宝贝位置选取");
const mapOpen = ref(false)

const address = ref("");
const getAddress = (data: string) => {
    if (data != "") {
        address.value = data;
        addGoodParm.address = data;
    }
}

// 提交地图地址
const commitAddress = () => {
    // 提交地图地址
    addGoodParm.address = address.value;
    // 关闭地图
    mapOpen.value = false;
    console.log(address, addGoodParm.address);

}

// 关闭地图
const closeAddress = () => {
    addGoodParm.address = "";
    address.value = "";
    // 关闭地图
    mapOpen.value = false;
}
// 地图选位置
function addressClick(item: { regeocode: { addressComponent: { city: string; province: string; district: string; }; formattedAddress: string; }; }, lng: number, lat: number) {
    address.value = `${item.regeocode.formattedAddress}, ${lng}, ${lat}`;
}

onMounted(() => {
    // 这里传后台获取的经纬度
    mapRef.value.fixed(100.179253, 27.096143)
})
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/576083.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【个人博客搭建】(11)swagger添加jwt信息

这个主要是为了方便使用swagger时&#xff0c;能更好的带入我们的token。 ps&#xff1a;如果使用其他第三方api工具&#xff08;apipost、postman等&#xff09;则不需要。 &#xff08;当然&#xff0c;不用不能没有&#xff0c;是吧&#xff09; 1、在AddSwaggerGen内添加…

文件权限管理

文件权限管理 1. 权限对象 权限对象含义u属主&#xff0c;所有者g属组o其他人 2. 权限类型 权限类型含义值r读权限4w写权限2x执行权限1 3. 修改文件属主及属组 命令:chown(change own)更改文件或目录属主与属组名 3.1 修改文件属主与属组 只修改属主&#xff1a;chown $…

【数据结构】链表的中间节点

给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 Definition for singly-linked list.struct ListNode {int val;struct ListNode *next;};typedef struct ListNode ListNode; struct ListNode…

美国服务器vs香港服务器,哪个网站部署打开更快一些?

网站打开速度受多种因素影响&#xff0c;包括服务器地理位置、网络质量、带宽等。用户距离服务器越近&#xff0c;访问速度越快。对于中国大陆用户而言&#xff0c;香港的服务器可能会提供更快的网站访问体验&#xff0c;因为香港距离大陆较近&#xff0c;且网络连接通常较好。…

python高阶函数:zip()

概述与基本用法 zip() 是 Python 内置函数之一&#xff0c;用于将多个可迭代对象打包成一个元组序列&#xff0c;然后返回一个迭代器。它可以接受任意数量的可迭代对象作为参数&#xff0c;并将它们的元素按顺序一一对应地打包成元组。 以下是 zip() 函数的基本用法&#xff…

2024年视频号小店来了,这次是不是新的电商风口?

大家好&#xff0c;我是电商糖果 2024年电商行业可以说大地震了&#xff0c;为什么这么说呢&#xff1f; 因为一个非常有实力的新平台出现了。 它就是微信视频号推出的视频号小店&#xff0c;也可以理解为腾讯旗下的电商平台。 视频号的出现是腾讯为了对标抖音&#xff0c;和…

使用LSTM网络实现文本情感分析

一、实验目的&#xff1a; 理解循环神经网络的基本概念和原理&#xff1b;了解循环神经网络处理文本数据的基本方法&#xff1b;掌握循环神经网络处理文本数据的实践方法&#xff0c;并实现文本情感分析任务。 实验要求&#xff1a; 使用Keras框架定义并训练循环神经网络模型…

链游:未来游戏发展的新风向

链游&#xff0c;即区块链游戏的一种&#xff0c;是一种将区块链技术与游戏玩法相结合的创新型游戏。它利用区块链技术的特性&#xff0c;如去中心化、可追溯性和安全性&#xff0c;为玩家提供了一种全新的游戏体验。链游通常采用智能合约来实现游戏的规则和交易系统&#xff0…

B站无限评论暴力截留协议及教程

B站无限评论暴力截留协议及教程 B站无限评论暴力截留协议及教程&#xff0c;需要抓CK &#xff0c;教程里面有讲如何抓取 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码&#xff1a;0b8x

森林消防隔膜泵的应用与前景——恒峰智慧科技

随着全球气候变暖&#xff0c;森林火灾频发&#xff0c;给生态环境和人类安全带来严重威胁。为有效应对这一挑战&#xff0c;森林消防领域不断引入新技术、新装备。其中&#xff0c;隔膜泵作为一种高效、可靠的消防设备&#xff0c;正逐渐受到广泛关注。本文将探讨森林消防隔膜…

c++在visual studio上的默认配置

右键 新建项 右键源文件 属性

5、Flink事件时间之Watermark详解

1&#xff09;生成 Watermark 1.Watermark 策略简介 为了使用事件时间语义&#xff0c;Flink 应用程序需要知道事件时间戳对应的字段&#xff0c;即数据流中的每个元素都需要拥有可分配的事件时间戳。 通过使用 TimestampAssigner API 从元素中的某个字段去访问/提取时间戳。…

Gitflow实操以及代码审查Pull Request操作

1.背景 之前一直有用过gitflow&#xff0c;但是一直没有归纳技术&#xff0c;另一方面也是每个团队用到的gitflow都不一致。而最近做项目要用gitflow&#xff0c;趁此机会分享一下gitflow的操作。 2.gitflow介绍 用git一直有一个问题&#xff0c;就是怎么保证代码稳定性&…

LeetCode in Python 48. Rotate Image/Matrix (旋转图像/矩阵)

旋转图像/矩阵的重点是寻找旋转前后对应位置的坐标关系。 示例&#xff1a; 图1 旋转图像/矩阵的输入输出示意图 代码&#xff1a; class Solution:def rotate(self, matrix):n len(matrix)for i in range(n // 2):for j in range(i, n - 1 - i):topleft matrix[i][j]ma…

ArcGIS小技巧——由图片创建点符号

一张合格的专题地图&#xff0c;除了内容的准确性和丰富性以外&#xff0c;美观性也是必不可少的。而Arcgis符号库中的符号非常有限&#xff0c;有时并不能很好的展现出地图要素的特点。因此&#xff0c;学会自定义符号就显得尤其重要了。今天&#xff0c;小编将结合实例&#…

AI大模型探索之路-训练篇4:大语言模型训练数据集概览

文章目录 前言一、常用的预训练数据集1、网页2、书籍3、维基百科4、代码5、混合型数据集 二、常用微调数据集1、指令微调数据集1.1 自然语言处理任务数据集1.2 日常对话数据集1.3 合成数据集 2、人类对齐数据集 前言 在人工智能领域&#xff0c;构建强大的AI系统的关键步骤之一…

synchronized 之谜

序言 本文给大家介绍一下 synchronized 关键字的部分原理。 一、内存中的 Java 对象 class A {private String attr; }先引入一个问题&#xff1a;上面类 A 有一个属性 attr。当类 A 实例化之后的对象在内存中是如何表示的呢&#xff1f; 在内存中&#xff0c;Java 对象由三…

Prompt Engineering,提示工程

什么是提示工程&#xff1f; 提示工程也叫【指令工程】。 Prompt发送给大模型的指令。比如[讲个笑话]、[用Python编个贪吃蛇游戏]、[给男/女朋友写情书]等看起来简单&#xff0c;但上手简单精通难 [Propmpt]是AGI时代的[编程语言][Propmpt]是AGI时代的[软件工程][提示工程]是…

Docker与Linux容器:“探索容器化技术的奥秘”

目录 一、Docker概述 二、容器技术的起源&#xff1a; 三、Linux容器 四、Docker的出现 五、Docker容器特点&#xff1a; 六、Docker三大概念&#xff1a; 容器&#xff1a; 镜像&#xff1a; 仓库&#xff1a; 七、Docker容器常用命令 一、Docker概述 在云原生时代&…

漫谈车辆诊断之DTC的状态位

搞车辆诊断测试的&#xff0c;离不开对DTC的状态位的测试 DTC的状态位是8个bit&#xff0c;每个bit代表不同的意思&#xff0c;每个bit置1或者置0都要满足一定的条件 初学者&#xff0c;很容易被这个搞得头很大 今天我们就来详细拆解一下&#xff0c;扫除你心中的疑惑 我们以…