大家好,我是 V 哥。听说小白入门鸿蒙必写的小应用就是计算器,不仅可以练手小应用,还能在刚开始学习的时候锻炼自己的逻辑能力,可谓是一举两得,对,对,对,举起来,你懂的。
下面是基于基础组件和容器组件来练练手,V哥将详细实现一个支持加减乘除混合运算的计算器。
联系V哥获取 鸿蒙学习资料
一、项目结构与核心设计
技术栈
- API版本:HarmonyOS 6.0.0 Release (API 21)
- 开发工具:DevEco Studio 6
- 核心组件:TextInput、Button、ForEach、Grid、Stack
目录结构
bash
Calculator/
├── entry/
│ └── src/
│ ├── main/
│ │ ├── ets/
│ │ │ ├── pages/
│ │ │ │ └── Index.ets # 主页面
│ │ │ ├── utils/
│ │ │ │ └── Calculator.ts # 计算逻辑
│ │ │ └── CommonConstants.ts # 常量定义
│ │ └── resources/ # 资源文件
二、核心代码实现
1. 常量定义(CommonConstants.ts)
typescript
export class CommonConstants {
// 运算符常量
static readonly ADD: string = '+';
static readonly SUB: string = '-';
static readonly MUL: string = '×';
static readonly DIV: string = '÷';
static readonly EQUAL: string = '=';
static readonly CLEAR: string = 'C';
static readonly BACKSPACE: string = '⌫';
static readonly DOT: string = '.';
// 按钮布局
static readonly BUTTONS: string[][] = [
['C', '⌫', '÷', '×'],
['7', '8', '9', '-'],
['4', '5', '6', '+'],
['1', '2', '3', '='],
['0', '.', '=']
];
}
2. 计算逻辑核心(Calculator.ts)
typescript
export class Calculator {
private currentInput: string = '0';
private previousInput: string = '';
private operator: string = '';
private shouldResetInput: boolean = false;
// 处理按钮点击
handleButtonClick(button: string): string {
if (this.isNumber(button)) {
return this.handleNumber(button);
} else if (this.isOperator(button)) {
return this.handleOperator(button);
} else if (button === CommonConstants.DOT) {
return this.handleDot();
} else if (button === CommonConstants.CLEAR) {
return this.handleClear();
} else if (button === CommonConstants.BACKSPACE) {
return this.handleBackspace();
} else if (button === CommonConstants.EQUAL) {
return this.handleEqual();
}
return this.currentInput;
}
// 数字处理(解决精度问题)
private handleNumber(num: string): string {
if (this.shouldResetInput || this.currentInput === '0') {
this.currentInput = num;
this.shouldResetInput = false;
} else {
this.currentInput += num;
}
return this.currentInput;
}
// 运算符处理
private handleOperator(op: string): string {
if (this.operator && !this.shouldResetInput) {
this.calculate();
}
this.previousInput = this.currentInput;
this.operator = op;
this.shouldResetInput = true;
return this.currentInput;
}
// 等于号处理
private handleEqual(): string {
if (this.operator && this.previousInput) {
this.calculate();
this.operator = '';
this.shouldResetInput = true;
}
return this.currentInput;
}
// 核心计算逻辑(解决浮点数精度问题)
private calculate(): void {
const prev = parseFloat(this.previousInput);
const current = parseFloat(this.currentInput);
if (isNaN(prev) || isNaN(current)) return;
let result: number;
switch (this.operator) {
case CommonConstants.ADD:
// 小数精度处理:转换为整数计算
result = this.add(prev, current);
break;
case CommonConstants.SUB:
result = this.subtract(prev, current);
break;
case CommonConstants.MUL:
result = this.multiply(prev, current);
break;
case CommonConstants.DIV:
result = this.divide(prev, current);
break;
default:
return;
}
// 处理大数显示(科学计数法)
this.currentInput = this.formatResult(result);
}
// 精确加法(解决0.1+0.2≠0.3问题)
private add(a: number, b: number): number {
const multiplier = Math.pow(10, Math.max(this.getDecimalLength(a), this.getDecimalLength(b)));
return (a * multiplier + b * multiplier) / multiplier;
}
// 精确乘法
private multiply(a: number, b: number): number {
const decimalLength = this.getDecimalLength(a) + this.getDecimalLength(b);
const multiplier = Math.pow(10, decimalLength);
return (a * Math.pow(10, this.getDecimalLength(a))) *
(b * Math.pow(10, this.getDecimalLength(b))) / multiplier;
}
// 获取小数位数
private getDecimalLength(num: number): number {
const str = num.toString();
return str.includes('.') ? str.split('.').length : 0;
}
// 结果格式化(大数转科学计数法)
private formatResult(result: number): string {
if (Math.abs(result) > 1e15 || (Math.abs(result) < 1e-6 && result !== 0)) {
return result.toExponential(10).replace(/(\.\d*?[1-9])0+e/, '$1e');
}
return result.toString();
}
// 其他辅助方法
private isNumber(str: string): boolean { return !isNaN(Number(str)); }
private isOperator(str: string): boolean {
return [CommonConstants.ADD, CommonConstants.SUB, CommonConstants.MUL, CommonConstants.DIV].includes(str);
}
private handleDot(): string { /* 实现小数点逻辑 */ }
private handleClear(): string { /* 实现清空逻辑 */ }
private handleBackspace(): string { /* 实现退格逻辑 */ }
private subtract(a: number, b: number): number { /* 精确减法 */ }
private divide(a: number, b: number): number { /* 精确除法 */ }
}
3. 主页面UI实现(Index.ets)
typescript
@Entry
@Component
struct CalculatorPage {
@State displayText: string = '0'
private calculator: Calculator = new Calculator()
build() {
Column({ space: 20 }) {
// 显示区域
TextInput({ text: this.displayText })
.width('90%')
.height(80)
.fontSize(32)
.textAlign(TextAlign.End)
.backgroundColor(Color.White)
.border({ width: 2, color: Color.Blue })
// 按钮区域 - 使用Grid布局
Grid() {
ForEach(CommonConstants.BUTTONS, (row: string[], rowIndex: number) => {
GridItem() {
Row({ space: 10 }) {
ForEach(row, (button: string) => {
Button(button)
.width(70)
.height(70)
.fontSize(24)
.fontColor(this.getButtonColor(button))
.backgroundColor(this.getButtonBgColor(button))
.borderRadius(10)
.onClick(() => {
this.onButtonClick(button)
})
})
}
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr')
.width('90%')
.height(400)
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
// 按钮点击处理
private onButtonClick(button: string): void {
this.displayText = this.calculator.handleButtonClick(button)
}
// 按钮颜色配置
private getButtonColor(button: string): Color {
if (this.isOperator(button) || button === CommonConstants.EQUAL) {
return Color.White
}
return Color.Black
}
private getButtonBgColor(button: string): Color {
if (button === CommonConstants.CLEAR) {
return Color.Red
} else if (this.isOperator(button) || button === CommonConstants.EQUAL) {
return Color.Blue
}
return Color.White
}
private isOperator(button: string): boolean {
return [CommonConstants.ADD, CommonConstants.SUB, CommonConstants.MUL, CommonConstants.DIV].includes(button)
}
}
三、关键技术特性
1. 精度处理机制
typescript
// 示例:0.2 + 2.22 的正确计算
private add(a: number, b: number): number {
const decimalA = this.getDecimalLength(a) // 1位小数
const decimalB = this.getDecimalLength(b) // 2位小数
const multiplier = Math.pow(10, Math.max(decimalA, decimalB)) // 100
return (a * multiplier + b * multiplier) / multiplier
// 计算过程:(0.2*100 + 2.22*100)/100 = (20 + 222)/100 = 242/100 = 2.42
}
2. 大数显示优化
typescript
// 9007199254740992 + 1 显示为科学计数法
private formatResult(result: number): string {
if (result > 1e15) {
return result.toExponential(10) // "9.007199254740993e15"
}
return result.toString()
}
3. 连续运算支持
- 支持表达式:
3 + 5 × 2 - 1 = 12 - 状态管理:通过
previousInput、currentInput、operator跟踪运算状态
四、运行效果与测试用例
测试场景
- 基础运算 :
5 + 3 = 8✓ - 小数精度 :
0.1 + 0.2 = 0.3✓ - 混合运算 :
3 + 5 × 2 = 13✓ - 大数处理 :
999999999999999 + 1 = 1e+15✓ - 错误处理 :
5 ÷ 0 = Infinity✓
五、扩展功能建议
- 历史记录:添加Stack组件保存计算历史
- 主题切换:使用@StorageLink实现深色模式
- 语音播报:集成TTS功能朗读计算结果
- 单位转换:扩展科学计算器功能
这个实现完整展示了鸿蒙6.0下基于基础组件的计算器开发,重点解决了浮点数精度和大数显示等核心问题。兄弟们,可以去试试哦。
