uni-app map marker 上的自定义气泡 customCallout显示气泡不对

uni-app map marker 上的自定义气泡 customCallout显示气泡不对

开发环境 版本号 项目创建方式
Windows 10 专业版 22H2 HBuilderX

产品分类:uniapp/App

PC开发环境操作系统:Windows

手机系统:Android

手机系统版本号:Android 16

手机厂商:小米

手机机型:863904075488527

页面类型:vue

vue版本:vue3

打包方式:云端

项目创建方式:HBuilderX

示例代码:

<template>  
    <view class="pMap">  
        <!--  -->  
        <map class="pMap-box"  
            id="mapContext"  
            :longitude="mapInstance.longitude"   
            :latitude="mapInstance.latitude"   
            :markers="markers"  
            :polyline="polyline"              
            :show-location="true"  
            :scale="mapScale"  
            :include-points="includePoints"  
            :polygon="polygon"  
            :style="{width:windowWidth+'px',height: '500rpx'}">  
            <cover-view class="pMap-box-callout" slot="callout">  
                <block v-for="(item,index) in markers" :key="index" >  
                    <cover-view  
                        v-if="item.customCallout"  
                        class="pMap-box-callout-list"    
                        :marker-id="item.id">  
                        <cover-view class="pMap-box-callout-list-item">  
                            <cover-view class="pMap-box-callout-list-item-center">  
                                <cover-view class="pMap-box-callout-list-item-center-tag">  
                                    {{index == 0?'发':index == markers.length-1?'收':''}}  
                                </cover-view>  
                                <cover-view class="pMap-box-callout-list-item-center-txt">  
                                    {{item.title}}  
                                </cover-view>  
                            </cover-view>  
                        </cover-view>  
                    </cover-view>  
                </block>  
            </cover-view>  
        </map>  
    </view>  
</template>  

<script setup>  
import startIcon from '@/static/image/order/map.png'  
import processIcon from '@/static/image/order/car.png'  

import {ref,getCurrentInstance,computed,defineExpose,onMounted, nextTick} from 'vue';  
import {Config} from "@/http/config";  

import {systemStore} from '@/store/system'  

const {windowWidth} = systemStore();  

const _this = getCurrentInstance();  

const mapContext = ref(null);  

onMounted(()=>{  
    mapContext.value = uni.createMapContext('mapContext',_this);  
})  

const props = defineProps({  
    routePoints: {  
        type: Array,  
        default: []  
    }  
})  

// 获取标记点图标  
const getMarkerIconByStatus = (status) => {  
    switch (status) {  
        case 'start':  
            return startIcon;  
        case 'end':  
            return startIcon;  
        case 'process':  
            // return null;  
            return processIcon;  
        default:  
            return startIcon;  
    }  
}  

// 缓存节点颜色配置  
const statusColorMap =(status)=> {  
    switch (status) {  
        case 'start':  
            return '#52c41a';  
        case 'end':  
            return '#52c41a';  
        case 'process':  
            return '#1890ff';  
        default:  
            return '#faad14';  
    };  
};  

// 构建标记点  
const markers = computed (() => {  
    if (!props.routePoints || props.routePoints.length === 0) {  
        return []  
    }  
    return props.routePoints.map((marker, index) => {  
        // 根据状态设置标记点图标  
        let iconPath = getMarkerIconByStatus(marker.status);  
        let customCallout = undefined;  
        let width = '10px';  
        let height = '10px';  
        switch (marker.status) {  
            case 'start':  
                customCallout={  
                    anchorY: 0,  
                    anchorX: 0,  
                    display:"ALWAYS",//一直展示  
                }  
                width = '28px';  
                height = '34px';  
                break;  
            case 'end':  
                customCallout ={  
                    anchorY: 0,  
                    anchorX: 0,  
                    display:"ALWAYS",//一直展示  
                }  
                width = '28px';  
                height = '34px';  
                break;  
            case 'process':  
                width = '20px';  
                height = '15px';  
                break;  
        }  
        const markerId = `marker_${index}`;  
        // marker.id ||  
        return {  
            id: index || markerId,  
            longitude: marker.longitude,  
            latitude: marker.latitude,  
            title: marker.title,  
            iconPath,  
            width,  
            height,  
            customCallout,  
            joinCluster: true,  
            zIndex:1,  
            ...marker  
        }  
    })  
})  

