# uni.onCompassChange(callback)

监听罗盘数据变化事件。频率:5 次/秒,接口调用后会自动开始监听

# onCompassChange 兼容性

Web 微信小程序 Android iOS iOS uni-app x UTS 插件 HarmonyOS HarmonyOS(Vapor)
4.0 4.41 5.08 5.08 x 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
callback (result: OnCompassChangeCallbackResult) => void -
-
罗盘数据变化事件的监听函数

# OnCompassChangeCallbackResult 的属性值

名称 类型 必备 默认值 兼容性 描述
direction number -
-
面对的方向度数
accuracy number | string -
-
精度
errMsg string -
-
错误信息

# 参见

# uni.offCompassChange(callback)

取消监听罗盘数据

# offCompassChange 兼容性

Web 微信小程序 Android iOS iOS uni-app x UTS 插件 HarmonyOS HarmonyOS(Vapor)
4.0 4.41 5.08 5.08 x 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
callback (result: OnCompassChangeCallbackResult) => void -
-
onCompassChange 传入的监听函数。不传此参数则移除所有监听函数。

# OnCompassChangeCallbackResult 的属性值

名称 类型 必备 默认值 兼容性 描述
direction number -
-
面对的方向度数
accuracy number | string -
-
精度
errMsg string -
-
错误信息

# 参见

# uni.startCompass(options?)

开始监听罗盘数据

# startCompass 兼容性

Web 微信小程序 Android iOS HarmonyOS HarmonyOS(Vapor)
4.0 4.41 5.08 5.08 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
options StartCompassOptions -
-
开始监听罗盘数据的参数
名称 类型 必备 默认值 兼容性 描述
success (res: StartCompassSuccess) => void -
-
开始监听罗盘数据调用成功的回调函数
fail (res: StartCompassFail) => void -
-
开始监听罗盘数据调用失败的回调函数
complete (res: StartCompassSuccess | StartCompassFail) => void -
-
开始监听罗盘数据调用结束的回调函数(调用成功、失败都会执行)

# StartCompassSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
errMsg string -
-

# StartCompassFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number -
-
合法值 兼容性 描述
501
-
-
502
-
-
503
-
-
504
-
-
601
-
-
602
-
-
603
-
-
604
-
-
701
-
-
702
-
-
703
-
-
704
-
-
801
-
-
802
-
-
803
-
-
804
-
-
901
-
-
errSubject string -
-
统一错误主题(模块)名称
data any -
-
错误信息中包含的数据
cause Error - - 源错误信息,可以包含多个错误,详见SourceError
errMsg string -
-

# 参见

# uni.stopCompass(options?)

停止监听罗盘数据

# stopCompass 兼容性

Web 微信小程序 Android iOS HarmonyOS HarmonyOS(Vapor)
4.0 4.41 5.08 5.08 5.08 5.08

# 参数

名称 类型 必填 默认值 兼容性 描述
options StopCompassOptions -
-
停止监听罗盘数据的参数
名称 类型 必备 默认值 兼容性 描述
success (res: StopCompassSuccess) => void -
-
停止监听罗盘数据调用成功的回调函数
fail (res: StopCompassFail) => void -
-
停止监听罗盘数据调用失败的回调函数
complete (res: StopCompassSuccess | StopCompassFail) => void -
-
停止监听罗盘数据调用结束的回调函数(调用成功、失败都会执行)

# StopCompassSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
errMsg string -
-

# StopCompassFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number -
-
合法值 兼容性 描述
501
-
-
502
-
-
503
-
-
504
-
-
601
-
-
602
-
-
603
-
-
604
-
-
701
-
-
702
-
-
703
-
-
704
-
-
801
-
-
802
-
-
803
-
-
804
-
-
901
-
-
errSubject string -
-
统一错误主题(模块)名称
data any -
-
错误信息中包含的数据
cause Error - - 源错误信息,可以包含多个错误,详见SourceError
errMsg string -
-

# 参见

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

扫码体验(手机浏览器跳转到App直达页)

示例

