当前位置: 首页 > news >正文

微信小程序开发实战:手把手教你从零撸一个高精度计算器(附完整源码)

微信小程序开发实战:从零构建高精度科学计算器

在移动互联网时代,微信小程序以其轻量级、即用即走的特性成为开发者展示技能的热门平台。而计算器作为基础工具类应用,看似简单却暗藏玄机——从界面布局到状态管理,从事件处理到浮点数精度控制,每一个环节都能考验开发者的基本功。本文将带你从零开始,打造一个支持连续运算、具备金融级计算精度的科学计算器小程序。

1. 项目初始化与基础配置

1.1 创建小程序项目

首先通过微信开发者工具创建新项目,选择"小程序"类型,填写AppID(或使用测试号),项目名称设为"PrecisionCalculator"。创建完成后,目录结构应包含:

├── pages/ │ └── index/ │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── utils/ ├── app.js ├── app.json ├── app.wxss └── project.config.json

app.json中配置导航栏样式:

{ "window": { "navigationBarTitleText": "高精度计算器", "navigationBarBackgroundColor": "#1E90FF", "navigationBarTextStyle": "white" } }

1.2 基础页面结构搭建

修改index.wxml构建计算器骨架:

<view class="container"> <!-- 结果显示区域 --> <view class="display"> <view class="formula">{{formula}}</view> <view class="result">{{currentValue}}</view> </view> <!-- 按钮区域 --> <view class="keyboard"> <view class="row" wx:for="{{buttons}}" wx:key="index"> <button wx:for="{{item}}" wx:key="value" >// 精确加法 function accAdd(num1, num2) { const [int1, dec1 = ''] = num1.toString().split('.') const [int2, dec2 = ''] = num2.toString().split('.') const maxScale = Math.max(dec1.length, dec2.length) const scale = Math.pow(10, maxScale) return (num1 * scale + num2 * scale) / scale } // 精确乘法 function accMul(num1, num2) { let m = 0 const s1 = num1.toString() const s2 = num2.toString() try { m += s1.split('.')[1].length } catch(e) {} try { m += s2.split('.')[1].length } catch(e) {} return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m) } module.exports = { add: accAdd, sub: (a, b) => accAdd(a, -b), mul: accMul, div: (a, b) => accMul(a, 1/b) }

2.2 状态管理模块

创建calculator.js管理计算状态:

const math = require('./math') class Calculator { constructor() { this.reset() } reset() { this.currentValue = '0' this.storedValue = null this.operator = null this.waitingForOperand = false this.formula = '' } inputDigit(digit) { if (this.waitingForOperand) { this.currentValue = digit this.waitingForOperand = false } else { this.currentValue = this.currentValue === '0' ? digit : this.currentValue + digit } } inputDecimal() { if (this.waitingForOperand) { this.currentValue = '0.' this.waitingForOperand = false return } if (!this.currentValue.includes('.')) { this.currentValue += '.' } } performOperation(nextOperator) { const inputValue = parseFloat(this.currentValue) if (this.storedValue === null) { this.storedValue = inputValue } else if (this.operator) { const currentValue = this.storedValue || 0 switch(this.operator) { case '+': this.storedValue = math.add(currentValue, inputValue); break case '-': this.storedValue = math.sub(currentValue, inputValue); break case '×': this.storedValue = math.mul(currentValue, inputValue); break case '÷': this.storedValue = math.div(currentValue, inputValue); break } } this.waitingForOperand = true this.operator = nextOperator this.formula = `${this.storedValue} ${this.operator || ''}` } } module.exports = Calculator

3. 界面交互实现

3.1 按钮布局与样式

index.wxss中定义计算器样式:

