vue3+taro+NutUl+高德地图微信小程序sdk实现微信小程序地图功能

156 阅读4分钟

homePages/address/index页面遇到的问题

  1. @regionchange.prevent ="debouncedHandleInput"方法里面不能更改地图经纬度,否则会一直调用debouncedHandleInput
//页面  homePages/address/index
<template>
  <view class="map_box">
      <Notify ref="notify" />
      <view class="search">
          <view class="text">取消</view>
          <view class="inputSearch" @click="mapShowFun()">
            <Search2/>
            <text> 搜索地点</text>
          </view>
          <view class="text" @click="IsPtInPolyFun()">确定</view>
      </view>
      <view class="mapId" >
        <map 
          id="mapId" 
          ref="map" 
          :zoom="data.zoom" 
          :longitude="data.longitude" 
          :latitude="data.latitude" 
          :scale="data.scale" 
          :polygons="data.polygons"
          @tap="debouncedMap"
          @regionchange.prevent ="debouncedHandleInput"
        ></map>
        <view class="icon" >
          <Locationg3 color="#fa2c19"/>
        </view>
      </view>
      <view class="pol" v-if="data.poisData.length!=0">
          <view class="poisData" v-for="(v,i) in data.poisData" :key="i" @click="listAdress(v,i)"> 
              <view class="left" >
                  <p style="font-size: 28rpx;color: #3d3d3d;">{{ v.name }}</p>
                  <p style="font-size: 25rpx;margin-top: 10rpx;color: #8c8c8c;">{{ v.pname }}{{ v.cityname}}{{ v.adname }}{{ v.address }}</p>
              </view>
              <view class="icon" v-show="index==i">
                <Success color="green"/>
              </view>
          </view>
      </view>
  </view>
</template>
<script lang="ts" setup>
import { ref, onMounted,reactive } from 'vue';
import { Locationg3 } from '@nutui/icons-vue-taro'
import { Success } from "@nutui/icons-vue-taro";
import { useRouter } from "@tarojs/taro";
import { Search2 } from '@nutui/icons-vue-taro'
import Notify from "../../componets/notify.vue";
const notify: any = ref(null); //获取子组件
let notification = reactive({
  cellClick: Function
})
var amap = require("../../libs/amap-wx.130.js");//高德地图微信小程序sdk
const router = useRouter();
const isList=ref(false)
const index=ref(-1)//当前选中的位置下标
const myAmapFun=new amap.AMapWX({key:'06a6cbc4426074d3e0675e6a9fc45699'})
//地图参数
const data=reactive({ 
  longitude: null as any, // 经度
  latitude: null as any, // 纬度
  scale: 14, // 缩放级别
  zoom: 5,//控制地图缩放级别
  center: []as any,//中心点
  poisData:[]as any,
  polygons: [{
    points: [
    { longitude: 114.974305, latitude:35.825551 }, //上左点
    { longitude: 114.902708, latitude: 35.631925},//下左点
    { longitude:115.30217, latitude: 35.669553 },//下右点
    { longitude: 115.313675, latitude:35.785582}, //上右点
    ],
    // fillColor: '#FFA07A33',
    strokeColor: '#FFA07A',
    strokeWidth: 5
  },{
    points: [
    { longitude: 115.09, latitude:35.92 }, //上左点
    { longitude: 115.09, latitude: 35.89},//下左点
    { longitude:115.13, latitude: 35.88 },//下右点
    { longitude: 115.13, latitude:35.91}, //上右点
    ],
    // fillColor: '#FFA07A33',
    strokeColor: '#FFA07A',
    strokeWidth: 5
  },
]
})
//经纬度
const longitude=ref()
const latitude=ref()
//地图移动获取中心点经纬度
const onRegionChange=(e)=>{
  longitude.value = e.detail.centerLocation.longitude;
  latitude.value =  e.detail.centerLocation.latitude;
  if (e.type=='end'&&!isList.value){
    getPoiAround(e.detail.centerLocation.latitude,e.detail.centerLocation.longitude)
    index.value=-1
  }
  isList.value=false
}
const handleMapTap=(e)=> {
      if (e.type === 'tap') {
        longitude.value = e.detail.longitude;
        latitude.value =  e.detail.latitude;
        data.latitude= e.detail.latitude,
        data.longitude=  e.detail.longitude
        getPoiAround(e.detail.latitude,e.detail.longitude)
      }
    }
