228 lines
5.7 KiB
TypeScript
228 lines
5.7 KiB
TypeScript
// pages/calculator/calculator.ts
|
||
Page({
|
||
data: {
|
||
displayValue: '0',
|
||
history: '',
|
||
operator: null as string | null,
|
||
firstOperand: null as number | null,
|
||
waitingForSecondOperand: false,
|
||
isScientific: false
|
||
},
|
||
|
||
onLoad() {
|
||
},
|
||
|
||
vibrate() {
|
||
// wx.vibrateShort({ type: 'light' });
|
||
},
|
||
|
||
toggleMode() {
|
||
this.vibrate();
|
||
this.setData({
|
||
isScientific: !this.data.isScientific
|
||
});
|
||
},
|
||
|
||
onDigit(e: any) {
|
||
this.vibrate();
|
||
const digit = e.currentTarget.dataset.digit;
|
||
const { displayValue, waitingForSecondOperand } = this.data;
|
||
|
||
// 科学模式允许更多数字
|
||
const limit = 15;
|
||
if (!waitingForSecondOperand && displayValue.length >= limit) {
|
||
return;
|
||
}
|
||
|
||
if (waitingForSecondOperand) {
|
||
this.setData({
|
||
displayValue: digit,
|
||
waitingForSecondOperand: false
|
||
});
|
||
} else {
|
||
this.setData({
|
||
displayValue: displayValue === '0' ? digit : displayValue + digit
|
||
});
|
||
}
|
||
},
|
||
|
||
onDot() {
|
||
this.vibrate();
|
||
const { displayValue, waitingForSecondOperand } = this.data;
|
||
if (waitingForSecondOperand) {
|
||
this.setData({
|
||
displayValue: '0.',
|
||
waitingForSecondOperand: false
|
||
});
|
||
} else if (displayValue.indexOf('.') === -1) {
|
||
this.setData({
|
||
displayValue: displayValue + '.'
|
||
});
|
||
}
|
||
},
|
||
|
||
onClear() {
|
||
this.vibrate();
|
||
this.setData({
|
||
displayValue: '0',
|
||
history: '',
|
||
operator: null,
|
||
firstOperand: null,
|
||
waitingForSecondOperand: false
|
||
});
|
||
},
|
||
|
||
onDelete() {
|
||
this.vibrate();
|
||
const { displayValue } = this.data;
|
||
if (displayValue.length > 1) {
|
||
this.setData({
|
||
displayValue: displayValue.slice(0, -1)
|
||
});
|
||
} else {
|
||
this.setData({ displayValue: '0' });
|
||
}
|
||
},
|
||
|
||
onToggleSign() {
|
||
this.vibrate();
|
||
const { displayValue } = this.data;
|
||
const newValue = parseFloat(displayValue) * -1;
|
||
this.setData({
|
||
displayValue: String(newValue)
|
||
});
|
||
},
|
||
|
||
onConstant(e: any) {
|
||
this.vibrate();
|
||
const type = e.currentTarget.dataset.const;
|
||
let val = 0;
|
||
if (type === 'pi') val = Math.PI;
|
||
if (type === 'e') val = Math.E;
|
||
|
||
this.setData({
|
||
displayValue: String(val).slice(0, 10),
|
||
waitingForSecondOperand: true // 下次输入将开启新数字,或者作为操作数
|
||
});
|
||
},
|
||
|
||
onMathFunc(e: any) { // 单操作数立即计算
|
||
this.vibrate();
|
||
const func = e.currentTarget.dataset.func;
|
||
let val = parseFloat(this.data.displayValue);
|
||
let result = 0;
|
||
let desc = '';
|
||
|
||
switch(func) {
|
||
case 'sin':
|
||
// 默认转为弧度计算 (度数 * PI / 180)
|
||
result = Math.sin(val * Math.PI / 180);
|
||
desc = `sin(${val})`;
|
||
break;
|
||
case 'cos':
|
||
result = Math.cos(val * Math.PI / 180);
|
||
desc = `cos(${val})`;
|
||
break;
|
||
case 'tan':
|
||
result = Math.tan(val * Math.PI / 180);
|
||
desc = `tan(${val})`;
|
||
break;
|
||
case 'log':
|
||
result = Math.log10(val);
|
||
desc = `log(${val})`;
|
||
break;
|
||
case 'ln':
|
||
result = Math.log(val);
|
||
desc = `ln(${val})`;
|
||
break;
|
||
case 'sqrt':
|
||
result = Math.sqrt(val);
|
||
desc = `√(${val})`;
|
||
break;
|
||
case 'pow2':
|
||
result = Math.pow(val, 2);
|
||
desc = `sqr(${val})`;
|
||
break;
|
||
case 'percent':
|
||
result = val / 100;
|
||
desc = `${val}%`;
|
||
break;
|
||
}
|
||
|
||
// 格式化结果
|
||
const formatted = parseFloat(result.toPrecision(12));
|
||
|
||
this.setData({
|
||
displayValue: String(formatted),
|
||
history: desc,
|
||
waitingForSecondOperand: true // 计算完后,下次输入数字是新数字
|
||
});
|
||
},
|
||
|
||
onOperator(e: any) {
|
||
this.vibrate();
|
||
const nextOperator = e.currentTarget.dataset.op;
|
||
const { displayValue, operator, firstOperand } = this.data;
|
||
const inputValue = parseFloat(displayValue);
|
||
|
||
if (operator && this.data.waitingForSecondOperand) {
|
||
this.setData({
|
||
operator: nextOperator,
|
||
// 更新历史记录中的符号
|
||
history: `${firstOperand} ${nextOperator}`
|
||
});
|
||
return;
|
||
}
|
||
|
||
let newFirstOperand = firstOperand;
|
||
|
||
if (firstOperand == null) {
|
||
newFirstOperand = inputValue;
|
||
} else if (operator) {
|
||
const result = this.performCalculation(operator, firstOperand, inputValue);
|
||
newFirstOperand = result;
|
||
this.setData({
|
||
displayValue: String(result),
|
||
});
|
||
}
|
||
|
||
this.setData({
|
||
firstOperand: newFirstOperand,
|
||
waitingForSecondOperand: true,
|
||
operator: nextOperator,
|
||
history: `${newFirstOperand} ${nextOperator}`
|
||
});
|
||
},
|
||
|
||
onEqual() {
|
||
this.vibrate();
|
||
const { displayValue, operator, firstOperand } = this.data;
|
||
const inputValue = parseFloat(displayValue);
|
||
|
||
if (operator && firstOperand != null) {
|
||
const result = this.performCalculation(operator, firstOperand, inputValue);
|
||
|
||
this.setData({
|
||
displayValue: String(result),
|
||
firstOperand: null,
|
||
operator: null,
|
||
waitingForSecondOperand: true,
|
||
history: `${firstOperand} ${operator} ${inputValue} =`
|
||
});
|
||
}
|
||
},
|
||
|
||
performCalculation(op: string, first: number, second: number): number {
|
||
let result = 0;
|
||
switch(op) {
|
||
case '+': result = first + second; break;
|
||
case '-': result = first - second; break;
|
||
case '×': result = first * second; break;
|
||
case '÷': result = first / second; break;
|
||
default: return second;
|
||
}
|
||
const precision = 10000000000;
|
||
return Math.round(result * precision) / precision;
|
||
}
|
||
})
|