更新记录

1.0.0(2026-08-17) 下载此版本

  • 实现Android、iOS和HarmonyOS的统一地图API开发
  • 支持地图展示、覆盖物展示以及其它常用功能

平台兼容性

uni-app x(4.85)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 鸿蒙插件版本 微信小程序
- - 7.0 1.0.0 12 1.0.0 17 1.0.0 -

baidumap-view

百度地图 UTS 插件

基于百度地图 SDK 的 uni-app x 原生地图插件,支持 Android、iOS、HarmonyOS 三端统一 API,覆盖地图展示、状态控制、覆盖物、富文本气泡与地图事件。

支持平台

平台 支持状态
Android
iOS
HarmonyOS

插件能力

  • 地图展示:中心点、缩放、旋转、俯视角、最小/最大缩放级别
  • 手势控制:缩放、拖动、旋转、俯视手势开关
  • 图层控制:POI、室内图、室内 POI、路况、比例尺、指南针、缩放控件
  • 地图类型:标准地图、卫星地图、坐标类型切换、个性化样式
  • 视野控制:fitBounds、地图状态获取、可视区域获取、屏幕坐标与经纬度互转
  • 地理工具:坐标转换、距离计算、点在多边形/矩形判断
  • 覆盖物:MarkerPolylinePolygonCircleLabel
  • 富文本气泡:MarkerLabel 支持 RichView
  • POI 检索:城市内检索、周边检索、地理编码、逆地理编码、SUG 联想
  • 路线规划:步行、骑行、驾车路线规划
  • 地图事件:点击、双击、长按、POI 点击、覆盖物点击、地图状态变化、地图加载/渲染完成
  • 调试能力:插件内部日志开关

版本要求

  • HBuilderX^4.85
  • uni-app-x^4.85

快速开始

1. 引入插件

import {
  SdkInit,
  LogUtil,
  createNativeMapContext,
  INativeMapContext,
  LatLng,
  MapOverlay,
  MapPoi,
  Marker,
  Polyline,
  Polygon,
  Circle,
  Label,
  RichView,
  RichViewItem
} from '@/uni_modules/baidumap-view'

2. 初始化隐私与 AK

使用地图前必须先同意隐私政策并配置百度地图 AK。

SdkInit.setAgreePrivacy(true)
SdkInit.setAK('你的百度地图AK')

3. 页面中放置地图组件

id 必填,且同一页面内必须唯一。

<baidumap-view
  id="demoMap"
  style="width: 750rpx; height: 900rpx"
  :lat="39.914779"
  :lng="116.404"
  :zoom="13"
  @onMapLoadFinish="onMapLoadFinish"
  @onMapClick="onMapClick"
  @onMapOverlayClick="onMapOverlayClick"
/>

4. 地图加载完成后创建上下文

let map : INativeMapContext | null = null

function onMapLoadFinish() {
  map = createNativeMapContext('demoMap', getCurrentInstance()?.proxy ?? null)
}

onBeforeUnmount(() => {
  map?.destroy()
})

完整页面示例

<template>
  <view>
    <button @click="addMarker">添加标记</button>
    <button @click="moveCenter">移动中心点</button>
    <baidumap-view
      id="demoMap"
      style="width: 750rpx; height: 900rpx"
      :lat="39.914779"
      :lng="116.404"
      :zoom="13"
      :showTrafficMap="true"
      @onMapLoadFinish="onMapLoadFinish"
      @onMapClick="onMapClick"
      @onMapPoiClick="onMapPoiClick"
      @onMapOverlayClick="onMapOverlayClick"
    />
  </view>
</template>

<script setup lang="uts">
import {
  SdkInit,
  createNativeMapContext,
  INativeMapContext,
  LatLng,
  MapOverlay,
  MapPoi,
  Marker,
  LogUtil
} from '@/uni_modules/baidumap-view'

SdkInit.setAgreePrivacy(true)
SdkInit.setAK('你的百度地图AK')
LogUtil.setMapLogStatus(true)

let map : INativeMapContext | null = null
let marker : Marker | null = null

function onMapLoadFinish() {
  map = createNativeMapContext('demoMap', getCurrentInstance()?.proxy ?? null)
}

function addMarker() {
  if (map == null) {
    return
  }
  marker?.remove()

  const newMarker = new Marker()
  const position : LatLng = { lat: 39.92235, lng: 116.380338 }
  newMarker.setPosition(position)
  newMarker.icon = '/static/icon_marker.png'
  newMarker.addToMap('demoMap')
  marker = newMarker
}