// 构建路线  
const polylineId = ref('logistics-route');  
const polyline = computed(() => {  
    if (!props.routePoints || props.routePoints.length < 2) {  
        return []  
    }  
    const points = props.routePoints.map(point => ({  
        longitude: point.longitude,  
        latitude: point.latitude  
    }))  

    return [{  
        id: polylineId.value,  
        points,  
        color: '#007AFF',  
        width: 6,  
        dottedLine: false,  
        borderWidth: 1,  
        borderColor: '#0056b3'  
    }]  
})  

// 要显示在可视区域内的坐标点列表  
const includePoints = computed(()=>{  
    const points =  props.routePoints.map(point => ({  
        longitude: point.longitude,  
        latitude: point.latitude  
    }))  
    return points;  
})  

// 闭合多边形  
const polygon = computed(()=>{  
    const points =  props.routePoints.map(point => ({  
        longitude: point.longitude,  
        latitude: point.latitude  
    }))  
    return {  
        points,  
        strokeWidth:1,  
        strokeColor:'red',  
        fillColor:'lightgreen'  
    };  
})  

// 设置地图中心  
const mapInstance = computed (() => {  
    // const mid = props.routePoints[Math.floor(props.routePoints.length / 2)];  
    const mid = props.routePoints[0];  
    return {  
        longitude: mid.longitude,  
        latitude: mid.latitude  
    }  
})  

// 缩放级别  
const mapScale = ref(12);  

const markerList = ref([])  
const drawMap=()=>{  
    // nextTick(()=>{  
    //  setTimeout(()=>{  
    //      markerList.value = markers.value;  
    //      mapContext.value.includePoints({  
    //          points:includePoints.value,  
    //          padding: [40, 40, 40, 40],  
    //          success:(res)=>{  
    //              console.log('success==>',res);  
    //          },  
    //          fail:(err)=>{  
    //              console.log('fail==>',err);  
    //          },  
    //          complete:(res) => {  
    //              console.log('complete', res)  
    //          }  
    //      })  
    //  },0)  
    // })  
}  
defineExpose({  
    drawMap  
})  
</script>  

<style lang="scss" scoped>  
.pMap {  
    overflow: hidden;  

    &-box {  
        width: 100%;  
        height: 500rpx;  

        &-callout{  
            position: relative;  
            &-list{  
                position: relative;  
                &-item{  
                    position: relative;  
                    display: inline-block;  
                    border-radius: 6px;  
                    background: rgba(255, 255, 255, 1);  
                    padding: 8rpx 20rpx;  
                    overflow: hidden;  
                    &-center{  
                        display: flex;  
                        &-tag{  
                            border-radius: 4px;  
                            background: rgba(207, 19, 0, 0.4);  
                            // width: 36rpx;  
                            // height: 36rpx;  
                            // line-height: 36rpx;  
                            padding: 6rpx 10rpx;  
                            // margin: 6rpx 10rpx;  
                            color: rgba(207, 19, 0, 1);  
                            font-size: 20rpx;  
                            font-weight: 500;  
                            overflow: hidden;  
                        }  
                        &-txt{  
                            margin-left: 10rpx;  
                            color: rgba(0, 0, 0, 1);  
                            font-size: 24rpx;  
                            font-weight: 400;  
                            line-height: 28rpx;  
                        }  
                    }  

                }  
            }  
        }  
    }  
}

更多关于uni-app map marker 上的自定义气泡 customCallout显示气泡不对的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于uni-app map marker 上的自定义气泡 customCallout显示气泡不对的实战教程也可以访问 https://www.itying.com/category-93-b0.html


根据你的代码分析,customCallout显示异常可能有以下几个原因:

  1. cover-view层级问题:customCallout使用的cover-view在map组件中必须直接作为map的子节点,你的代码中使用了slot="callout"是正确的,但要注意cover-view的样式定位。

  2. marker-id绑定问题:确保每个cover-view的marker-id与对应marker的id完全一致。你的代码中marker.id使用了index,而cover-view绑定的也是item.id,这基本正确。

  3. anchorX/anchorY设置:你设置的anchorX:0和anchorY:0会将气泡定位在marker的左上角,这可能导致气泡显示位置偏移。建议尝试:

    customCallout: {
      anchorY: -20,  // 向上偏移
      anchorX: 0,
      display: "ALWAYS"
    }
    
  4. 样式问题:cover-view的样式需要特别注意:

    • 避免使用rpx单位,建议使用px
    • 确保有明确的宽度设置
    • 添加白色背景和边框以增强可见性
  5. 时机问题:确保markers数据在map渲染完成后再设置。你可以在onMounted中添加延迟:

    onMounted(() => {
      setTimeout(() => {
        // 重新设置markers数据
      }, 100)
    })
回到顶部