鸿蒙ArkTS开发实战:零基础手写计算器
本文将从环境搭建、工程创建、变量定义、页面布局、样式优化、交互逻辑编写、运算核心实现、功能容错处理、项目测试优化等完整流程,一步步完成简易计算器的开发。数学规则中,除数不能为 0,因此在除法分支中单独增加判断:如果第二个数字为 0,显示屏展示「计算错误」,同时重置所有变量,终止代码运行,彻底避免应用闪退、卡死问题,这也是程序容错设计的核心部分。完成布局代码编写后,点击工具右上角运行按钮,选择模拟器
一、项目开发概述
随着鸿蒙操作系统生态的持续完善,基于 ArkTS 与 ArkUI 的原生应用开发,已经成为移动端入门开发的主流学习方向。相较于传统移动端开发技术栈,鸿蒙声明式开发范式语法更简洁、逻辑更清晰、数据与视图的关联性更强,非常适合编程零基础、移动端开发新手入门学习。
在所有鸿蒙入门实战项目中,简易计算器是最具代表性的综合性练习项目。该项目整合了页面布局搭建、静态样式美化、动态数据绑定、用户点击交互、逻辑条件判断、数值运算处理、程序异常容错等一系列基础开发技能,能够全方位锻炼开发者的基础编码能力与程序逻辑思维。
本次开发全程基于 HarmonyOS NEXT 版本,使用官方原生 ArkTS 语言与 ArkUI 声明式组件开发,不引入任何第三方开源框架、无复杂工程配置、无高阶封装语法,所有代码均为原生基础写法,兼容性强、可读性高、极易上手。
本文将从环境搭建、工程创建、变量定义、页面布局、样式优化、交互逻辑编写、运算核心实现、功能容错处理、项目测试优化等完整流程,一步步完成简易计算器的开发。全文内容详实、步骤完整、注释清晰、细节拉满,适合零基础新手系统学习,也可作为课程设计、实训作业、技术博客原创内容使用。
1.1 项目实现功能介绍
本次开发的简易计算器对标系统原生计算器基础功能,实现日常使用的完整基础运算能力,具体功能如下:
- 数字输入功能:支持 0-9 多位数字连续输入,支持整数、小数混合输入;
- 小数点规范输入:添加输入拦截逻辑,禁止同一数值内重复输入小数点,规避非法数值格式;
- 基础四则运算:完整实现加法、减法、乘法、除法四种日常数学运算;
- 一键重置功能:配备 C 清空按键,一键重置所有运算数据与页面显示,恢复初始状态;
- 异常容错处理:针对数学运算中最常见的除数为零问题做专属拦截,避免程序报错、闪退、卡死;
- 连续运算能力:运算完成后,结果可直接作为新的运算基数,支持多轮连续复合运算;
- 数值格式优化:自动精简浮点运算多余小数位,解决原生浮点运算精度冗余问题,展示结果更规整。
1.2 技术栈与开发环境
为保证项目通用性与稳定性,本次开发全部采用官方稳定版本工具与原生技术组件,具体环境配置如下:
- 开发工具:DevEco Studio 最新稳定版
- 目标系统:HarmonyOS NEXT
- 开发语言:ArkTS(鸿蒙原生开发语言)
- UI 开发框架:ArkUI 声明式开发范式
- 运行设备:鸿蒙模拟器 / 鸿蒙真机设备
1.3 项目开发核心知识点
通过完成本项目开发,能够扎实掌握鸿蒙入门阶段核心知识点,所有知识点均为日常开发高频刚需内容:
- 鸿蒙项目工程的创建、文件结构认知、基础运行流程;
- @State 响应式状态变量的定义与使用,理解数据驱动视图的核心机制;
- 主流基础布局组件:Column 纵向布局、Grid 网格布局的实战使用;
- 基础交互组件:Text 文本展示组件、Button 按钮组件的属性配置与样式美化;
- 组件点击事件绑定与事件分发逻辑;
- 字符串处理、数值类型转换、条件分支判断、基础语法综合运用;
- 移动端应用基础容错设计与用户体验优化思路。
二、开发环境搭建与工程创建
2.1 开发工具介绍
DevEco Studio 是华为官方专为鸿蒙应用开发打造的集成开发工具,集成了项目创建、代码编写、语法校验、实时预览、编译运行、调试报错等全套开发能力,完全适配 HarmonyOS NEXT 系统应用开发。该工具对鸿蒙原生语法兼容性好、报错提示精准、编译速度快、内置模拟器适配完善,零基础开发者完成安装配置后,就可以直接启动项目开发工作,无需额外配置复杂环境变量与依赖包。
对于初次接触该工具的新手而言,建议使用官方推荐的稳定版本,避免测试版出现未知兼容问题。工具安装流程遵循官方引导即可,安装完成后默认会附带鸿蒙模拟器镜像,可直接用于应用预览与测试,当然也可以使用实体鸿蒙手机连接电脑进行真机调试,两种运行方式本文都会在后续测试环节进行说明。
2.2 全新项目创建流程
正式编码前,我们首先需要创建一个全新的鸿蒙空白工程,详细操作步骤如下:
- 双击打开 DevEco Studio,在软件启动后的欢迎界面中,点击 Create Project 选项,进入项目创建向导;
- 在模板选择页面,众多工程模板里选择 Empty Ability 空白模板,该模板不会自带冗余业务代码,是从零自定义开发应用的首选模板,选中后点击右下角「Next」继续;
- 进入工程配置页面,依次填写相关信息:项目名称建议使用纯英文,命名简洁易懂;设备类型勾选 Phone 手机类型,匹配计算器移动端使用场景;开发语言选定 ArkTS;
- 选择本地文件夹作为项目存储路径,路径建议设置为纯英文路径,不要包含中文、空格与特殊字符,防止编译报错;
- 确认所有配置无误后,点击「Finish」完成创建,此时工具会自动拉取项目依赖、初始化目录文件,等待加载完毕即可。