function moveCenter() {
  const center : LatLng = { lat: 39.915, lng: 116.404 }
  map?.setCenter(center.lat, center.lng)
  map?.setZoom(15)
}

function onMapClick(position : LatLng) {
  console.log('map click', position)
}

function onMapPoiClick(poi : MapPoi) {
  console.log('poi click', poi.name, poi.uid)
}

function onMapOverlayClick(overlay : MapOverlay) {
  const currentMarker = marker
  if (currentMarker != null && currentMarker.getId() == overlay.id) {
    currentMarker.updateIcon('/static/icon_marker_selected.png')
  }
}

onBeforeUnmount(() => {
  marker?.remove()
  map?.destroy()
})
</script>

组件属性

属性 类型 默认值 说明
id string 必填 地图唯一标识
lat number 39.914779 初始中心纬度
lng number 116.404000 初始中心经度
zoom number 18 初始缩放级别
minZoom number 3 最小缩放级别
maxZoom number 23 最大缩放级别
rotate number 0 地图旋转角度
overlook number 0 地图俯视角
showMapPoi boolean true 是否展示 POI
showMapIndoorPoi boolean true 是否展示室内 POI
showBaseIndoorMap boolean true 是否展示室内图
showTrafficMap boolean true 是否展示路况图层
zoomGesturesEnabled boolean true 是否启用缩放手势
moveGesturesEnabled boolean true 是否启用拖动手势
rotateGesturesEnabled boolean true 是否启用旋转手势
overlookingGesturesEnabled boolean true 是否启用俯视手势

组件事件

事件名 参数 说明
@onMapLoadFinish - 地图加载完成
@onMapRenderFinish - 地图渲染完成
@onMapClick LatLng 点击地图空白区域
@onMapDoubleClick LatLng 双击地图
@onMapLongPress LatLng 长按地图
@onMapPoiClick MapPoi 点击地图 POI
@onMapOverlayClick MapOverlay 点击覆盖物或富文本子项
@onMapStatusChangeStart number 地图状态开始变化
@onMapStatusChange - 地图状态变化中
@onMapStatusChangeFinish - 地图状态变化结束

事件数据结构

type LatLng = {
  lat : number,
  lng : number
}

type MapPoi = {
  name : string,
  uid : string,
  position : LatLng
}

type MapOverlay = {
  id : number,
  type : 'marker' | 'polyline' | 'polygon' | 'circle' | 'label' | 'multipoint',
  isItemView ?: boolean,
  itemIndex ?: number
}

地图控制 API

通过 createNativeMapContext 获取 INativeMapContext 后可调用以下能力:

地图状态

map?.setZoom(15)
map?.setMinZoom(5)
map?.setMaxZoom(20)
map?.setRotate(30)
map?.setOverlook(20)
map?.setCenter(39.915, 116.404)

map?.setMapStatus({
  center: { lat: 39.915, lng: 116.404 },
  zoom: 14,
  rotate: 0,
  overlook: 0,
  minZoom: 3,
  maxZoom: 23,
  isAnimate: true,
  animationTime: 300
})

手势开关

map?.zoomGesturesEnabled(true)
map?.moveGesturesEnabled(true)
map?.rotateGesturesEnabled(true)
map?.overlookingGesturesEnabled(true)

图层与控件

map?.showMapPoi(true)
map?.showMapIndoorPoi(true)
map?.showBaseIndoorMap(true)
map?.showTrafficMap(true)
map?.showScaleControl(true)
map?.showZoomControls(true)
map?.showCompass(true)

生命周期

if (map?.isValid() == true) {
  console.log('map context valid')
}
map?.destroy()

地图类型与坐标系

// 地图类型:1-标准地图 2-卫星地图
map?.setMapType(1)

// 坐标类型:1-BD09LL(百度) 2-GCJ02(国测局)
map?.setCoordType(1)

// 地图样式:0-标准 1-深色
map?.setMapStyleMode(0)

// 个性化样式(本地文件)
map?.setCustomMapStylePath('/static/custom_style.sty')

// 个性化样式(样式ID,从百度地图开放平台获取)
map?.setCustomMapStyleById('your_style_id')

视野控制

