【天体运行模拟|09】HarmonyOS ArkTS 物理常量实战:集中管理常量来源和显示精度
物理常量页最容易被误认为“把几个数字排成列表”。但常量一旦同时用于学习展示、单位换算和模拟计算,就必须回答三个问题:数值来自哪里,采用哪个定义或观测口径,显示精度与计算精度是否一致。光速是定义值,地球半径可能是平均半径或赤道半径,月地距离也会随轨道变化;如果模型只保存一段字符串,这些差异会被界面悄悄抹平。
“天体运行模拟”的 ConstantsPage.ets 已经实现了一个简洁的离线天文常数页:用 AstroConstant 描述名称、符号、值和单位,内置光速、万有引力常量、天文单位、太阳质量、地球质量、地球半径、月地距离和光年八条数据,再通过 ArkUI List 渲染统一卡片。
本文基于这份真实源码,复核八条内容的结构和展示边界,并设计一套把“显示文本、计算数值、来源、口径和精度”分层的模型。当前页面没有来源字段、更新时间、数值类型或复制功能;文章中的增强方案会明确标注为建议,不会伪造成已有能力。

唯一复核标记:CONSTANT-ONE13-SOURCE-PRECISION-20260726:常量数值、显示格式、来源口径和有效数字必须分开建模。
验证基线与源码清单
本文面向 HarmonyOS 5.0 及以上版本。实际工程应用版本为 1.0.0,targetSdkVersion 为 6.0.2(22),compatibleSdkVersion 为 6.0.1(21),入口模块支持 phone、tablet、2in1。
源码中的八条数据为:
| 名称 | 符号 | 显示值 | 单位 |
|---|---|---|---|
| 光速 | c |
3.0 x 10^8 |
m/s |
| 万有引力常量 | G |
6.674 x 10^-11 |
N·m²/kg² |
| 天文单位 | AU |
1.496 x 10^8 |
km |
| 太阳质量 | M_sun |
1.989 x 10^30 |
kg |
| 地球质量 | M_earth |
5.972 x 10^24 |
kg |
| 地球半径 | R_earth |
6371 |
km |
| 月地距离 | D_moon |
3.844 x 10^5 |
km |
| 光年 | ly |
9.461 x 10^12 |
km |
静态复核结果:8 条记录全部拥有名称、符号、值和单位;8 个 value 都是字符串;来源字段为 0;口径字段为 0;有效数字字段为 0;数值计算入口为 0。当前能力准确定位为“静态速查展示”。
一、现有 AstroConstant 适合展示
模型只有四个字符串字段:
interface AstroConstant {
name: string
symbol: string
value: string
unit: string
}
它的优点很直接:
- 不需要处理浮点格式化。
- 科学计数形式可以原样显示。
- 不同单位可以放在同一列表。
- ArkUI 绑定简单。
这也是为什么当前页面稳定:List 只负责展示,模型没有计算职责。
缺点同样明显:'3.0 x 10^8' 不能安全用于乘除运算,value 中可能出现任意文本,编译器无法检查单位与数值是否匹配。
二、显示字符串不能充当计算常量
如果直接解析:
parseFloat('3.0 x 10^8')
结果只会得到 3,因为 parseFloat 在空格和 x 处停止。这说明显示文本与计算值必须分开。
推荐:
interface PhysicalConstant {
id: string
name: string
symbol: string
siValue: number
siUnit: string
displayValue: string
displayUnit: string
}
光速可以保存:
{
id: 'speed_of_light',
name: '光速',
symbol: 'c',
siValue: 299_792_458,
siUnit: 'm/s',
displayValue: '2.99792458 × 10⁸',
displayUnit: 'm/s'
}
计算读取 siValue,页面读取 displayValue,两者不会互相解析。
三、常量、参考值和平均值要区分
页面标题叫“天文常数”,但八条数据并不全是同一种语义。
- 光速是定义值。
- 天文单位是定义长度。
- 万有引力常量是测量得到的物理常量。
- 太阳质量与地球质量是天体参数的近似值。
- 地球半径需要说明采用平均、赤道还是极半径。
- 月地距离会变化,
384400 km通常是平均尺度。 - 光年是由光速和时间定义推导出的长度。
模型可以增加:
type ConstantKind =
| 'defined'
| 'measured'
| 'derived'
| 'reference'
| 'average'
用户就能知道“为什么有些数字可以写很多位,有些只能近似”。
四、来源不是一个可选装饰字段
推荐每条数据记录:
interface ConstantSource {
organization: string
document: string
edition: string
publishedAt?: string
url?: string
}
来源字段服务于:
- 审核与复核。
- 常量更新。
- 解释不同资料的数值差异。
- 离线页面中的引用说明。
- 防止开发者凭记忆修改常量。
来源链接可以显示在详情页,但应用仍可离线保存必要的组织、文档和版本文本。不要让“没有网络”成为“没有来源”的理由。
五、有效数字需要显式建模
源码显示:
c = 3.0 x 10^8 m/s
这只有 2 位有效数字。它适合入门速查,但如果同一个值用于计算,会损失大量精度。
推荐增加:
interface PrecisionPolicy {
significantDigits: number
approximate: boolean
uncertainty?: string
}
显示层按 significantDigits 格式化,计算层继续使用完整 siValue。近似值应显示 ≈,定义值可以显示 =。
六、科学计数符号要统一
源码使用 ASCII 字符串:
3.0 x 10^8
6.674 x 10^-11
在中文科学展示中,更规范的视觉形式通常是:
3.0 × 10⁸
6.674 × 10⁻¹¹
Unicode 上标可用于短文本,但不应手工维护所有指数。格式化函数可以生成:
const SUPERSCRIPT: Record<string, string> = {
'-': '⁻',
'0': '⁰',
'1': '¹',
'2': '²',
'3': '³',
'4': '⁴',
'5': '⁵',
'6': '⁶',
'7': '⁷',
'8': '⁸',
'9': '⁹'
}
如果目标字体缺少上标,回退到 e 记法:
6.674e-11
七、光速条目如何分离展示与定义
当前显示值是:
3.0 x 10^8 m/s
作为入门近似没有问题。更完整模型可以同时保存:
{
siValue: 299_792_458,
displayDigits: 9,
exact: true
}
页面提供两种展示:
- 简明:
3.00 × 10⁸ m/s - 精确:
299 792 458 m/s
同一数值只维护一次,避免卡片和换算器使用不同常量。
八、万有引力常量需要保留测量语义
源码显示:
G = 6.674 x 10^-11 N·m²/kg²
G 的量级正确,但它不是像光速那样的定义值。专业模型应允许保存不确定度或来源版本:
{
kind: 'measured',
approximate: true,
uncertainty: 'source-defined'
}
文章不应仅靠多写几位小数制造“更准确”的错觉。没有来源和不确定度说明时,合理做法是明确显示近似号。
九、天文单位要避免米和千米重复维护
源码以千米显示:
AU = 1.496 x 10^8 km
计算层建议只保存 SI 米值,显示时转换:
function metersToKilometers(
meters: number
): number {
return meters / 1000
}
如果同时手工维护米值和千米值,一个值更新后另一个可能忘记同步。单一真源加单位换算更可靠。
十、太阳质量与地球质量是近似参考量
源码:
M_sun = 1.989 x 10^30 kg
M_earth = 5.972 x 10^24 kg
它们适合教学量级。若模拟引擎使用归一化质量 M,不要把页面中的 kg 直接传入模拟。应建立显式映射:
interface SimulationScale {
massUnitInKg: number
lengthUnitInMeters: number
timeUnitInSeconds: number
}
公式页展示现实尺度,模拟页使用教学单位,两者可以关联,但不能混为同一数据域。