2.3 项目核心文件说明
工程加载完成后,我们可以看到标准的鸿蒙项目目录结构。本项目属于单页面简易应用,所有代码都将编写在 entry/src/main/ets/pages/Index.ets 文件中。
这个文件是项目默认的首页页面文件,也是应用启动后第一个展示的页面。其余目录文件为工程配置、资源文件、编译脚本等,本次开发无需修改。新手在初期学习阶段,不用深究复杂目录分工,聚焦核心页面文件即可。

三、项目核心逻辑设计与全局变量定义
在动手编写界面和交互代码之前,梳理项目整体运行逻辑、定义全局变量是必不可少的一步。变量是整个应用的数据核心,页面展示内容、运算缓存数据、状态标记全部依靠变量承载,合理的变量定义能够让后续逻辑编写更加顺畅。
3.1 整体交互逻辑梳理
结合日常使用计算器的操作习惯,我们梳理出完整的业务执行流程,方便大家理解每一段代码的设计初衷:
- 应用启动初始化,页面显示屏默认展示数字 0,所有运算缓存数据清空,程序处于待输入状态;
- 用户点击 0-9 数字键或小数点按键,页面实时刷新展示输入内容,支持多位数连续录入;
- 用户点击 +、-、*、/ 任意运算符,程序会将当前显示屏上的数字缓存为第一个运算数,同时记录选中的运算符,并切换为等待输入第二个数字的状态;
- 用户继续输入第二个运算数字,输入完成后点击 = 等于键,程序读取两组数字与运算符,执行对应的数学运算;
- 运算结束后,页面展示最终计算结果,同时将结果缓存,支持直接基于该结果开展新一轮连续运算;
- 若在运算过程中触发「除数为 0」这类非法运算,程序主动拦截异常,展示错误提示,保证应用不会闪退;
- 点击 C 清空键,所有变量全部重置,页面回到初始状态,可重新开始新一轮计算。
3.2 全局变量编写与逐行解析
根据上面梳理的逻辑,我们一共需要定义四个全局变量,分别负责页面展示、运算数字缓存、运算符记录、输入状态标记。打开 Index.ets 文件,在组件内部首先编写变量代码:
// 屏幕显示内容,响应式变量,数据变更自动刷新UI
@State showText: string = "0"
// 缓存第一个参与运算的数字
private firstNum: number = 0
// 记录用户选择的运算符
private operator: string = ""
// 标记是否开启新一轮输入
private isNewInput: boolean = true
接下来对每一个变量进行详细讲解,帮助新手理解设计思路与使用场景:
- @State showText: string = "0"
@State 是 ArkUI 中最基础也最重要的装饰器,被它修饰的变量称之为响应式变量。鸿蒙声明式开发采用「数据驱动视图」的设计思想,当 showText 的值发生改变时,页面中绑定该变量的 Text 组件会自动刷新内容,不需要开发者手动编写页面更新代码。
该变量类型设置为字符串,初始值为 "0",保证应用启动后显示屏有默认内容,符合大众使用计算器的使用习惯。如果去掉默认值,页面初始状态会为空,影响使用体验。
- private firstNum: number = 0
这是一个私有数值类型变量,作用是缓存第一个参与四则运算的数字。当用户点击运算符之后,当前显示屏的数字会转换为数值类型赋值给该变量,全程在后台静默存储数据,不会直接展示在页面上。初始值设置为 0,保证变量初始化合法。
- private operator: string = ""
字符串类型私有变量,专门用来记录用户选中的运算符,可选值为 +、-、*、/。程序后续执行运算时,会读取该变量的值,判断需要执行加法、减法、乘法还是除法。初始值设置为空字符串,代表当前未选择任何运算符。
- private isNewInput: boolean = true
布尔类型状态标记变量,是优化输入逻辑的关键。true 代表需要清空原有内容、开启全新输入;false 代表在原有内容基础上继续拼接输入。借助这个变量,可以有效解决运算完成后数字重叠、初始多零等问题,让输入逻辑更加贴合原生计算器。
四、UI 界面布局与样式编写
变量定义完成后,我们开始搭建可视化界面。本项目界面分为两大模块:上方的数字显示屏、下方的功能按键区。整体使用 Column 纵向布局实现上下分区,按键区域使用 Grid 网格布局实现规整排列,同时搭配样式属性美化界面,提升视觉效果。
4.1 整体布局思路
页面整体结构从上至下依次为:显示屏 → 功能按键区。
- 外层容器使用 Column 布局:这是鸿蒙最常用的纵向布局组件,能够让内部组件按照从上到下的顺序依次排列;
- 显示屏使用独立的 Text 组件实现,单独设置宽高、背景、圆角、文字对齐等样式,模拟真实计算器屏幕;
- 按键区域使用 Grid + GridItem 组合:Grid 网格布局可以将区域划分为固定行列,均匀分布按钮,非常适合制作键盘、计算器按键这类矩阵式布局;GridItem 作为网格中的每一个单元格,内部放置 Button 按钮组件。
4.2 完整布局代码编写
在组件内 build() 函数中编写布局与样式代码,完整内容如下:
build() {
Column() {
// 顶部显示屏
Text(this.showText)
.width("90%")
.height(120)
.fontSize(48)
.textAlign(TextAlign.End)
.padding({ right: 15 })
.backgroundColor(0xF5F5F5)
.borderRadius(12)
.margin({ top: 30, bottom: 20 })
// 底部按钮网格区域
Grid() {
GridItem() { Button("C").fontSize(28).backgroundColor(0xEEEEEE) }
GridItem() { Button("/").fontSize(28).backgroundColor(0xFFB74D) }
GridItem() { Button("*").fontSize(28).backgroundColor(0xFFB74D) }
GridItem() { Button("-").fontSize(28).backgroundColor(0xFFB74D) }
GridItem() { Button("7").fontSize(28) }
GridItem() { Button("8").fontSize(28) }
GridItem() { Button("9").fontSize(28) }
GridItem() { Button("+").fontSize(28).backgroundColor(0xFFB74D) }
GridItem() { Button("4").fontSize(28) }
GridItem() { Button("5").fontSize(28) }
GridItem() { Button("6").fontSize(28) }
GridItem() { Button("=").fontSize(28).backgroundColor(0x42A5F5).fontColor(Color.White) }
GridItem() { Button("1").fontSize(28) }
GridItem() { Button("2").fontSize(28) }
GridItem() { Button("3").fontSize(28) }
GridItem() { Button(".").fontSize(28) }
GridItem() { Button("0").fontSize(28).width("100%") }
}
.columnsTemplate("1fr 1fr 1fr 1fr")
.rowsGap(12)
.columnsGap(12)
.width("90%")
.height(420)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Start)
}
4.3 布局与样式属性详解
- 外层 Column 容器
width("100%") 和 height("100%") 表示容器占满整个手机屏幕宽高;justifyContent(FlexAlign.Start) 表示内部组件靠顶部排列,避免内容居中导致布局错乱。
- Text 显示屏组件
- width("90%"):宽度占屏幕90%,左右预留边距,视觉更美观;
- height(120):固定高度,模拟屏幕尺寸;
- fontSize(48):设置文字大小,保证数字清晰可见;
- textAlign(TextAlign.End):文字右对齐,和主流计算器显示规则保持一致;
- backgroundColor(0xF5F5F5):设置浅灰色背景,区分屏幕与按键区域;
- borderRadius(12):设置圆角,弱化直角生硬感;
- margin:设置上下外边距,拉开屏幕与按键的距离。
- Grid 网格布局属性
- columnsTemplate("1fr 1fr 1fr 1fr"):将网格划分为4列,1fr 代表每一列均分剩余宽度;
- rowsGap / columnsGap:分别设置行间距、列间距,避免按钮紧密贴合;
- 整体设置宽高,限定按键区域范围。
- Button 按钮样式区分
为不同功能按钮设置差异化背景色,提升辨识度:清空键使用浅灰色、四则运算符使用橙黄色、等于键使用蓝色并搭配白色文字,纯数字键使用默认样式,视觉分区清晰。
4.4 静态界面预览
完成布局代码编写后,点击工具右上角运行按钮,选择模拟器启动应用,此时可以看到完整的静态界面,按钮样式、布局、配色均已生效,暂时无法点击交互。
【截图位置3:计算器静态UI界面预览效果】
五、按钮点击交互逻辑开发
静态界面搭建完成后,接下来实现核心的点击交互功能。我们采用统一事件入口的设计方式:所有按钮绑定同一个点击方法,通过判断按钮上的文本内容,分流执行不同的业务逻辑。这种写法代码结构规整,便于后期维护与修改。
5.1 定义统一点击方法
在组件内部、build 函数外侧,新增 onBtnClick 方法,作为所有按钮的统一点击入口,代码如下:
/**
* 所有按钮统一点击事件
* @param value 按钮上的文本内容
*/
onBtnClick(value: string): void {
// 清空按钮逻辑
if (value === "C") {
this.showText = "0"
this.firstNum = 0
this.operator = ""
this.isNewInput = true
return
}
// 等于按钮,触发计算
if (value === "=") {
this.calcResult()
return
}
// 点击四则运算符,保存第一个数字与运算符号
if (["+", "-", "*", "/"].includes(value)) {
this.firstNum = parseFloat(this.showText)
this.operator = value
this.isNewInput = true
return
}
// 数字与小数点输入逻辑
if (this.isNewInput) {
this.showText = value === "." ? "0." : value
this.isNewInput = false
} else {
// 禁止重复输入小数点
if (value === "." && this.showText.includes(".")) {
return
}
this.showText += value
}
}
5.2 代码分段解析
- 清空键 C 逻辑
当点击 C 按钮时,将所有变量恢复为初始值:显示屏重置为 "0"、运算数字清零、运算符置空、输入状态标记恢复为 true,实现一键重置效果,执行 return 终止后续代码运行。
- 等于键 = 逻辑
点击等于键后,直接调用后续编写的 calcResult() 运算方法,触发四则运算逻辑。
- 四则运算符逻辑
判断点击的内容为 +、-、*、/ 任意运算符后,使用 parseFloat() 将显示屏的字符串转为数值,赋值给 firstNum 完成数字缓存;同时记录运算符,并且将 isNewInput 设为 true,准备接收第二个数字输入。
- 数字与小数点输入逻辑
结合 isNewInput 标记区分两种场景:
- 全新输入状态:直接将按钮内容赋值给显示屏,若点击小数点,则默认补 0.,规范小数格式;
- 接续输入状态:在原有字符串后方拼接内容,同时增加判断,若当前内容已存在小数点,则拦截二次输入,避免出现非法数值。
5.3 为所有按钮绑定点击事件
回到 Grid 布局中的每一个 GridItem,为内部的 Button 组件补充 onClick 点击绑定,格式统一为:
|
修改后的完整按钮代码示例:
Grid() {
GridItem() { Button("C").fontSize(28).backgroundColor(0xEEEEEE) }
.onClick(() => this.onBtnClick("C"))
GridItem() { Button("/").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("/"))
GridItem() { Button("*").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("*"))
GridItem() { Button("-").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("-"))
GridItem() { Button("7").fontSize(28) }
.onClick(() => this.onBtnClick("7"))
GridItem() { Button("8").fontSize(28) }
.onClick(() => this.onBtnClick("8"))
GridItem() { Button("9").fontSize(28) }
.onClick(() => this.onBtnClick("9"))
GridItem() { Button("+").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("+"))
GridItem() { Button("4").fontSize(28) }
.onClick(() => this.onBtnClick("4"))
GridItem() { Button("5").fontSize(28) }
.onClick(() => this.onBtnClick("5"))
GridItem() { Button("6").fontSize(28) }
.onClick(() => this.onBtnClick("6"))
GridItem() { Button("=").fontSize(28).backgroundColor(0x42A5F5).fontColor(Color.White) }
.onClick(() => this.onBtnClick("="))
GridItem() { Button("1").fontSize(28) }
.onClick(() => this.onBtnClick("1"))
GridItem() { Button("2").fontSize(28) }
.onClick(() => this.onBtnClick("2"))
GridItem() { Button("3").fontSize(28) }
.onClick(() => this.onBtnClick("3"))
GridItem() { Button(".").fontSize(28) }
.onClick(() => this.onBtnClick("."))
GridItem() { Button("0").fontSize(28).width("100%") }
.onClick(() => this.onBtnClick("0"))
}
绑定完成后,数字输入、切换运算符、一键重置等基础交互功能已经可以正常运行,接下来实现核心的四则运算逻辑。
六、四则运算核心方法与异常处理
运算逻辑是计算器的核心功能,我们单独封装 calcResult 方法,统一处理数值转换、分支运算、异常拦截、结果回显等逻辑,同时针对浮点精度、除数为零两大常见问题做优化处理。
6.1 运算方法完整代码
在组件内添加如下代码:
/**
* 四则运算核心方法
*/
calcResult(): void {
// 未选择运算符,不执行计算
if (this.operator === "") {
return
}
const secondNum: number = parseFloat(this.showText)
let result: number = 0
// 根据运算符执行对应运算
switch (this.operator) {
case "+":
result = this.firstNum + secondNum
break
case "-":
result = this.firstNum - secondNum
break
case "*":
result = this.firstNum * secondNum
break
case "/":
// 处理除数为0的异常场景
if (secondNum === 0) {
this.showText = "计算错误"
this.firstNum = 0
this.operator = ""
this.isNewInput = true
return
}
result = this.firstNum / secondNum
break
}
// 限制小数位数,优化浮点显示效果
result = parseFloat(result.toFixed(6))
// 更新界面,支持连续运算
this.showText = result.toString()
this.firstNum = result
this.operator = ""
this.isNewInput = true
}
6.2 代码逐段解析
- 前置判断
首先判断 operator 运算符变量是否为空,如果用户没有选择任何运算符就点击等于键,直接终止方法,不执行无效运算。
- 数值转换
使用 parseFloat() 将显示屏的字符串内容转为数值类型,赋值给 secondNum,作为第二个运算数。
- switch 分支运算
通过 switch 语句匹配运算符,分别执行加法、减法、乘法、除法运算,将计算结果存入 result 变量。
- 除数为零异常拦截
数学规则中,除数不能为 0,因此在除法分支中单独增加判断:如果第二个数字为 0,显示屏展示「计算错误」,同时重置所有变量,终止代码运行,彻底避免应用闪退、卡死问题,这也是程序容错设计的核心部分。
- 浮点精度优化
ArkTS 基于 JavaScript 内核,原生浮点运算会出现多余长尾小数。使用 toFixed(6) 保留 6 位小数,再转回数值类型,精简无效小数位,让展示结果更加整洁。
- 结果回显与连续运算支持
将最终结果转为字符串赋值给 showText 刷新页面;同时把结果赋值给 firstNum,清空运算符,标记为全新输入状态,此时用户可以直接点击运算符继续计算,实现连续运算功能。
七、项目完整整合代码
至此,所有功能代码全部编写完成。以下是 Index.ets 文件完整可运行源码,大家可以直接复制替换文件中所有内容,保证代码完整性:
@Entry
@Component
struct Index {
// 屏幕显示内容,响应式变量,数据变更自动刷新UI
@State showText: string = "0"
// 缓存第一个参与运算的数字
private firstNum: number = 0
// 记录用户选择的运算符
private operator: string = ""
// 标记是否开启新一轮输入
private isNewInput: boolean = true
/**
* 所有按钮统一点击事件
* @param value 按钮上的文本内容
*/
onBtnClick(value: string): void {
// 清空按钮逻辑
if (value === "C") {
this.showText = "0"
this.firstNum = 0
this.operator = ""
this.isNewInput = true
return
}
// 等于按钮,触发计算
if (value === "=") {
this.calcResult()
return
}
// 点击四则运算符,保存第一个数字与运算符号
if (["+", "-", "*", "/"].includes(value)) {
this.firstNum = parseFloat(this.showText)
this.operator = value
this.isNewInput = true
return
}
// 数字与小数点输入逻辑
if (this.isNewInput) {
this.showText = value === "." ? "0." : value
this.isNewInput = false
} else {
// 禁止重复输入小数点
if (value === "." && this.showText.includes(".")) {
return
}
this.showText += value
}
}
/**
* 四则运算核心方法
*/
calcResult(): void {
// 未选择运算符,不执行计算
if (this.operator === "") {
return
}
const secondNum: number = parseFloat(this.showText)
let result: number = 0
// 根据运算符执行对应运算
switch (this.operator) {
case "+":
result = this.firstNum + secondNum
break
case "-":
result = this.firstNum - secondNum
break
case "*":
result = this.firstNum * secondNum
break
case "/":
// 处理除数为0的异常场景
if (secondNum === 0) {
this.showText = "计算错误"
this.firstNum = 0
this.operator = ""
this.isNewInput = true
return
}
result = this.firstNum / secondNum
break
}
// 限制小数位数,优化浮点显示效果
result = parseFloat(result.toFixed(6))
// 更新界面,支持连续运算
this.showText = result.toString()
this.firstNum = result
this.operator = ""
this.isNewInput = true
}
build() {
Column() {
// 顶部显示屏
Text(this.showText)
.width("90%")
.height(120)
.fontSize(48)
.textAlign(TextAlign.End)
.padding({ right: 15 })
.backgroundColor(0xF5F5F5)
.borderRadius(12)
.margin({ top: 30, bottom: 20 })
// 底部按钮网格区域
Grid() {
GridItem() { Button("C").fontSize(28).backgroundColor(0xEEEEEE) }
.onClick(() => this.onBtnClick("C"))
GridItem() { Button("/").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("/"))
GridItem() { Button("*").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("*"))
GridItem() { Button("-").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("-"))
GridItem() { Button("7").fontSize(28) }
.onClick(() => this.onBtnClick("7"))
GridItem() { Button("8").fontSize(28) }
.onClick(() => this.onBtnClick("8"))
GridItem() { Button("9").fontSize(28) }
.onClick(() => this.onBtnClick("9"))
GridItem() { Button("+").fontSize(28).backgroundColor(0xFFB74D) }
.onClick(() => this.onBtnClick("+"))
GridItem() { Button("4").fontSize(28) }
.onClick(() => this.onBtnClick("4"))
GridItem() { Button("5").fontSize(28) }
.onClick(() => this.onBtnClick("5"))
GridItem() { Button("6").fontSize(28) }
.onClick(() => this.onBtnClick("6"))
GridItem() { Button("=").fontSize(28).backgroundColor(0x42A5F5).fontColor(Color.White) }
.onClick(() => this.onBtnClick("="))
GridItem() { Button("1").fontSize(28) }
.onClick(() => this.onBtnClick("1"))
GridItem() { Button("2").fontSize(28) }
.onClick(() => this.onBtnClick("2"))
GridItem() { Button("3").fontSize(28) }
.onClick(() => this.onBtnClick("3"))
GridItem() { Button(".").fontSize(28) }
.onClick(() => this.onBtnClick("."))
GridItem() { Button("0").fontSize(28).width("100%") }
.onClick(() => this.onBtnClick("0"))
}
.columnsTemplate("1fr 1fr 1fr 1fr")
.rowsGap(12)
.columnsGap(12)
.width("90%")
.height(420)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Start)
}
}

