在vue中使用qqmap腾讯地图

本文介绍如何在前端项目中集成腾讯地图API,通过封装组件实现地图显示,并设置地图中心位置及缩放级别等基本配置。

在index.html的head里引入依赖

  <script charset="utf-8"
          src="https://map.qq.com/api/js?v=2.exp&key=自己腾讯地图的key&libraries=drawing,geometry"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

在组件里使用(封装成组件)

<template>
    <div ref='thismap' id="map"></div>
</template>
<script>
export default {
  props: {
    mapLoaded: {
      type: Function,
      default: () => {

      }
    }
  },
  data() {
    return {
      map: null
    };
  },
  methods: {
    async init() {
      // 创建地图
      this.map = new qq.maps.Map(this.$refs.thismap, {
        // 地图的中心地理坐标
        center: new qq.maps.LatLng(32.15079, 118.71084),
        // 地图缩放级别
        zoom: 16,
        // 地图的默认鼠标指针样式 pointer crosshair
        draggableCursor: undefined,
        // 拖动地图时的鼠标指针样式
        draggingCursor: 'pointer',
        // 该key绑定的style1对应于经典地图样式,若未绑定将弹出无权限提示窗
        mapStyleId: 'style1'
      });
      window.qmap = this.map;
    }
  },
  mounted() {
    this.init();
  }
};
</script>
<style lang="less" scoped>
  #map {
    width: 100%;
    height: 100%;
  }
</style>

在需要使用的地方引用

<template>
	<div class="map-right">
		 <qqmap />
	</div>
