RidgeUI页面脚本开发系列:计算器页面脚本开发

82 阅读4分钟

RidgeUI页面脚本开发系列:计算器页面脚本开发

在这里插入图片描述

我们首先看看计算器。 虽然大家日常经常会使用它,但是真要实现它,还需要进行一些分析 从用户交互来讲,计算器是:

  1. 有很多按键,除了0-9、加减乘除、等于、清除是标配,而复杂一些的计算器会提供更多计算功能
  2. 点击按键时,屏幕会显示相关结果,例如计算式行和当前结果行 (我们实体计算器一般因为屏幕支持原因,不包含计算式行)

从交互分析来看,需要提供一个方法来处理每个按键按下事件。同时提供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. 之前已经输入完整的例如 1+2, 在输入计算相当于先计算出3 在设置当前计算符
  2. 将现在屏幕上数字设置为计算左侧
  3. 设置为当前计算符号 (因为可能连续输入计算符号)
  4. 更新计算式行
  5. 后面输入数字会从头输入

方法如下:


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)
},

回顾和思考

  1. 上述逻辑实际不是一蹴而就的,大家经常使用计算器,这其中临时变量的定义也时随着开发逐步明确的
  2. 既然算法很明确,我们可以像AI提问: 使用js制作一个计算器应用。有一个处理按键按下的方法,参数为 加减乘除、小数点、数字、等于、清除、回退等输入字符,方法执行时,将结果更新到context.currentDisplay 和context.lastOperation 这2个值上面,表示当前屏幕显示及上次计算表达式。 看看AI是否能给出完整的结果
  3. 当点击计算器的百分号,会发生什么? 结果和处理可能比你想象的复杂,留给大家思考

附录

可以通过这个地址查看计算器最终效果。 ridgeui.com/npm/ridge-c…

完整脚本地址: ridgeui.com/npm/ridge-c…