// 调整视野以包含指定坐标点
const bounds : LatLng[] = [
  { lat: 39.915, lng: 116.404 },
  { lat: 39.925, lng: 116.414 }
]
const fitOptions : FitBoundsOptions = {
  padding: 50,
  isAnimate: true,
  animationTime: 300
}
map?.fitBounds(bounds, fitOptions)

// 获取当前地图状态
map?.getMapStatus((status : MapStatus) => {
  console.log('center:', status.center, 'zoom:', status.zoom)
})

// 获取可视区域
map?.getVisibleRegion((region : VisibleRegion) => {
  console.log('northeast:', region.northeast, 'southwest:', region.southwest)
})

// 屏幕坐标与经纬度互转
map?.screenToLatLng(200, 300, (latlng : LatLng) => {
  console.log('screen to latlng:', latlng)
})
map?.latLngToScreen({ lat: 39.915, lng: 116.404 }, (point : ScreenPoint) => {
  console.log('latlng to screen:', point.x, point.y)
})

覆盖物使用

建议所有覆盖物变量声明为 let xxx : Type | null = null,并在重复添加前先调用 remove(),避免地图上累积旧对象。

Marker

let marker : Marker | null = null

function addMarker() {
  marker?.remove()
  const newMarker = new Marker()
  const position : LatLng = { lat: 39.92235, lng: 116.380338 }
  newMarker.setPosition(position)
  newMarker.icon = '/static/icon_marker.png'
  newMarker.addToMap('demoMap')
  marker = newMarker
}

marker?.updatePosition({ lat: 39.915, lng: 116.404 })
marker?.updateIcon('/static/icon_marker_selected.png')
marker?.remove()

Polyline

let polyline : Polyline | null = null

function addPolyline() {
  polyline?.remove()
  const newPolyline = new Polyline()
  newPolyline.setPoints([
    { lat: 39.915, lng: 116.404 },
    { lat: 39.925, lng: 116.414 },
    { lat: 39.935, lng: 116.424 }
  ])
  newPolyline.color = '#1E80FF'
  newPolyline.width = 8
  newPolyline.addToMap('demoMap')
  polyline = newPolyline
}

polyline?.updatePoints([
  { lat: 39.915, lng: 116.404 },
  { lat: 39.945, lng: 116.434 }
])
polyline?.updateColor('#FF5A5F')
polyline?.updateWidth(10)

Polygon

let polygon : Polygon | null = null

function addPolygon() {
  polygon?.remove()
  const newPolygon = new Polygon()
  newPolygon.setPointsData([
    { lat: 39.915, lng: 116.404 },
    { lat: 39.925, lng: 116.434 },
    { lat: 39.905, lng: 116.444 }
  ])
  newPolygon.borderWidth = 4
  newPolygon.borderColor = '#1E80FF'
  newPolygon.fillColor = '#4D1E80FF'
  newPolygon.addToMap('demoMap')
  polygon = newPolygon
}

polygon?.updatePoints([
  { lat: 39.915, lng: 116.404 },
  { lat: 39.935, lng: 116.424 },
  { lat: 39.905, lng: 116.444 }
])
polygon?.updateBorderWidth(6)
polygon?.updateBorderColor('#FF5A5F')
polygon?.updateFillColor('#4DFF5A5F')

Circle

let circle : Circle | null = null

function addCircle() {
  circle?.remove()
  const newCircle = new Circle()
  newCircle.setCenter({ lat: 39.915, lng: 116.404 })
  newCircle.radius = 500
  newCircle.borderWidth = 4
  newCircle.borderColor = '#1E80FF'
  newCircle.fillColor = '#4D1E80FF'
  newCircle.addToMap('demoMap')
  circle = newCircle
}

circle?.updateCenter({ lat: 39.918, lng: 116.408 })
circle?.updateRadius(800)
circle?.updateBorderWidth(6)
circle?.updateBorderColor('#FF5A5F')
circle?.updateFillColor('#4DFF5A5F')

Label

let label : Label | null = null

function addLabel() {
  label?.remove()
  const newLabel = new Label()
  newLabel.setPosition({ lat: 39.915, lng: 116.404 })
  newLabel.text = '百度地图'
  newLabel.fontSize = 28
  newLabel.fontColor = '#1F2329'
  newLabel.borderWidth = 2
  newLabel.borderColor = '#FFFFFF'
  newLabel.rotate = 0
  newLabel.addToMap('demoMap')
  label = newLabel
}