</template>
<script>
import qqmap from "@/components/map/qqmap"
export default {
  components: {
    qqmap
  }
};
</script>
<think>我们正在使用 RuoYi Vue3 版本(基于 Vue3 和 Vite)集成腾讯地图QQMap)。根据用户提供的引用片段,我们看到在 uniapp 中配置了腾讯地图的 key,但我们的场景是 RuoYi Vue3 的 Web 应用,因此需要按照 Web 的方式集成。 步骤概述: 1. 引入腾讯地图 JavaScript API SDK 2. 创建地图组件 3. 在需要的地方使用地图组件(例如在表单中选择位置) 4. 处理坐标和地址的反解析(逆地理编码) 详细步骤: 1. **申请腾讯地图 Key** 前往腾讯位置服务(https://lbs.qq.com/)申请开发者密钥(Key)。申请时注意设置安全域名(如本地开发用localhost,生产环境用你的域名)。 2. **在项目中引入 SDK** 在 `public/index.html` 中通过 script 标签引入腾讯地图 SDK(注意:Vue3 项目通常使用 Vite,也可以使用 npm 包,但腾讯地图官方推荐直接引入脚本)。 在 `public/index.html` 的 `<head>` 或 `<body>` 中添加: ```html <script src="https://map.qq.com/api/gljs?v=1.exp&key=YOUR_KEY"></script> ``` 将 `YOUR_KEY` 替换为你的实际密钥。 3. **创建地图组件** 在 `src/components` 目录下创建 `QQMap.vue` 组件。 ```vue <template> <div class="map-container"> <div id="map" ref="mapContainer"></div> <div class="map-controls"> <el-button type="primary" @click="confirmLocation">确认位置</el-button> <el-button @click="closeMap">关闭</el-button> </div> </div> </template> <script setup> import { ref, onMounted, defineEmits, defineProps } from 'vue'; const props = defineProps({ latitude: Number, longitude: Number, address: String }); const emit = defineEmits(['selectMap', 'closeMap']); const mapContainer = ref(null); let map = null; let marker = null; let selectedLocation = ref(null); onMounted(() => { initMap(); }); const initMap = () => { // 确保 TMap 已经加载(全局变量 TMap) if (window.TMap) { // 如果有传入的经纬度,则使用传入的,否则使用默认(北京) const center = props.latitude && props.longitude ? new TMap.LatLng(props.latitude, props.longitude) : new TMap.LatLng(39.908823, 116.397470); // 初始化地图 map = new TMap.Map(mapContainer.value, { center: center, zoom: 12 }); // 初始化标记 marker = new TMap.MultiMarker({ map: map, styles: { marker: new TMap.MarkerStyle({ width: 25, height: 35, anchor: { x: 12.5, y: 35 } }) }, geometries: [{ position: center }] }); // 地图点击事件 map.on('click', (evt) => { selectedLocation.value = evt.latLng; marker.setGeometries([{ position: evt.latLng }]); }); } else { console.error('TMap SDK 尚未加载完成,请稍后再试'); } }; // 确认位置 const confirmLocation = async () => { if (selectedLocation.value) { // 获取地址(逆地理编码) try { const address = await getAddress(selectedLocation.value); emit('selectMap', { latitude: selectedLocation.value.lat, longitude: selectedLocation.value.lng, address: address }); } catch (error) { console.error('逆地理编码失败', error); // 如果逆地理编码失败,至少返回坐标 emit('selectMap', { latitude: selectedLocation.value.lat, longitude: selectedLocation.value.lng, address: '未知地址' }); } } }; // 逆地理编码 const getAddress = (latLng) => { return new Promise((resolve, reject) => { const geocoder = new TMap.service.Geocoder(); geocoder.getAddress({ location: latLng }, (err, res) => { if (err || !res || !res.result) { reject(err || new Error('逆地理编码失败')); } else { resolve(res.result.address); } }); }); }; // 关闭地图 const closeMap = () => { emit('closeMap'); }; </script> <style scoped> .map-container { position: relative; height: 500px; } #map { width: 100%; height: 100%; } .map-controls { position: absolute; bottom: 20px; right: 20px; z-index: 1000; } </style> ``` 4. **在业务页面中使用地图组件** 例如,我们想在用户管理页面中添加一个地址选择功能。 ```vue <template> <div class="app-container"> <!-- 其他表单内容 --> <el-form :model="form" label-width="80px"> <el-form-item label="地址"> <el-input v-model="form.address" placeholder="点击选择位置" @click="openMap" readonly> </el-input> </el-form-item> </el-form> <el-dialog title="选择位置" v-model="mapVisible" width="80%" append-to-body> <QQMap v-if="mapVisible" :latitude="form.latitude" :longitude="form.longitude" :address="form.address" @selectMap="handleSelectMap" @closeMap="mapVisible = false" /> </el-dialog> </div> </template> <script setup> import { ref } from 'vue'; import QQMap from '@/components/QQMap.vue'; const form = ref({ latitude: null, longitude: null, address: '' }); const mapVisible = ref(false); const openMap = () => { mapVisible.value = true; }; const handleSelectMap = (location) => { form.value = { ...form.value, latitude: location.latitude, longitude: location.longitude, address: location.address }; mapVisible.value = false; }; </script> ``` 5. **注意事项** - **密钥安全**:不要将密钥直接暴露在代码中,生产环境建议通过环境变量注入。在 RuoYi Vue3 中,可以在 `.env.production` 等环境文件中设置,然后在构建时替换。 - **坐标系**:腾讯地图使用 GCJ-02 坐标系(火星坐标系),如果后台使用其他坐标系(如 WGS-84),需要进行转换。可以在前端使用转换库(如 gcoord)进行转换,或者在后端转换。 - **性能**:地图组件在打开时才渲染,使用 `v-if` 控制。 - **移动端适配**:如果需要适配移动端,注意地图容器的高度和触摸事件。 6. **环境变量配置(可选)** 在 `.env.development` 和 `.env.production` 中添加: ``` VITE_QQMAP_KEY=你的密钥 ``` 然后在 `public/index.html` 中通过环境变量注入: ```html <script src="https://map.qq.com/api/gljs?v=1.exp&key=%VITE_QQMAP_KEY%"></script> ``` 注意:Vite 在构建时不会替换 public 目录下的文件中的环境变量,因此我们需要使用一个插件(如 vite-plugin-html)来支持。或者,我们可以在入口文件中动态注入,但这样可能会影响地图的加载顺序。 另一种方法:不在 public/index.html 中引入,而是在组件中动态加载: ```js // 在组件中 const loadScript = (src) => { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); }; onMounted(async () => { if (!window.TMap) { await loadScript(`https://map.qq.com/api/gljs?v=1.exp&key=${import.meta.env.VITE_QQMAP_KEY}`); } initMap(); }); ``` 这样我们就可以使用环境变量了。但注意,这种方式需要确保地图组件的加载顺序。 根据以上步骤,我们可以在 RuoYi Vue3 项目中集成腾讯地图,并实现位置选择功能。 相关问题: 1. 如何在 RuoYi Vue3 中安全地管理腾讯地图的密钥? 2. 腾讯地图的坐标如何与后台的坐标系进行转换? 3. 如何优化地图组件在 RuoYi 项目中的加载速度? 4. 在 RuoYi 中,如何将地图选点功能封装成表单控件?</think>### RuoYi Vue3 集成腾讯地图完整指南 #### 一、前期准备 1. **申请腾讯地图 Key** - 访问[腾讯位置服务官网](https://lbs.qq.com/) - 创建应用 → 启用 WebService API 和 JavaScript API - 配置安全域名(本地开发用 `localhost`,生产环境用实际域名) 2. **配置环境变量** 在 `.env.production` 和 `.env.development` 中添加: ```ini VITE_QQMAP_KEY = "你的腾讯地图KEY" ``` #### 二、集成步骤 ##### 1. 引入地图 SDK 在 `index.html` 中动态加载 SDK: ```html <head> <script> window.QQMapKey = "<%= VITE_QQMAP_KEY %>"; </script> <script src="https://map.qq.com/api/gljs?v=1.exp&key=<%= VITE_QQMAP_KEY %>" defer> </script> </head> ``` ##### 2. 创建地图组件 (`src/components/map/QQMap.vue`) ```vue <template> <div class="map-container"> <div id="qq-map" ref="mapContainer"></div> <div class="map-controls"> <el-button type="primary" @click="confirmLocation"> <i class="ri-check-line"></i> 确认位置 </el-button> <el-button @click="$emit('close')"> <i class="ri-close-line"></i> 关闭 </el-button> </div> </div> </template> <script setup> import { ref, onMounted, watch } from 'vue' import { ElMessage } from 'element-plus' const props = defineProps({ lat: { type: Number, default: 39.908823 }, lng: { type: Number, default: 116.397470 }, address: String }) const emit = defineEmits(['confirm', 'close']) const mapContainer = ref(null) const map = ref(null) const marker = ref(null) const selectedLocation = ref(null) // 初始化地图 const initMap = async () => { if (!window.TMap) { ElMessage.error('地图SDK加载失败,请刷新重试') return } const center = new TMap.LatLng(props.lat, props.lng) map.value = new TMap.Map(mapContainer.value, { center: center, zoom: 13, viewMode: '2D' }) // 添加标记 marker.value = new TMap.MultiMarker({ map: map.value, styles: { marker: new TMap.MarkerStyle({ width: 25, height: 35, anchor: { x: 12, y: 35 } }) }, geometries: [{ position: center }] }) // 点击事件 map.value.on('click', async (evt) => { selectedLocation.value = evt.latLng marker.value.setGeometries([{ position: evt.latLng }]) }) } // 获取地址信息 const getAddress = (latLng) => { return new Promise((resolve) => { new TMap.service.Geocoder().getAddress({ location: latLng }, (err, res) => { resolve(err ? '未知地址' : res.result.address) }) }) } // 确认位置 const confirmLocation = async () => { if (!selectedLocation.value) { ElMessage.warning('请先在地图上选择位置') return } const address = await getAddress(selectedLocation.value) emit('confirm', { lat: selectedLocation.value.lat, lng: selectedLocation.value.lng, address }) } onMounted(() => { // 确保SDK加载完成 if (window.TMap) { initMap() } else { window.addEventListener('qqmap-loaded', initMap) } }) </script> <style scoped> .map-container { position: relative; height: 70vh; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } #qq-map { width: 100%; height: 100%; } .map-controls { position: absolute; bottom: 20px; right: 20px; z-index: 1000; display: flex; gap: 10px; } </style> ``` ##### 3. 在业务页面中使用 (`src/views/system/user.vue`) ```vue <template> <div class="app-container"> <el-form :model="form" label-width="100px"> <el-form-item label="所在位置"> <el-input v-model="form.address" placeholder="点击选择位置" readonly @click="mapVisible = true"> <template #append> <el-button :icon="MapLocation" @click="mapVisible = true" /> </template> </el-input> </el-form-item> </el-form> <!-- 地图弹窗 --> <el-dialog v-model="mapVisible" title="位置选择" width="80%" destroy-on-close append-to-body> <QQMap :lat="form.lat" :lng="form.lng" @confirm="handleMapConfirm" @close="mapVisible = false" /> </el-dialog> </div> </template> <script setup> import { ref } from 'vue' import { MapLocation } from '@element-plus/icons-vue' import QQMap from '@/components/map/QQMap.vue' const mapVisible = ref(false) const form = ref({ lat: null, lng: null, address: '' }) const handleMapConfirm = (location) => { form.value = { ...location } mapVisible.value = false // 这里可添加数据保存逻辑 } </script> ``` #### 三、关键配置说明 1. **坐标系处理**: - 腾讯地图使用 **GCJ-02** 坐标系 - 若后端使用 WGS-84 坐标系,需进行转换: ```javascript // 安装转换库 npm install gcoord // 在提交数据时转换 import gcoord from 'gcoord' const wgsPoint = gcoord.transform( [form.value.lng, form.value.lat], gcoord.GCJ02, gcoord.WGS84 ) ``` 2. **性能优化**: ```vue <QQMap v-if="mapVisible" ... /> ``` 使用 `v-if` 确保地图组件在需要时加载 3. **移动端适配**: ```css @media (max-width: 768px) { .map-container { height: 60vh; } .map-controls { bottom: 10px; right: 10px; } } ``` #### 四、常见问题解决 1. **地图不显示**: - 检查 Key 的域名白名单是否包含本地地址 - 确保 SDK 加载完成后再初始化地图 ```javascript window.addEventListener('qqmap-loaded', initMap) ``` 2. **逆地理编码失败**: - 添加错误重试机制 ```javascript const getAddress = async (latLng, retry = 3) => { try { // ...逆地理编码逻辑 } catch (err) { if (retry > 0) return getAddress(latLng, retry - 1) return '地址解析失败' } } ``` 3. **内存泄漏**: ```vue <script setup> onBeforeUnmount(() => { if (map.value) { map.value.destroy() map.value = null } }) </script> ``` > 实际部署时建议将地图密钥存储在环境变量中,避免硬编码暴露安全风险[^1]。
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值