八、功能全量测试与效果验证
代码整合完成后,启动应用,逐项测试所有功能,验证每一个模块是否正常运行,同时验证容错逻辑是否生效。测试分为基础输入测试、常规运算测试、异常场景测试、辅助功能测试四大板块。
8.1 数字与小数点输入测试
操作流程:依次点击 0-9 数字按键,测试多位数连续输入;多次点击小数点按键,测试拦截逻辑。
预期效果:可正常输入多位整数;重复点击小数点时,页面不会出现多个小数点,数值格式合法。

8.2 常规四则运算测试
分别测试加法、减法、乘法、除法基础运算,示例操作:
- 输入 25 → 点击 + → 输入 15 → 点击 =,查看结果;
- 输入 99 → 点击 - → 输入 33 → 点击 =,查看结果;
- 输入 8 → 点击 * → 输入 7 → 点击 =,查看结果;
- 输入 80 → 点击 / → 输入 4 → 点击 =,查看结果。
预期效果:所有运算均可精准输出结果,浮点数值自动精简多余小数位。


8.3 除数为零异常测试
操作流程:任意输入一个数字,点击 / 除号,再输入 0,最后点击 = 等于键。
预期效果:页面展示「计算错误」,应用不会闪退、卡死,点击 C 可正常重置。

