首页前端工具函数uni-app 开发小程序 地图选点

uni-app 开发小程序 地图选点

分类前端工具函数时间2025-10-23 17:17:26发布RustStream浏览278
摘要:单独封装成一个页面 // mapselectorpage.vue import MapSelector from './components/map-selector/index.vue' export default { components: { MapSelector }, methods: { onConfirm(address { // 这里可以将选中的地址保存到Vuex或全局变量 <!--autointro-->...

单独封装成一个页面

// mapselectorpage.vue
<template>
  <map-selector @confirm="onConfirm"></map-selector>
</template>

<script>
import MapSelector from './components/map-selector/index.vue'

export default {
  components: { MapSelector },
  methods: {
    onConfirm(address) {
      // 这里可以将选中的地址保存到Vuex或全局变量
      this.$store.commit('setSelectedAddress', address)
      // 返回上一页
      // uni.navigateBack()
    }
  }
}
</script>

组件代码

<template>
  <view class="map-selector">
    <!-- 搜索框区域 -->
    <view class="search-bar">
      <u-search
        v-model="searchKeyword"
        placeholder="请输入地点搜索"
        :clearable="true"
        @custom="handleSearch"
        @confirm="handleSearch"
        @clear="handleClear"
        :input-style="{ fontSize: '28rpx' }"
      ></u-search>
    </view>

    <!-- 搜索结果列表 -->
    <!--  -->
    <view 
      class="search-result" 
      v-if="showResult && resultList.length"
    >
      <view 
        class="result-item" 
        v-for="(item, index) in resultList" 
        :key="index"
        @click="handleSelectResult(item)"
      >
        <u-icon name="map-marker" color="#246ED2" size="32rpx"></u-icon>
        <view class="result-info">
          <view class="result-title">{{ item.title }}</view>
          <view class="result-address">{{ item.address }}</view>
        </view>
      </view>
    </view>

    <!-- 地图容器 -->
    <view class="map-container">
      <!-- 微信小程序地图 -->
      <map
        :longitude="longitude"
        :latitude="latitude"
        :markers="markers"
        :show-location="true"
        @markertap="handleMarkerTap"
        @regionchange="handleRegionChange"
        style="width: 100%; height: 100%;"
      ></map>
    </view>

    <!-- 确认按钮 -->
    <view class="confirm-btn" @click="handleConfirm">
      <u-button 
        type="primary" 
        shape="circle"
        :disabled="!selectedAddress"
      >
        确认选择
      </u-button>
    </view>
  </view>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  name: 'MapSelector',
  data() {
    return {
      // 基础参数
      isMiniProgram: uni.getSystemInfoSync().platform === 'devtools' || uni.getSystemInfoSync().platform === 'mp-weixin',
      searchKeyword: '',
      showResult: false,
      resultList: [],

      // 地图参数
      longitude: 116.39747, // 默认经度(北京)
      latitude: 39.90882,  // 默认纬度
      markers: [], // 地图标记点
      selectedAddress: null, // 选中的地址信息
    }
  },
  computed: {
    ...mapGetters(['userLocation'])
  },
  onLoad() {
    // 初始化获取当前位置
    this.getUserLocation()
  },
  methods: {
    // 获取用户当前位置
    getUserLocation() {
      uni.getLocation({
        type: 'gcj02',
        success: (res) => {
          this.longitude = res.longitude
          this.latitude = res.latitude
          this.updateMarker(res.longitude, res.latitude, '当前位置')
        },
        fail: (err) => {
          console.error('获取位置失败', err)
          uni.showToast({ title: '请允许获取位置信息', icon: 'none' })
        }
      })
    },

    // 搜索地点
    handleSearch() {
      if (!this.searchKeyword.trim()) return
      // uni.chooseLocation    打开地图选择位置。
      if (this.isMiniProgram) {
        uni.chooseLocation({
          keyword: this.searchKeyword,
          success: (res) => {
            this.updateMarker(res.longitude, res.latitude, res.name)
            this.selectedAddress = {
              name: res.name,
              address: res.address,
              longitude: res.longitude,
              latitude: res.latitude
            }
            this.showResult = false
          }
        })
      } 
    },

    // 选择搜索结果
    handleSelectResult(item) {
      this.updateMarker(item.longitude, item.latitude, item.title)
      this.selectedAddress = {
        name: item.title,
        address: item.address,
        longitude: item.longitude,
        latitude: item.latitude
      }
      this.showResult = false
      this.searchKeyword = ''
    },

    // 清除搜索
    handleClear() {
      this.searchKeyword = ''
      this.resultList = []
      this.showResult = false
    },

    // 更新地图标记
    updateMarker(longitude, latitude, title) {
      this.markers = [{
        id: 1,
        longitude,
        latitude,
        title,
        iconPath: '/static/images/marker.webp', // 可替换为自己的标记图标
        width: 40,
        height: 40,
        anchor: { x: 0.5, y: 0.5 }
      }]
    },

    // 地图标记点击
    handleMarkerTap() {
        console.log('handle')
      if (this.selectedAddress) {
        uni.showToast({
          title: `已选中: ${this.selectedAddress.name}`,
          icon: 'none'
        })
      }
    },

    // 地图视野变化 (小程序)
    handleRegionChange(e) {
      if (e.type === 'end') {
        this.mapCtx = wx.createMapContext('map')
        this.mapCtx.getCenterLocation({
          success: (res) => {
            this.longitude = res.longitude
            this.latitude = res.latitude
            this.getAddressByLocation(res.longitude, res.latitude)
          }
        })
      }
    },

    // 通过经纬度获取地址信息
    getAddressByLocation(lng, lat) {
      if (this.isMiniProgram) {
        wx.reverseGeocoder({
          location: { longitude: lng, latitude: lat },
          success: (res) => {
            const address = res.result
            this.selectedAddress = {
              name: address.formatted_addresses.recommend,
              address: address.address,
              longitude: lng,
              latitude: lat
            }
            this.updateMarker(lng, lat, address.formatted_addresses.recommend)
          }
        })
      }
    },

    // 确认选择
    handleConfirm() {
      if (this.selectedAddress) {
        // 触发父组件事件,返回选中的地址信息
        this.$emit('confirm', this.selectedAddress)
        // 关闭当前页面(如果是模态框形式可注释)
        uni.navigateBack()
      } else {
        uni.showToast({ title: '请先选择地点', icon: 'none' })
      }
    }
  }
}
</script>

