信息发布→ 登录 注册 退出

vue3 腾讯地图设置签到范围并获取经纬度的实现代码

发布时间:2026-01-11

点击量:
目录
  • 一.使用说明
  • 二.自定义组件
    • 1.此组件取名MapRadiusSetting.vue
    • 2.使用
  • 三.效果
    • 四.计算两个经纬度的距离方法

      一.使用说明

      • 先腾讯地图注册获取一个密钥;
      • 在项目的开始文件index.html头部引入script链接;
      <script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&libraries=service&key=你的密钥"></script>

      在项目中调用自定义组件

      二.自定义组件

      1.此组件取名MapRadiusSetting.vue

      <template>
         <div class="content">
           <div :id="`mapContent-${eleUuid}`"></div>
           <div class="iptContent">
             <el-form ref="formRef" :inline="true" :model="state.map" :rules="props.required?state.rules:{}">
               <el-form-item label="名称地点:" prop="address" style="width:100%">
                 <el-input v-model="state.map.address" maxlength="100" show-word-limit></el-input>
               </el-form-item>
               <el-form-item label="签到范围:" prop="radius">
                 <el-input-number v-model="state.map.radius" :min="50" :max="9999" :precision="0" :step="1" @change="handleChange" />
               </el-form-item>
               <div id="location"></div>
             </el-form>
           </div>
         </div>
      </template>
      <script lang="ts">
      import { defineComponent } from 'vue'
      export default defineComponent({
       name: 'mapRadiusSetting',
      })
      </script>
      <script lang="ts" setup>
      import { reactive, ref, unref, onMounted, nextTick ,watch} from 'vue'
      import { ElForm, ElMessage, ElMessageBox } from 'element-plus'
      import { uuid } from "vue-uuid";
      const props = defineProps({
       map:{
         type: Object,
         default: {},
       },
       required:{
         type:Boolean,
         default:false
       }
      })
      const eleUuid = ref('')
      const formRef = ref(ElForm)
      const rangeDistance = (rule: any, value: any, callback: any) => {
       if (!value) {
         callback(new Error('必填'))
       } else if (value && !/^[1-9]\d{0,3}$/.test(value)) {
         callback(new Error('请输入四位以内正整数'))
       } else {
         callback()
       }
      }
      const state:any = reactive({
       map: {
         latitude: '',
         longitude: '',
         radius: 500,
         address:'',
         uuid: '',
       },
       rules: {
         address: [{ required: true, message: '请输入', trigger: ['change','blur'] }],
         radius: [{ required: true, validator: rangeDistance, trigger: 'change' }],
       },
      })
      var TMap = (window as any).TMap // 引入地图
      var randerCircle:any = {}
      var randerMap:any = {}
      var markerLayer:any = {}
      var geocoderTools:any = {}; // 新建一个正逆地址解析类
      const initMap = (mapData: any) => {
       let center = new TMap.LatLng(mapData.latitude, mapData.longitude)
       //初始化地图
       randerMap = new TMap.Map(`mapContent-${eleUuid.value}`, {
         rotation: 0, //设置地图旋转角度
         pitch: 0, //设置俯仰角度(0~45)
         zoom: 14, //设置地图缩放级别
         center: center, //设置地图中心点坐标
       })
       geocoderTools = new TMap.service.Geocoder();
       //画图圆
       randerCircle = new TMap.MultiCircle({ 
         map:randerMap,
         styles: { // 设置圆形样式
           'circle': new TMap.CircleStyle({
             'color': 'rgba(41,91,255,0.16)',
             'showBorder': true,
             'borderColor': 'rgba(41,91,255,1)',
             'borderWidth': 2,
           }),
         },
         geometries: [{
           styleId: 'circle',
           center: center,
           radius: state.map.radius,
         }],
       });
       //创建并初始化marker
       markerLayer = new TMap.MultiMarker({
         id: 'marker-layer',
         map: randerMap,
         //文字标记数据
         geometries: [
           {
             id: mapData.uuid,
             position: new TMap.LatLng(mapData.latitude, mapData.longitude),
           },
         ],
       })
       randerMap.on('click',  (evt: any)=> {
         const lat = evt.latLng.getLat().toFixed(6)
         const lng = evt.latLng.getLng().toFixed(6)
         state.map.latitude = lat
         state.map.longitude = lng
         //地图移到中间
         const center2 = new TMap.LatLng(state.map.latitude, state.map.longitude)
         // randerMap.setCenter(center2);
         //更新或新增标记点
         if (mapData.longitude && mapData.latitude) {
           markerLayer.setGeometries([])
           markerLayer.updateGeometries({
             id: mapData.uuid,
             position: new TMap.LatLng(lat, lng),
           })
         } else {
           markerLayer.add({
             position: evt.latLng,
           })
         }
         //重新画圈
         randerCircle.setGeometries([
           {
             center: new TMap.LatLng(state.map.latitude, state.map.longitude),
             radius: state.map.radius,
             id: mapData.uuid,
             position: new TMap.LatLng(state.map.latitude, state.map.longitude),
           }
         ])
         //获取地址对应的文字
         randerLocationToAddressMap(state.map.latitude, state.map.longitude);
       })
      }
      //范围变化
      const handleChange = () => {
       if(state.map.latitude && state.map.longitude && state.map.radius && randerCircle){
         //重新画圈
         randerCircle.setGeometries([
           {
             center: new TMap.LatLng(state.map.latitude, state.map.longitude),
             radius: state.map.radius,
             id: state.map.uuid,
             position: new TMap.LatLng(state.map.latitude, state.map.longitude),
           }
         ])
       }
      }
      //输入文字转化成坐标,重新渲染
      const randerAddressToLocationMap = () => {
       // markerLayer.setGeometries([]);
       // 将给定的地址转换为坐标位置
       geocoderTools
         .getLocation({ address: state.map.address })
         .then((result:any) => {
           console.log("获取的坐标是啥",result.result.location,state.map.address);
           state.map.latitude = result.result.location.lat
           state.map.longitude = result.result.location.lng
           //地图移到中间
           const center2 = new TMap.LatLng(state.map.latitude, state.map.longitude)
           randerMap.setCenter(center2);
           //更新或新增标记点
           if (state.map.longitude && state.map.longitude) {
             markerLayer.updateGeometries({
               id: state.map.uuid,
               position: new TMap.LatLng(state.map.latitude, state.map.longitude),
             })
           } else {
             markerLayer.add({
               position: new TMap.LatLng(state.map.latitude, state.map.longitude),
             })
           }
           //重新画圈
           randerCircle.setGeometries([
             {
               center: new TMap.LatLng(state.map.latitude, state.map.longitude),
               radius: state.map.radius,
               id: state.map.uuid,
               position: new TMap.LatLng(state.map.latitude, state.map.longitude),
             }
           ])
           // document.getElementById(
           //   'location'
           // )!.innerHTML = result.result.location.toString();
           // 显示坐标数值
           console.log("变化的值",result);
         });
      }
      //将坐标转化成文字
      const randerLocationToAddressMap = (latitude:any,longitude:any) => {
       var location = new TMap.LatLng(latitude, longitude);
       geocoderTools
         .getAddress({ location: location }) // 将给定的坐标位置转换为地址
         .then((result:any) => {
           // 显示搜索到的地址
           console.log("result",result);
           if(result.result && result.result.address) state.map.address = result.result.address
         });
      }
      //提交验证
      const submitForm = (callback:any) => {
       const form = unref(formRef)
       form.validate((valid: any) => {
         if (valid) {
           console.log(state.map)
           if(callback)callback(state.map)
         }
       })
      }
      defineExpose({submitForm})
      // 关闭弹窗 清空地图容器 刷新坐标接口
      const handleClose = () => {
       (document.getElementById(`mapContent-${eleUuid.value}`) as any).innerHTML = ''
       // formRef.value.resetFields() //不起效
      }
      watch(()=>props.map,()=>{
       if(props.map && props.map.uuid){
         // eleUuid.value = props.map.uuid
         state.map = Object.assign({},state.map,props.map)
         handleClose()
         nextTick(() => {
           initMap(state.map)
         })
       } 
      })
      onMounted(() => {
         eleUuid.value = uuid.v4().replace(/-/g, '');
         state.map = {
           // 默认值为成都市
           latitude: '30.633',
           longitude: '104.077',
           radius:  50,
           uuid:  '1',//必须要有值,否则都是新增
           address:''
         }
         if(props.map && props.map.uuid) state.map = Object.assign({},state.map,props.map)
         // handleClose()
         nextTick(() => {
           initMap(state.map)
         })
      })
      </script>
      <style lang="scss" scoped>
      :deep(.el-dialog) {
       .el-dialog__header {
         border-bottom: 1px solid #eef5f9;
         padding-bottom: 20px;
       }
      }
      #mapContent {
       /*地图(容器)显示大小*/
       width: 100%;
       height: 400px;
       margin-top: 10px;
       cursor: url(https://mapapi.qq.com/web/lbs/static/lbs_home/icon/point1.ico) 12.5 12.5, crosshair;
       :deep(a) {
         img {
           display: none !important;
         }
       }
       :deep(.logo-text) {
         display: none !important;
       }
       :deep(.tmap-scale-control) {
         display: none;
       }
      }
      .iptContent {
       margin-top: 10px;
       .btn {
         text-align: right;
         border-top: 1px solid #eef5f9;
         padding-top: 20px;
         button {
           width: 100px;
           :deep(.el-form-item--small.el-form-item) {
             margin-bottom: 0;
           }
         }
       }
      }
      </style>

      2.使用

      <MapRadiusSetting :map="state.formData" ref="mapRadiusSettingRef" required :key="refreshKey"/>
      import MapRadiusSetting  from '@/你的自定义组件路径/components/MapRadiusSetting.vue'
      const mapRadiusSettingRef:any = ref({})
      //提交触发验证
      const submit = ()=>{
      	mapRadiusSettingRef.value.submitForm((res:any)=>{
      	//调用你那边后端接口,保存经纬度 地址 签到范围等
      	//如果res.uuid == '1'说明是新增 ,等于那边的一个uuid,那么是修改
      	})
      }
      // 数据结构要求
      state.formData = {
      	// 默认值为成都市
            latitude: '30.633',
            longitude: '104.077',
            radius:  50,
            uuid:  '1',//必须要有值,否则都是新增
            address:''
       }

      三.效果

      四.计算两个经纬度的距离方法

      //地理位置经纬度距离
      const calculateDistance = (lat1: any, lon1: any, lat2: any, lon2: any, setDistance: number) => {
          const radians = Math.PI / 180
          const R = 6371 // 地球半径,单位为千米
          const deltaLat = (lat2 - lat1) * radians
          const deltaLon = (lon2 - lon1) * radians
          lat1 = lat1 * radians
          lat2 = lat2 * radians
          const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2)
          const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
          const distance = R * c
          return parseInt((distance * 1000).toString()) < setDistance
      }
      //使用 判断两个经纬度是不是在500米范围内 在范围内就true 不在就是false 
      console.log(calculateDistance(lat1, lon1, lat2, lon2,500)
      在线客服
      服务热线

      服务热线

      4008888355

      微信咨询
      二维码
      返回顶部
      ×二维码

      截屏,微信识别二维码

      打开微信

      微信号已复制,请打开微信添加咨询详情!