十一、地球半径必须写明口径
源码显示:
R_earth = 6371 km
这个值常被用作平均半径。地球并非完全球体,赤道半径和极半径不同。模型可以增加:
interface MeasurementContext {
qualifier?: string
epoch?: string
referenceFrame?: string
}
对应条目:
context: {
qualifier: 'mean radius'
}
页面中文可显示“地球平均半径”,比只写“地球半径”更准确。
十二、月地距离不是固定轨道半径
源码显示:
D_moon = 3.844 x 10^5 km
月球绕地球运行的距离会变化。速查页可以保留平均尺度,但应把名称改为“月地平均距离”或在说明中标记近似。
如果未来加入近地点、远地点和实时轨道数据,它们应是不同条目,不应覆盖当前参考值。
十三、光年是长度单位
源码把光年显示为:
ly = 9.461 x 10^12 km
光年名称包含“年”,但它表示距离。详情中应说明:
光在真空中一个儒略年传播的距离
单位换算页如果加入 ly,必须放在长度组。常量页与换算页应该共享同一个 PhysicalConstants 模块,避免两处写不同值。
十四、建立单一常量目录
当前八条数据写在页面状态中:
@State constants: AstroConstant[] = [...]
它们其实是静态目录,不需要 @State。可以移到模型文件:
export const ASTRO_CONSTANTS:
readonly PhysicalConstant[] = [
// ...
]
页面只读取目录:
private constants:
readonly PhysicalConstant[] =
ASTRO_CONSTANTS
单位换算、公式页和模拟说明也从同一模块导入,减少重复。
十五、页面状态与静态数据要分开
@State 适合会触发 UI 更新的可变数据。八条常量在当前页面不会变化,把它们标为 @State 会暗示页面可能修改目录。
真正需要状态的可能是:
- 搜索词。
- 当前分类。
- 展开的详情 ID。
- 显示精度模式。
- 复制成功提示。
常量目录则应保持只读。这样用户交互不会意外改写基础数据。
十六、格式化器应该是纯函数
推荐:
interface FormatOptions {
significantDigits: number
scientificThreshold: number
}
function formatConstant(
value: number,
options: FormatOptions
): string {
const abs = Math.abs(value)
if (abs === 0) return '0'
if (abs >= options.scientificThreshold ||
abs < 1 / options.scientificThreshold) {
return value.toExponential(
options.significantDigits - 1
)
}
return value.toPrecision(
options.significantDigits
)
}
纯函数可以用测试向量验证,不依赖 ArkUI 生命周期。
十七、精度模式可以服务不同读者
页面可以提供分段控制:
- 入门:3 到 4 位有效数字。
- 标准:来源推荐精度。
- 详细:完整存储值和来源说明。
切换模式只改变格式化,不改变 siValue。用户从简明切到详细后不会触发重新加载,也不会产生两份常量。
当前源码没有精度切换,本文只是说明可扩展方向。
十八、List 卡片结构已经适合扩展
每个列表项分为:
- 左侧 70vp 符号块。
- 右侧名称。
- 数值与单位行。
符号使用主色,数值使用橙色,单位使用提示色。视觉层级清晰,List({ space: 8 }) 也便于增加更多条目。
符号块设置:
.maxLines(1)
.textOverflow({
overflow: TextOverflow.Ellipsis
})
这能防止长符号撑破布局,但 M_earth 在大字体下可能被截断。更好的显示是 Unicode 下标或缩短视觉符号,并通过无障碍文本朗读完整名称。
十九、长单位与大字体需要约束
N·m²/kg² 比 kg 长。当前值和单位放在同一 Row,在窄屏或大字体下可能拥挤。
可以:
- 给数值使用
layoutWeight(1)。 - 单位允许换行或移动到下一行。
- 设置
maxLines和明确溢出策略。 - 平板上保持卡片最大宽度。
- 让详情页展示完整来源和单位。
不要为了塞进一行而把单位字体缩到不可读。