8.4 清空与连续运算测试
- 清空功能:任意输入数字、完成运算后,点击 C 键,页面立刻重置为初始 0,所有缓存数据清空;
- 连续运算:完成一次运算得出结果后,直接点击运算符、新数字、等于键,可基于上一次结果继续运算。
两项功能均正常运行,代表整体逻辑闭环完整。
九、开发常见问题分析与解决方案
在编写和运行代码的过程中,新手大概率会遇到各类报错、功能异常问题,本章节汇总高频问题、报错原因以及对应的解决办法,方便大家自主排查问题。
9.1 页面内容无法刷新
现象:点击数字按键,显示屏内容始终保持初始 0,没有任何变化。
原因:承载页面内容的变量 showText 没有添加 @State 装饰器,失去响应式能力,数据改变无法驱动视图刷新。
解决方案:检查变量定义代码,为展示变量补充 @State 装饰器。
9.2 可以重复输入多个小数点
现象:连续点击小数点,页面出现 1.2.3 这类非法格式。
原因:缺少小数点拦截判断逻辑,未使用 includes() 方法检测字符串内是否已存在小数点。
解决方案:在小数点输入分支中增加判断,已存在小数点则直接终止逻辑。
9.3 除法运算时应用闪退
现象:输入数字除以 0 后,应用直接退出、崩溃。
原因:未做除数为零的异常拦截,数学非法运算导致程序运行异常。
解决方案:在除法分支中添加 secondNum === 0 判断,主动拦截非法运算并重置状态。
9.4 运算结果出现超长浮点小数
现象:小数运算后,结果出现大量长尾无效小数,例如 0.1 + 0.2 = 0.30000000000000004。
原因:ArkTS 浮点运算原生精度问题,是语言底层特性。
解决方案:使用 toFixed(n) 方法限定小数保留位数,精简展示内容。
9.5 点击等于键无任何反应
现象:输入两个数字后点击等于键,页面没有计算结果。
原因:未选择运算符,operator 变量始终为空,前置判断直接终止运算方法。
解决方案:按照标准流程操作,先点击运算符再输入第二个数字。
十、项目总结与知识点拓展
回顾整个开发流程,我们从工程创建、变量定义、界面布局、交互逻辑、运算实现、异常处理完整走完了一套鸿蒙小型应用的开发流程,巩固了多项入门核心技能:
- 熟练掌握 DevEco Studio 基础操作、鸿蒙项目创建与运行流程,理解单页面应用的开发模式;
- 深度理解 @State 响应式变量与数据驱动视图的核心思想,这是鸿蒙声明式开发的核心基础;
- 掌握 Column、Grid、GridItem、Text、Button 五大高频基础组件的属性配置与实战用法,理解不同布局组件的适用场景;
- 学会按钮点击事件绑定、事件分发逻辑,掌握 if、switch 分支语句在业务逻辑中的综合运用;
- 掌握字符串与数值之间的相互转换方法,了解移动端应用基础容错设计的思路与实现方式;
- 建立基础的程序分层思维:数据层(全局变量)、视图层(UI布局)、逻辑层(交互与运算方法)。
更多推荐



所有评论(0)