label?.updateText('地图插件')
label?.updateFontSize(32)
label?.updateFontColor('#1E80FF')
label?.updateBorderWidth(3)
label?.updateBorderColor('#FF5A5F')
label?.updateRotate(10)
label?.updatePosition({ lat: 39.918, lng: 116.408 })

RichView 富文本气泡

MarkerLabel 支持 addRichView() / removeRichView(),可用于实现信息气泡、组合图文标注等场景。

RichView 类型

type RichViewItem = {
  type : string,
  text ?: string,
  fontSize ?: number,
  fontColor ?: string,
  fontBold ?: boolean,
  borderWidth ?: number,
  borderColor ?: string,
  maxLines ?: number,
  image ?: string,
  direction ?: 'vertical' | 'horizontal',
  children ?: Array<RichViewItem>,
  width ?: number,
  height ?: number,
  background ?: string,
  backgroundColor ?: string,
  margin ?: {
    top ?: number,
    left ?: number,
    bottom ?: number,
    right ?: number
  },
  gravity ?: 'left' | 'center' | 'right',
  clickable ?: boolean
}

type RichView = {
  items : Array<RichViewItem>,
  direction ?: 'vertical' | 'horizontal',
  locate ?: 'top' | 'bottom' | 'left' | 'right',
  offsetX ?: number,
  offsetY ?: number,
  gravity ?: 'left' | 'center' | 'right',
  background ?: string,
  backgroundColor ?: string,
  collisionPriority ?: number
}

给 Marker 添加气泡

const richView : RichView = {
  locate: 'top',
  offsetY: -12,
  direction: 'vertical',
  items: [
    {
      type: 'layout',
      direction: 'horizontal',
      children: [
        {
          type: 'image',
          image: '/static/avatar.png',
          width: 48,
          height: 48,
          margin: { right: 8 }
        },
        {
          type: 'text',
          text: '教学点位',
          fontSize: 26,
          fontColor: '#1F2329',
          fontBold: true,
          clickable: true
        }
      ]
    }
  ]
}

marker?.addRichView(richView)
marker?.removeRichView()

点击 RichView 子项时,@onMapOverlayClickMapOverlay 会携带:

  • isItemView
  • itemIndex

可据此判断是否点击了气泡内某个元素。

检索服务

通过 map?.getSearchService() 获取检索服务实例。

POI 检索

const searchService = map?.getSearchService()

// 城市内检索
searchService?.poiCitySearch({
  keyword: '餐厅',
  city: '北京',
  pageIndex: 0,
  pageSize: 10
}, (result) => {
  result.poiList?.forEach((poi) => {
    console.log(poi.name, poi.address, poi.location)
  })
})

// 周边检索
searchService?.poiNearbySearch({
  keyword: '酒店',
  location: { lat: 39.915, lng: 116.404 },
  radius: 1000,
  pageIndex: 0,
  pageSize: 10
}, (result) => {
  result.poiList?.forEach((poi) => {
    console.log(poi.name, poi.distance)
  })
})

地理编码

// 地址 -> 坐标
searchService?.geoCode({
  address: '北京市海淀区上地十街10号',
  city: '北京'
}, (result) => {
  console.log('location:', result.location)
})

// 坐标 -> 地址
searchService?.reverseGeoCode({
  location: { lat: 39.915, lng: 116.404 }
}, (result) => {
  console.log('address:', result.address)
  console.log('poiList:', result.poiList)
})

SUG 联想检索

searchService?.suggestionSearch({
  keyword: '天安门',
  city: '北京'
}, (result) => {
  result.suggestionList?.forEach((item) => {
    console.log(item.key, item.address, item.location)
  })
})

路线规划

步行路线

searchService?.walkingRouteSearch({
  startLocation: { lat: 39.915, lng: 116.404 },
  endLocation: { lat: 39.925, lng: 116.414 }
}, (result) => {
  const route = result.routeLines?.[0]
  if (route != null) {
    console.log('distance:', route.distance, 'duration:', route.duration)
    // route.steps 包含路线各步骤
    // route.wayPoints 包含路线点串,可用于绑定 Polyline
  }
})

骑行路线