//获取自己所在地址周围的pol
const getPoiAround=(latitude?:any,longitude?:any)=>{ 
  myAmapFun.getPoiAround({ 
    location: `${latitude},${longitude}`,
    success: function(res:any){
      data.poisData=res.poisData
    },
    fail: function(info){
        //失败回调
      console.log(info)
    }
  })
}
// 创建防抖函数
function debounce(func, delay) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), delay);
  };
}
const debouncedHandleInput = debounce(onRegionChange, 800);
const debouncedMap = debounce(handleMapTap, 200);


onMounted(() => {
  //获取子组件方法
  let {latitude ,longitude} = router.params
 notification = notify.value.customState.methods
 if(latitude&&longitude){//判断是不是从搜索页面进来的
    console.log('有经纬度');
    data.latitude= latitude,
    data.longitude= longitude
    getPoiAround(latitude ,longitude)
 }else{
    wx.getLocation({
      type: 'wgs84',
      success: function(res:any) {
        console.log(res,'获取当前位置');
        data.latitude=res.latitude
        data.longitude=res.longitude
      },
      fail: function(error) {
        console.error('获取位置失败', error);
      }
    });
    myAmapFun.getRegeo({  //获取自己所在地址的定位
      success: function(res:any){
        //成功回调
        console.log(data,'定位')
        data.latitude= res[0].latitude,
        data.longitude= res[0].longitude
      },
      fail: function(info){
        //失败回调
        console.log(info)
      }
    })
    getPoiAround()
 }
})

// 点击搜索栏input框跳转搜索页面
const mapShowFun=()=>{
  wx.redirectTo({
    url: '/homePages/selectedPosition/index',
  });
}
//点击列表切换地图位置
const listAdress=(v?:any,i?:any)=>{
  isList.value=true
  index.value=i
  const res=v.location.split(",")
  data.latitude=res[1]
  data.longitude=res[0]
  latitude.value=res[1]
  longitude.value=res[0]
}

//判断用户选择的位置是否在多边形里面
const IsPtInPoly= (lat, lng, points)=> {
  let x = lng;
  let y = lat;
  let n = points.length;
  let inside = false;
  for (let i = 0, j = n - 1; i < n; j = i++) {
    let xi = points[i].longitude, yi = points[i].latitude;
    let xj = points[j].longitude, yj = points[j].latitude;
    let intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
    if (intersect) inside = !inside;
  }
  return inside;
}

const IsPtInPolyFun=()=>{
  let isInAnyPolygon = data.polygons.some(polygon => {
    return IsPtInPoly(latitude.value, longitude.value, polygon.points);
  });
  if(!isInAnyPolygon){
    notification.cellClick('warning', '位置不在范围内,请重新选择')
  }
}
</script>
<style lang="scss">
.map_box{
width: 100vw;
height: 100vh;
position: relative;
.search{
    width: 100vw;
    position: absolute;
    z-index: 1;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 20rpx;
    box-sizing: border-box;
    background-color: #fff;
    .inputSearch{
      flex: 1;
      display: flex;
      align-items: center;
      background-color: #f4f4f4 !important;
      padding: 10rpx 10rpx;
      border-radius: 30rpx;
      color: #999;
      text{
        margin-left: 10rpx;
      }
    }
    .text{
      font-size: 25rpx;
      white-space: nowrap;
      width: 100rpx;
      text-align: center;
    }
    .nut-input{
      flex: 1;
      width: 100vw;
      background-color: #f4f4f4;
      padding: 0 !important;
      margin: 0 20rpx;
    }
    .input{
      background-color: #f4f4f4;
      color: #999;
      border-radius: 15rpx;
    }
  }
}
.mapId{
  width: 100%;
  height: 50%;
  position: relative;
  #mapId{
    width: 100% !important;
    height: 100% !important;
  }
  .icon {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 50px;
    height: 50px;
    z-index:1;
  }
}
#container{
  width: 100%;
  height: 40%;
}
.pol{
  width: 100%;
  height: 50%;
  overflow: auto;
  padding: 0 20rpx;
  .poisData{
      display: flex;
      justify-content: space-between;
      border-bottom: 1px solid #ccc;
      padding: 20rpx;
      align-items: center;
  }
}
</style>

页面样式

image.png

点击搜索地点跳转搜索页面