.container { height: 100vh; display: flex; flex-direction: column; background: #f5f5f5; } .display { flex: 2; padding: 20rpx; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-end; background: #2c3e50; } .formula { color: rgba(255,255,255,0.7); font-size: 36rpx; margin-bottom: 20rpx; } .result { color: white; font-size: 72rpx; } .keyboard { flex: 3; display: flex; flex-direction: column; background: #ecf0f1; } .row { flex: 1; display: flex; } .btn { flex: 1; margin: 5rpx; border-radius: 10rpx; font-size: 40rpx; display: flex; justify-content: center; align-items: center; background: white; } .operator { background: #f39c12; color: white; } .zero { flex: 2; }

3.2 事件处理逻辑

index.js中实现按钮交互:

const Calculator = require('../../utils/calculator') Page({ data: { currentValue: '0', formula: '', buttons: [ [ { label: 'C', value: 'clear', type: 'function' }, { label: '±', value: 'toggleSign', type: 'function' }, { label: '%', value: 'percentage', type: 'function' }, { label: '÷', value: '÷', type: 'operator' } ], [ { label: '7', value: '7', type: 'digit' }, { label: '8', value: '8', type: 'digit' }, { label: '9', value: '9', type: 'digit' }, { label: '×', value: '×', type: 'operator' } ], [ { label: '4', value: '4', type: 'digit' }, { label: '5', value: '5', type: 'digit' }, { label: '6', value: '6', type: 'digit' }, { label: '-', value: '-', type: 'operator' } ], [ { label: '1', value: '1', type: 'digit' }, { label: '2', value: '2', type: 'digit' }, { label: '3', value: '3', type: 'digit' }, { label: '+', value: '+', type: 'operator' } ], [ { label: '0', value: '0', type: 'digit' }, { label: '.', value: '.', type: 'decimal' }, { label: '⌫', value: 'backspace', type: 'function' }, { label: '=', value: '=', type: 'operator' } ] ] }, onLoad() { this.calculator = new Calculator() }, handleTap(e) { const { value, type } = e.currentTarget.dataset switch(type) { case 'digit': this.calculator.inputDigit(value) break case 'decimal': this.calculator.inputDecimal() break case 'operator': this.calculator.performOperation(value) break case 'function': this.handleFunction(value) break } this.updateDisplay() }, handleFunction(func) { switch(func) { case 'clear': this.calculator.reset() break case 'toggleSign': this.calculator.currentValue = String(-parseFloat(this.calculator.currentValue)) break case 'percentage': this.calculator.currentValue = String(parseFloat(this.calculator.currentValue) / 100) break case 'backspace': this.handleBackspace() break } }, handleBackspace() { const { currentValue } = this.calculator if (currentValue.length === 1 || (currentValue.length === 2 && currentValue.startsWith('-'))) { this.calculator.currentValue = '0' } else { this.calculator.currentValue = currentValue.slice(0, -1) } }, updateDisplay() { this.setData({ currentValue: this.calculator.currentValue, formula: this.calculator.formula }) } })

4. 高级功能扩展

4.1 连续计算与历史记录

扩展calculator.js支持计算历史:

class EnhancedCalculator extends Calculator { constructor() { super() this.history = [] } performOperation(nextOperator) { // ...原有逻辑... if (nextOperator === '=') { this.history.push({ formula: `${this.storedValue} ${this.operator} ${this.currentValue}`, result: this.storedValue }) } } getHistory() { return this.history } }

4.2 科学计算功能

添加科学计算函数:

// 在math.js中添加 function sqrt(num) { if (num < 0) throw new Error('负数不能开平方') let result = num const precision = 0.000001 while (Math.abs(result * result - num) > precision) { result = (result + num / result) / 2 } return result } // 在Calculator类中添加 handleScientific(func) { switch(func) { case 'sqrt': this.currentValue = String(math.sqrt(parseFloat(this.currentValue))) break case 'square': this.currentValue = String(math.mul(parseFloat(this.currentValue), parseFloat(this.currentValue))) break case 'reciprocal': this.currentValue = String(math.div(1, parseFloat(this.currentValue))) break } }

4.3 主题切换功能

通过小程序全局样式变量实现主题切换:

// app.wxss :root { --primary-color: #1E90FF; --secondary-color: #FF8C00; --bg-color: #f5f5f5; --text-color: #333; } .dark-theme { --primary-color: #4A148C; --secondary-color: #FF6D00; --bg-color: #121212; --text-color: #f5f5f5; }

然后在页面中动态切换类名:

toggleTheme() { const theme = this.data.theme === 'light' ? 'dark' : 'light' this.setData({ theme }) wx.setStorageSync('calculator_theme', theme) }
http://www.cnnetsun.cn/news/2047554.html

相关文章:

  • 从单机到集群:手把手教你用LSF社区版搭建个人高性能计算(HPC)学习环境
  • 告别BDC!用SAP标准函数K_SRULE_SAVE_UTASK搞定WBS结算规则批量维护(附完整ABAP代码)
  • 后端Java面试题 (八股文+场景题)及答案全面总结(2026版)
  • Social Force Model在自动驾驶感知模块中的应用:如何让车辆‘理解’行人意图
  • 从风控到个人记账:一个Python脚本,搞定支付宝账单PDF的数据清洗与分析
  • Ubuntu 16.04 上搜狗输入法卸载不干净?试试这个彻底清理脚本(附ibus/fcitx配置)
  • OpenRGB:打破RGB品牌壁垒,让灯光控制回归简单与自由
  • MZmine 3:从质谱数据到科学发现的完整开源解决方案
  • 终极指南:GetQzonehistory免费备份QQ空间历史说说的完整教程
  • 通达信缠论插件ChanlunX:3步实现股票走势智能识别,告别手动画线的烦恼
  • DevEco Studio报错后,项目目录里多了一堆.map和.js文件?别慌,用这个插件一键清理ArkTS缓存
  • 3分钟告别英文困扰!FigmaCN中文插件让你的设计效率翻倍
  • 告别小字屏!用STM32F407的FSMC驱动TFTLCD,轻松显示32/48/64点阵大字体
  • 树莓派新手必看:默认root账户是禁用的,教你三步激活并设置密码
  • Python的__enter__方法资源
  • 谷歌推广和seo收录是一回事吗?搞错概念会让你的SEO预算全打水漂
  • 5步掌握暗黑破坏神2存档编辑器:打造你的专属游戏体验
  • 告别点灯!用STM32F103和2.4寸TFT屏做个迷你天气站(SPI驱动教程)
  • 【SCPI】从零到一:掌握仪器自动化编程的核心语法
  • 别再手动敲命令了!用Python+Netmiko批量备份Cisco设备配置(附完整脚本)
  • 手把手教你用Marlin 2.1.x配置双Z轴与自动调平(RAMPS 1.4 + TMC2208实战)
  • 告别模型复制粘贴:手把手教你用Simulink Variant子系统管理多版本需求
  • 5分钟打造专业级字幕!VideoSrt让你告别繁琐的手动字幕制作
  • WebUploader能否支持航空航天领域的目录结构上传?
  • TensorBoardX终极指南:10个技巧让深度学习可视化更简单高效
  • OpenShadingLanguage在电影制作中的应用:从《蜘蛛侠》到《曼达洛人》的完整案例
  • 如何让知识无障碍传播:B站公开课目录的终极搬运指南
  • 工业视觉避坑指南:Halcon点云匹配中RelSamplingDistance参数怎么调?
  • Docker 27资源回收失败诊断矩阵(含strace+crun+metrics-server三重验证流程,仅限边缘场景)
  • 从渔船避让到潜艇航行:聊聊SAR和光学卫星如何帮我们预警海洋‘水下风暴’