searchService?.ridingRouteSearch({
  startLocation: { lat: 39.915, lng: 116.404 },
  endLocation: { lat: 39.925, lng: 116.414 }
}, (result) => {
  const route = result.routeLines?.[0]
  if (route != null) {
    console.log('distance:', route.distance, 'duration:', route.duration)
  }
})

驾车路线

searchService?.drivingRouteSearch({
  startLocation: { lat: 39.915, lng: 116.404 },
  endLocation: { lat: 39.935, lng: 116.434 }
}, (result) => {
  const route = result.routeLines?.[0]
  if (route != null) {
    console.log('distance:', route.distance, 'duration:', route.duration)
    // route.trafficInfo 包含路况信息
  }
})

路线绘制示例

let routePolyline : Polyline | null = null

function drawRoute(wayPoints : LatLng[]) {
  routePolyline?.remove()
  const polyline = new Polyline()
  polyline.setPoints(wayPoints)
  polyline.color = '#1E80FF'
  polyline.width = 8
  polyline.addToMap('demoMap')
  routePolyline = polyline

  // 调整视野以显示完整路线
  map?.fitBounds(wayPoints, { padding: 80, isAnimate: true })
}

地理工具

const geoUtils = map?.getGeoUtils()

// 坐标转换
const gcj02 = geoUtils?.bd09llToGcj02({ lat: 39.915, lng: 116.404 })
const bd09ll = geoUtils?.gcj02ToBd09ll({ lat: 39.91, lng: 116.40 })

// 计算两点距离(米)
const distance = geoUtils?.getDistance(
  { lat: 39.915, lng: 116.404 },
  { lat: 39.925, lng: 116.414 }
)

// 判断点是否在多边形内
const polygon : LatLng[] = [
  { lat: 39.91, lng: 116.40 },
  { lat: 39.92, lng: 116.41 },
  { lat: 39.91, lng: 116.42 }
]
const inPolygon = geoUtils?.isPointInPolygon({ lat: 39.915, lng: 116.405 }, polygon)

// 判断点是否在矩形范围内
const inBounds = geoUtils?.isPointInBounds(
  { lat: 39.915, lng: 116.405 },
  { lat: 39.91, lng: 116.40 },  // southwest
  { lat: 39.92, lng: 116.42 }   // northeast
)

推荐使用规范

1. 使用局部常量创建覆盖物

为避免 UTS 对可变变量的 Smart Cast 限制,推荐使用局部常量模式:

let marker : Marker | null = null

function addMarker() {
  marker?.remove()
  const newMarker = new Marker()
  newMarker.setPosition({ lat: 39.92235, lng: 116.380338 })
  newMarker.icon = '/static/icon_marker.png'
  newMarker.addToMap('demoMap')
  marker = newMarker
}

2. 覆盖物点击时先取局部引用

function onMapOverlayClick(overlay : MapOverlay) {
  const currentMarker = marker
  if (currentMarker != null && currentMarker.getId() == overlay.id) {
    currentMarker.updateIcon('/static/icon_marker_selected.png')
  }
}

3. 注意资源路径

  • 图片资源建议使用项目内绝对静态路径,如 '/static/icon_marker.png'
  • Marker.iconRichView.imageRichView.background 会在原生层转换为绝对路径

4. 页面卸载时释放资源

onBeforeUnmount(() => {
  marker?.remove()
  map?.destroy()
})

调试日志

LogUtil.setMapLogStatus(true)
console.log(LogUtil.getMapLogStatus())

常见问题

1. 地图不显示

请检查:

  • 是否已调用 SdkInit.setAgreePrivacy(true)
  • 是否已正确设置 SdkInit.setAK(...)
  • 地图组件是否设置了明确宽高
  • id 是否唯一

2. createNativeMapContext 返回空

请检查:

  • 是否在 @onMapLoadFinish 之后再创建上下文
  • createNativeMapContext('地图id', getCurrentInstance()?.proxy ?? null) 中的 id 是否与组件一致

3. 覆盖物添加失败

请检查:

  • 是否先创建了地图上下文
  • LatLng 坐标是否合法
  • Marker.icon 或 RichView 图片资源路径是否有效
  • addToMap('xxx') 的参数是否与地图 id 一致

官方文档

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件设备信息以及网络信息,用于SDK鉴权以及用于排查和分析异常时的问题日志,详见:https://lbs.baidu.com/docs/pcsa?title=compliance/openprivacy#1%E5%AE%9A%E4%BD%8D%E4%BA%A7%E5%93%81

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。