<template>
	<!-- #ifdef APP -->
	<scroll-view style="flex: 1;padding: 6px;">
	<!-- #endif -->
		<text class="uni-h2">罗盘 API</text>
		<text class="notice">演示 `uni.startCompass`、`uni.stopCompass`、`uni.onCompassChange`、`uni.offCompassChange` 的完整流程。靠近强磁场或金属物体时数据可能抖动,可做“8”字校准。Web平台需使用https</text>
		<text class="margin-v">先绑定监听,再启动采集,更容易观察回调是否生效。</text>

		<text class="uni-h3">实时信息</text>
		<view class="panel-list">
			<text class="panel-item" v-for="item in infoItems" :key="item.label">{{ item.label }}:{{ item.value }}</text>
		</view>

		<text class="uni-h3">当前方位</text>
		<view class="compass-card">
			<view class="bg-compass-line"></view>
			<image class="bg-compass" src="/static/compass.png" :style="compassStyle" />
			<view class="direction-center">
				<text class="direction-value">{{ directionText }}</text>
				<text class="direction-degree">{{ degreeText }}</text>
			</view>
		</view>

		<view class="uni-row">
			<button id="btn-bind-primary-listener" class="margin-v" @tap="bindPrimaryListener">注册罗盘Change</button>
			<button id="btn-remove-primary-listener" class="margin-v" style="margin-left: 3px;" @tap="removePrimaryListener">注销罗盘Change</button>
		</view>
		<view class="uni-row">
			<button id="btn-start-compass" class="margin-v" type="primary" @tap="startCompassListen">uni.startCompass</button>
			<button id="btn-stop-compass" class="margin-v" style="margin-left: 3px;" @tap="stopCompassListen">uni.stopCompass</button>
		</view>
		<text>重复绑定测试</text>
		<view class="uni-row">
			<button id="btn-bind-secondary-listener" class="margin-v" @tap="bindSecondaryListener">注册罗盘Change2</button>
			<button id="btn-remove-secondary-listener" class="margin-v" style="margin-left: 3px;" @tap="removeSecondaryListener">注销罗盘Change2</button>
		</view>
		<text class="uni-h3">监听日志</text>
		<view class="panel-list">
			<text class="panel-item" v-for="item in logItems" :key="item.id">{{ item.text }}</text>
		</view>
	<!-- #ifdef APP -->
	</scroll-view>
	<!-- #endif -->
</template>