<style scoped>
.map-selector {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #fff;
}

.search-bar {
  padding: 20rpx;
  background-color: #fff;
  z-index: 10;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}

.search-result {
  position: absolute;
  top: 120rpx;
  left: 0;
  right: 0;
  max-height: 400rpx;
  overflow-y: auto;
  background-color: #fff;
  z-index: 9;
  box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.1);
}

.result-item {
  display: flex;
  align-items: center;
  padding: 20rpx 30rpx;
  border-bottom: 1rpx solid #f5f5f5;
}

.result-info {
  margin-left: 15rpx;
}

.result-title {
  font-size: 28rpx;
  color: #333;
}

.result-address {
  font-size: 24rpx;
  color: #999;
  margin-top: 5rpx;
}

.map-container {
  /* flex: 1;
  position: relative; */
  width: 100%;
  height: calc(100% - 120rpx - 120rpx);
}

.confirm-btn {
  padding: 30rpx;
  background-color: #fff;
}
</style>

注意

微信小程序 chooseLocation 无结果:
需在 app.json (manifest.json 源码视图)中声明权限(否则接口会静默失败):

"mp-weixin" : {
        "requiredPrivateInfos" : [ "chooseLocation", "getLocation" ]
    },

本文链接:https://blog.smallhao.fun/?id=39 转载需授权!

分享到:

Chen’Blog版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

封装 预览组件(Vue3) uni-app 使用 高德SDK 获取地理位置

游客 回复需填写必要信息
召唤伊斯特瓦尔