//页面 homePages/selectedPosition/index
<template>
  <view class="search_box">
      <Notify ref="notify" />
      <view class="search" >
        <view class="inputSearch" hover-class="none" hover-stop-propagation="false">
          <Search/>
          <input ref="searchBar" class="input" v-model="ssValue" placeholder=" 搜索地点" @input="debouncedHandleInput" />
        </view>
        <view class="text" @click="routerAddress()">取消</view>
      </view>
      <view class="pol" v-if="data.tips.length!=0">
        <view class="poisData" v-for="(v,i) in data.tips" :key="i" @click="routerAddress(v)"> 
            <view class="icon">
              <Search/>
            </view>
            <view class="left" >
                <p style="font-size: 28rpx;color: #3d3d3d;">{{ v.name }}</p>
                <p style="font-size: 25rpx;margin-top: 10rpx;color: #8c8c8c;">{{ v.district }}{{ v.address}}</p>
            </view>

        </view>
    </view>
  </view>
  </template>
  <script lang="ts" setup>
  import { nextTick, ref, onMounted,reactive } from 'vue';
  import { Search } from "@nutui/icons-vue-taro";
  import Notify from "../../componets/notify.vue";
  const notify: any = ref(null); //获取子组件
  let notification = reactive({
    cellClick: Function
  })
  var amap = require("../../libs/amap-wx.130.js");
  const searchBar=ref()
  const ssValue=ref('')
  // 创建防抖函数
function debounce(func, delay) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), delay);
  };
}
const routerAddress=(v?:any)=>{
  if(!v.location){
    notification.cellClick('warning', '选择详细地址')
    return 
  }
  if(v){
    const a=v.location.split(",")
    wx.redirectTo({
      url: `/homePages/address/index?longitude=${a[0]}&latitude=${a[1]}`,
    });
  }else{
    wx.redirectTo({
      url: `/homePages/address/index`,
    });
  }
}
  const data=reactive({ 
    longitude: null as any, // 经度
    latitude: null as any, // 纬度
    tips:[]as any,
  })
  const myAmapFun=new amap.AMapWX({key:'1c66d0626db992de0fca5ee12b49ad96'})
  onMounted(() => {
    notification = notify.value.customState.methods
    console.log(searchBar.value,'searchBar.value');
    nextTick(()=>{
        searchBar.value.focus();
    })
  myAmapFun.getRegeo({  //获取自己所在地址的定位
    success: function(res:any){
      //成功回调
      console.log(data,'定位')
      data.latitude= res[0].latitude,
      data.longitude= res[0].longitude
    },
    fail: function(info){
      //失败回调
      console.log(info)
    }
  })
  })
  const searchVal=(event)=>{
    console.log(event.target.value,ssValue.value);
    myAmapFun.getInputtips({  //官方接口中有三个参数,主要需要传keywords使用  citylimit是分页参数
      keywords: event.target.value,
      city: '濮阳市',
      citylimit: true,
      location:data.longitude + ',' + data.latitude,
      success: function(res){
        console.log(res);
        if(res && res.tips){
            data.tips=res.tips
        }
      }
    })
  }
  const debouncedHandleInput = debounce(searchVal, 500);

  </script>
  <style lang="scss" >
  .search_box{
    width: 100vw;
    height: 100vh;
    position: relative;
    .search{
      width: 100vw;
      position: absolute;
      top: 0;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 20rpx 20rpx;
      box-sizing: border-box;
      .inputSearch{
        flex: 1;
        display: flex;
        align-items: center;
        background-color: #f4f4f4 !important;
        padding: 0 10rpx;
        border-radius: 30rpx;
        .input{
          padding: 10rpx;
          flex: 1;
        }
      }
      .text{
        font-size: 25rpx;
        white-space: nowrap;
        width: 100rpx;
        text-align: center;
      }
      .nut-input{
        flex: 1;
        width: 100vw;
        background-color: #f4f4f4;
        padding: 0 !important;
        margin: 0 20rpx;
      }
      .input{
        background-color: #f4f4f4;
        color: #999;
        border-radius: 15rpx;
      }
    }
  }
  .pol{
  width: 100%;
  height: 100vh;
  overflow: auto;
  padding: 70rpx 20rpx 20rpx 20rpx;
  .poisData{
      display: flex;
      border-bottom: 1px solid #ccc;
      padding: 20rpx;
      align-items: center;
      .icon{
        margin-right: 20rpx;
      }
  }
  }
  </style>

页面样式

image.png