<script setup lang="uts">
	type DisplayItem = {
		label : string
		value : string
	}

	type PageCompassAccuracy = number | string | null

	type LogItem = {
		id : number
		text : string
	}

	const statusText = ref('未启动')
	const direction = ref(0)
	const directionText = ref('北')
	const accuracyText = ref('null')
	const primaryBound = ref(false)
	const secondaryBound = ref(false)
	const lastAction = ref('等待调用')
	const lastStatus = ref('未执行')
	const lastPayload = ref('请先绑定监听并开始采集')
	const logItems = ref<Array<LogItem>>([])
	const logId = ref(0)
	
	const infoItems = computed(() : Array<DisplayItem> => {
		return [
			{ label: '监听状态', value: statusText.value },
			{ label: '主监听', value: primaryBound.value ? '已绑定' : '未绑定' },
			{ label: '额外监听', value: secondaryBound.value ? '已绑定' : '未绑定' },
			{ label: 'accuracy', value: accuracyText.value },
			{ label: '最近动作', value: lastAction.value },
			{ label: '状态', value: lastStatus.value },
			{ label: '说明', value: lastPayload.value }
		]
	})

	function pushLog(line : string) : void {
		logId.value = logId.value + 1
		const item : LogItem = {
			id: logId.value,
			text: line
		}
		logItems.value.unshift(item)
		if (logItems.value.length > 10) {
			logItems.value.splice(10)
		}
	}

	function updateResult(action : string, status : string, payload : string) : void {
		lastAction.value = action
		lastStatus.value = status
		lastPayload.value = payload
		pushLog(`${action} -> ${status}`)
	}

	function formatDirection(value : number) : string {
		return value.toFixed(1)
	}

	function formatAccuracy(value : PageCompassAccuracy) : string {
		if (value == null) {
			return 'null'
		}
		if (typeof value == 'number') {
			return value.toFixed(2)
		}
		return value
	}

	function resolveDirectionText(value : number) : string {
		if (value >= 337.5 || value < 22.5) {
			return '北'
		}
		if (value < 67.5) {
			return '东北'
		}
		if (value < 112.5) {
			return '东'
		}
		if (value < 157.5) {
			return '东南'
		}
		if (value < 202.5) {
			return '南'
		}
		if (value < 247.5) {
			return '西南'
		}
		if (value < 292.5) {
			return '西'
		}
		return '西北'
	}

	const compassStyle = computed(() : string => {
		return `transform: rotate(${-direction.value}deg);`
	})

	const degreeText = computed(() : string => {
		return `${formatDirection(direction.value)}°`
	})

	const primaryListener : OnCompassChangeCallback = (result : OnCompassChangeCallbackResult) => {
		direction.value = result.direction
		directionText.value = resolveDirectionText(result.direction)
		accuracyText.value = formatAccuracy(result.accuracy != null ? result.accuracy : null)
		statusText.value = '监听中'
	}

	const secondaryListener : OnCompassChangeCallback = (result : OnCompassChangeCallbackResult) => {
		pushLog(`额外监听 -> ${formatDirection(result.direction)}° / accuracy ${formatAccuracy(result.accuracy != null ? result.accuracy : null)}`)
	}

	function ensurePrimaryBound() : void {
		if (!primaryBound.value) {
			uni.onCompassChange(primaryListener)
			primaryBound.value = true
		}
	}

	function bindPrimaryListener() : void {
		ensurePrimaryBound()
		updateResult('onCompassChange(primary)', '已绑定', '主监听已注册')
	}

	function bindSecondaryListener() : void {
		if (!secondaryBound.value) {
			uni.onCompassChange(secondaryListener)
			secondaryBound.value = true
		}
		updateResult('onCompassChange(extra)', '已绑定', '额外监听已注册')
	}

	function removePrimaryListener() : void {
		uni.offCompassChange(primaryListener)
		primaryBound.value = false
		updateResult('offCompassChange(primary)', '已解绑', '主监听已移除')
	}

	function removeSecondaryListener() : void {
		uni.offCompassChange(secondaryListener)
		secondaryBound.value = false
		updateResult('offCompassChange(extra)', '已解绑', '额外监听已移除')
	}

	function startCompassListen() : void {
		ensurePrimaryBound()
		uni.startCompass({
			success: (res) => {
				statusText.value = '监听中'
				const message = res.errMsg != null ? res.errMsg as string : 'startCompass:ok'
				updateResult('startCompass', '成功', message)
			},
			fail: (error) => {
				statusText.value = '启动失败'
				const message = error.errMsg != null ? error.errMsg : 'startCompass:fail'
				updateResult('startCompass', `失败 (${error.errCode})`, message)
			}
		})
	}

	function stopCompassListen() : void {
		uni.stopCompass({
			success: (res) => {
				statusText.value = '已停止'
				const message = res.errMsg != null ? res.errMsg as string : 'stopCompass:ok'
				updateResult('stopCompass', '成功', message)
			},
			fail: (error) => {
				const message = error.errMsg != null ? error.errMsg : 'stopCompass:fail'
				updateResult('stopCompass', `失败 (${error.errCode})`, message)
			}
		})
	}

	onUnload(() => {
		uni.offCompassChange(primaryListener)
		uni.offCompassChange(secondaryListener)
		uni.stopCompass()
	});
	
	defineExpose({
		startCompassListen
	})
</script>

<style>
	.margin-v {
		margin: 5px 0;
	}

	.notice {
		color: #6b2d16;
		font-size: 14px;
	}

	.panel-list {
		margin: 5px 0;
		padding: 10px;
		border: 1px solid #ccc;
		display: flex;
		flex-direction: column;
	}

	.panel-item {
		font-size: 14px;
		margin: 4px 0;
	}

	.compass-card {
		position: relative;
		margin: 12px auto;
		width: 270px;
		height: 270px;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.direction-center {
		position: relative;
		z-index: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
	}

	.direction-value {
		font-size: 30px;
	}

	.direction-degree {
		font-size: 16px;
		margin-top: 6px;
	}

	.bg-compass {
		position: absolute;
		top: 0;
		left: 0;
		width: 270px;
		height: 270px;
		transition-duration: 0.1s;
	}

	.bg-compass-line {
		position: absolute;
		left: 134px;
		top: -5px;
		width: 3px;
		height: 28px;
		background-color: #1aad19;
		border-radius: 100px;
		z-index: 1;
	}
</style>

# 通用类型

# GeneralCallbackResult

名称 类型 必备 默认值 兼容性 描述
errMsg string -
错误信息