RidgeUI页面脚本开发系列:计算器页面脚本开发
我们首先看看计算器。 虽然大家日常经常会使用它,但是真要实现它,还需要进行一些分析 从用户交互来讲,计算器是:
- 有很多按键,除了0-9、加减乘除、等于、清除是标配,而复杂一些的计算器会提供更多计算功能
- 点击按键时,屏幕会显示相关结果,例如计算式行和当前结果行 (我们实体计算器一般因为屏幕支持原因,不包含计算式行)
从交互分析来看,需要提供一个方法来处理每个按键按下事件。同时提供2个页面状态,显示根据按键的动作,更新计算结果行和计算式行的内容
为此,我们可以生成以下程序结构
export default {
name: 'Calculator',
state: {
currentDisplay: '0', // 当前结果行
lastOperation: '' // 计算式行
},
actions: {
onKeyPressed (key) { // 按键按下
}
}
}
输入数字
计算器按下数字键时,屏幕如何展示?一般是直接增加数字
const appendNumber = (context, n) => {
if (context.currentDisplay === '0' || context.shouldResetScreen) {
resetScreen(context)
}
context.currentDisplay += n
}
const resetScreen = (context) => {
context.currentDisplay = '0'
context.shouldResetScreen = false
}
但如果之前输入过0, 那么00是没啥意义的 就将之前的0去除
将方法加入整体判断,代码如下:
export default {
name: 'Calculator',
state: {
currentDisplay: '', // 当前结果行
lastOperation: '' // 计算式行
},
actions: {
onKeyPressed (key) { // 按键按下
const code = key.charCodeAt(0)
if (code >= 48 && code <= 57) {
appendNumber(this, key)
}
}
}
}
处理加减乘除
输入计算符号时,需要有以下考虑:
- 之前已经输入完整的例如 1+2, 在输入计算相当于先计算出3 在设置当前计算符
- 将现在屏幕上数字设置为计算左侧
- 设置为当前计算符号 (因为可能连续输入计算符号)
- 更新计算式行
- 后面输入数字会从头输入
方法如下:
const convertOperator = keyboardOperator => { // 转换展示字符
if (keyboardOperator === '/') return '÷'
if (keyboardOperator === '*') return '×'
if (keyboardOperator === '-') return '−'
if (keyboardOperator === '+') return '+'
return keyboardOperator
}
const setOperation = (context, operator) => { // 设置运算符
// 如果有计算符先计算
if (context.currentOperation != null) evaluate(context)
context.firstOperand = context.currentDisplay
context.currentOperation = operator
context.lastOperation = `${context.firstOperand} ${convertOperator(operator)}`
context.shouldResetScreen = true
}
处理计算
计算发生在按下符号或者等号时处理
const add = (a, b) => {
return a + b
}
const substract = (a, b) => {
return a - b
}
const multiply = (a, b) => {
return a * b
}
const divide = (a, b) => {
return a / b
}
const operate = (operator, a, b) => {
a = Number(a)
b = Number(b)
switch (operator) {
case '+':
return add(a, b)
case '-':
return substract(a, b)
case '*':
return multiply(a, b)
case '/':
if (b === 0) return null
else return divide(a, b)
default:
return null
}
}
const roundResult = number => {
return Math.round(number * 1000) / 1000
}
const evaluate = context => { // 计算
if (context.currentOperation == null || context.shouldResetScreen) return
if (context.currentOperation === '/' && context.currentDisplay === '0') {
alert("You can't divide by 0!")
return
}
context.secondOperand = context.currentDisplay
context.currentDisplay = roundResult(
operate(context.currentOperation, context.firstOperand, context.secondOperand)
)
context.lastOperation = `${context.firstOperand} ${convertOperator(context.currentOperation)} ${context.secondOperand} =`
context.currentOperation = null
}
上面处理加减乘除不再赘述。 计算过程中需要更新计算式行与结果行, 同时清空现在的计算符号
其他按键处理
按键回退,如果没了屏幕置为0
const back = context => { // 回退
context.currentDisplay = context.currentDisplay.toString().slice(0, -1) || '0'
}
切换正负。注意这个计算不存在-0
const toggleNegative = context => { // 切换正负数
if (context.currentDisplay) {
context.currentDisplay = -Number(context.currentDisplay)
}
}
全清空:将所有变量设置为初始状态
const clear = context => { // AC
context.currentDisplay = '0'
context.lastOperation = ''
context.firstOperand = ''
context.secondOperand = ''
context.currentOperation = null
}
输入小数点。 值得注意的逻辑就是如果当前输入过点,那么当前输入就无效。 如果当前为0,那就是 0.x
const appendPoint = context => { // 输入.点
if (context.shouldResetScreen) context.resetScreen()
if (context.currentDisplay.includes('.')) return
context.currentDisplay += '.'
}
增加键盘绑定
最后,如果在电脑上运行,我们增加对按键的绑定,让用户按小键盘就能进行计算
const handleKeyboardInput = (context, key) => {
if (key >= 0 && key <= 9) appendNumber(context, key)
if (key === '.') appendPoint(context)
if (key === '%') handlePercent(context)
if (key === '=' || key === 'Enter') evaluate(context)
if (key === 'Backspace') back(context)
if (key === 'Escape') clear(context)
if (key === '+' || key === '-' || key === '*' || key === '/') setOperation(context,key)
}
同时修改setup和destory
setup() {
this.keyDownhandler = event => {
handleKeyboardInput(this, event.key)
}
window.addEventListener('keydown', this.keyDownhandler)
},
destory () {
window.removeEventListener('keydown', this.keyDownhandler)
},
回顾和思考
- 上述逻辑实际不是一蹴而就的,大家经常使用计算器,这其中临时变量的定义也时随着开发逐步明确的
- 既然算法很明确,我们可以像AI提问: 使用js制作一个计算器应用。有一个处理按键按下的方法,参数为 加减乘除、小数点、数字、等于、清除、回退等输入字符,方法执行时,将结果更新到context.currentDisplay 和context.lastOperation 这2个值上面,表示当前屏幕显示及上次计算表达式。 看看AI是否能给出完整的结果
- 当点击计算器的百分号,会发生什么? 结果和处理可能比你想象的复杂,留给大家思考
附录
可以通过这个地址查看计算器最终效果。 ridgeui.com/npm/ridge-c…
完整脚本地址: ridgeui.com/npm/ridge-c…