191 lines
4.2 KiB
JavaScript
191 lines
4.2 KiB
JavaScript
// ===== 计算器状态 =====
|
||
let currentInput = '0'; // 当前输入的数字字符串
|
||
let previousValue = null; // 上一个操作数
|
||
let currentOperator = null; // 当前运算符
|
||
let shouldResetInput = false; // 下次输入是否覆盖当前值
|
||
|
||
// ===== DOM 元素 =====
|
||
const display = document.getElementById('display');
|
||
|
||
/**
|
||
* 更新显示区域
|
||
*/
|
||
function updateDisplay() {
|
||
display.textContent = currentInput;
|
||
}
|
||
|
||
/**
|
||
* 输入数字
|
||
* @param {string} num
|
||
*/
|
||
function inputNumber(num) {
|
||
if (shouldResetInput) {
|
||
currentInput = num;
|
||
shouldResetInput = false;
|
||
} else {
|
||
// 避免出现多个前导 0
|
||
currentInput = currentInput === '0' ? num : currentInput + num;
|
||
}
|
||
updateDisplay();
|
||
}
|
||
|
||
/**
|
||
* 输入小数点
|
||
*/
|
||
function inputDecimal() {
|
||
if (shouldResetInput) {
|
||
currentInput = '0.';
|
||
shouldResetInput = false;
|
||
} else if (!currentInput.includes('.')) {
|
||
currentInput += '.';
|
||
}
|
||
updateDisplay();
|
||
}
|
||
|
||
/**
|
||
* 执行计算
|
||
* @param {number} a
|
||
* @param {number} b
|
||
* @param {string} op
|
||
* @returns {number}
|
||
*/
|
||
function calculate(a, b, op) {
|
||
switch (op) {
|
||
case '+': return a + b;
|
||
case '-': return a - b;
|
||
case '×': return a * b;
|
||
case '÷':
|
||
if (b === 0) return NaN; // 除零处理
|
||
return a / b;
|
||
default: return b;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 选择运算符
|
||
* @param {string} op
|
||
*/
|
||
function chooseOperator(op) {
|
||
const inputValue = parseFloat(currentInput);
|
||
|
||
// 连续按运算符时,先计算前一步
|
||
if (previousValue !== null && currentOperator && !shouldResetInput) {
|
||
const result = calculate(previousValue, inputValue, currentOperator);
|
||
if (isNaN(result)) {
|
||
currentInput = '错误';
|
||
previousValue = null;
|
||
currentOperator = null;
|
||
shouldResetInput = true;
|
||
updateDisplay();
|
||
return;
|
||
}
|
||
previousValue = result;
|
||
currentInput = formatNumber(result);
|
||
} else {
|
||
previousValue = inputValue;
|
||
}
|
||
|
||
currentOperator = op;
|
||
shouldResetInput = true;
|
||
updateDisplay();
|
||
}
|
||
|
||
/**
|
||
* 按等号计算结果
|
||
*/
|
||
function pressEquals() {
|
||
if (previousValue === null || currentOperator === null) return;
|
||
|
||
const inputValue = parseFloat(currentInput);
|
||
const result = calculate(previousValue, inputValue, currentOperator);
|
||
|
||
if (isNaN(result)) {
|
||
currentInput = '错误';
|
||
} else {
|
||
currentInput = formatNumber(result);
|
||
}
|
||
|
||
previousValue = null;
|
||
currentOperator = null;
|
||
shouldResetInput = true;
|
||
updateDisplay();
|
||
}
|
||
|
||
/**
|
||
* 清除所有状态
|
||
*/
|
||
function clearAll() {
|
||
currentInput = '0';
|
||
previousValue = null;
|
||
currentOperator = null;
|
||
shouldResetInput = false;
|
||
updateDisplay();
|
||
}
|
||
|
||
/**
|
||
* 格式化数字,避免过长的小数
|
||
* @param {number} num
|
||
* @returns {string}
|
||
*/
|
||
function formatNumber(num) {
|
||
if (!isFinite(num)) return '错误';
|
||
// 保留最多 10 位有效数字,去掉多余的 0
|
||
return parseFloat(num.toPrecision(12)).toString();
|
||
}
|
||
|
||
// ===== 事件绑定 =====
|
||
document.querySelector('.keys').addEventListener('click', (e) => {
|
||
const btn = e.target.closest('button');
|
||
if (!btn) return;
|
||
|
||
const action = btn.dataset.action;
|
||
|
||
switch (action) {
|
||
case 'number':
|
||
inputNumber(btn.dataset.value);
|
||
break;
|
||
case 'decimal':
|
||
inputDecimal();
|
||
break;
|
||
case 'operator':
|
||
chooseOperator(btn.dataset.op);
|
||
break;
|
||
case 'equals':
|
||
pressEquals();
|
||
break;
|
||
case 'clear':
|
||
clearAll();
|
||
break;
|
||
}
|
||
});
|
||
|
||
// ===== 键盘支持 =====
|
||
document.addEventListener('keydown', (e) => {
|
||
const key = e.key;
|
||
|
||
if (/^[0-9]$/.test(key)) {
|
||
inputNumber(key);
|
||
} else if (key === '.') {
|
||
inputDecimal();
|
||
} else if (key === '+' || key === '-' || key === '*' || key === '/') {
|
||
const map = { '*': '×', '/': '÷', '+': '+', '-': '-' };
|
||
chooseOperator(map[key]);
|
||
} else if (key === 'Enter' || key === '=') {
|
||
e.preventDefault();
|
||
pressEquals();
|
||
} else if (key === 'Escape' || key.toLowerCase() === 'c') {
|
||
clearAll();
|
||
} else if (key === 'Backspace') {
|
||
// 退格删除
|
||
if (currentInput.length > 1 && currentInput !== '错误') {
|
||
currentInput = currentInput.slice(0, -1);
|
||
} else {
|
||
currentInput = '0';
|
||
}
|
||
updateDisplay();
|
||
}
|
||
});
|
||
|
||
// ===== 初始化 =====
|
||
updateDisplay();
|