二十、多设备布局与安全区
根容器使用:
.width('100%')
.height('100%')
.padding({
top: this.statusBarHeight,
bottom: this.bottomBarHeight
})
手机单列列表合理。平板可以采用两列,但应保持阅读顺序稳定;2in1 可以增加键盘搜索和复制操作。不同设备共享同一常量目录、来源和精度规则,布局层不能修改数值语义。
需要验证状态栏、底部导航、横屏小窗口、系统字体放大,以及长来源文本的滚动。
二十一、复制功能应复制机器可用值
用户点击复制时,可以提供:
G = 6.674 × 10⁻¹¹ N·m²/kg²
也可以提供 ASCII:
G = 6.674e-11 N*m^2/kg^2
前者适合文档,后者适合代码和计算器。不要只复制卡片上截断后的字符串。
当前源码没有复制功能,新增时需要明确格式并提供成功反馈。
二十二、常量目录的启动校验
function validateConstants(
items: readonly PhysicalConstant[]
): string[] {
const errors: string[] = []
const ids = new Set<string>()
items.forEach((item: PhysicalConstant) => {
if (ids.has(item.id)) {
errors.push(`duplicate id: ${item.id}`)
}
ids.add(item.id)
if (!Number.isFinite(item.siValue)) {
errors.push(`invalid value: ${item.id}`)
}
if (item.siUnit.length === 0) {
errors.push(`empty unit: ${item.id}`)
}
if (!item.source) {
errors.push(`missing source: ${item.id}`)
}
})
return errors
}
开发构建可以执行完整校验,正式构建至少保留安全回退,避免单条错误阻塞整个页面。
二十三、测试矩阵
| 测试 | 预期 |
|---|---|
| 初始进入 | 展示 8 条真实记录 |
| 每条记录 | 名称、符号、值、单位均非空 |
| 返回按钮 | 调用 router.back() |
| 窄屏 | 符号块与数值不重叠 |
| 大字体 | 长单位可读,不遮挡下一项 |
| 来源增强后 | 每条都有来源版本 |
| 精度切换 | 只改变显示,不改变 siValue |
| 单位换算 | AU 与光年读取同一常量目录 |
| 非有限数值 | 校验失败,不进入页面目录 |
| 重复 ID | 启动校验报告错误 |
现有源码可以复核前四项的结构基础;来源、精度切换和共享目录属于建议实现。
二十四、发布前检查
- 常量 ID 唯一且稳定。
- 计算数值与显示字符串分离。
- SI 值只维护一份。
- 来源组织、文档和版本可复核。
- 定义值、测量值、推导值和平均值有区分。
- 有效数字与近似号一致。
- 地球半径明确口径。
- 月地距离标注平均或参考性质。
- 光年归入长度。
- 页面与单位换算共享常量目录。
- 长单位、大字体和多设备不溢出。
- 复制内容可选择科学显示或 ASCII。
二十五、总结
当前 ConstantsPage.ets 用统一模型和 ArkUI List 完成了八条天文数据的离线展示,结构清楚、页面轻量,适合作为学习工具的第一版。它的边界也很明确:所有值都是显示字符串,没有来源、口径、有效数字和计算类型。
真正可靠的常量管理要把五件事分开:数值、单位、显示格式、来源和测量语义。计算层使用单一 SI 真源,展示层按读者需要控制有效数字,来源层说明定义或观测口径。这样公式页、换算器和模拟说明才能共享同一份可验证数据,而不是各自维护一串看起来相近的数字。
说明:本文基于真实 HarmonyOS/ArkTS 源码进行整理,部分文字与示例由 AI 辅助生成;所有现有能力与建议改造已明确区分。
更多推荐




所有评论(0)