<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算器</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei", system-ui, sans-serif;
background: #202020;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
user-select: none;
}
/* Windows 11 计算器窗口 */
.calc-window {
width: 340px;
height: 560px;
background: #202020;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 标题栏 */
.title-bar {
height: 40px;
display: flex;
align-items: center;
padding-left: 16px;
-webkit-app-region: drag;
flex-shrink: 0;
}
.title-bar .mode-title {
font-size: 13px;
font-weight: 600;
color: #ffffff;
display: flex;
align-items: center;
gap: 8px;
}
.title-bar .mode-title::before {
content: "";
display: inline-block;
width: 16px;
height: 16px;
border: 1.5px solid #fff;
border-radius: 3px;
position: relative;
}
.title-bar .mode-title::before {
background:
linear-gradient(#fff, #fff) 4px 4px / 3px 3px no-repeat,
linear-gradient(#fff, #fff) 9px 4px / 3px 3px no-repeat,
linear-gradient(#fff, #fff) 4px 9px / 3px 3px no-repeat,
linear-gradient(#fff, #fff) 9px 9px / 3px 3px no-repeat;
background-color: transparent;
}
/* 显示区域 */
.display {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
padding: 8px 16px 12px;
min-height: 120px;
overflow: hidden;
}
.expression {
font-size: 14px;
color: #a0a0a0;
min-height: 20px;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
direction: rtl;
text-align: right;
font-weight: 400;
}
.result {
font-size: 48px;
font-weight: 600;
color: #ffffff;
line-height: 1.1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
direction: rtl;
text-align: right;
letter-spacing: -0.5px;
}
.result.shrink { font-size: 32px; }
.result.shrink-more { font-size: 24px; }
/* 内存按钮行 */
.memory-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 2px;
padding: 0 4px 4px;
flex-shrink: 0;
}
.mem-btn {
background: transparent;
border: none;
color: #8a8a8a;
font-size: 12px;
font-family: inherit;
height: 32px;
border-radius: 4px;
cursor: pointer;
transition: background 0.1s;
}
.mem-btn:hover { background: #2d2d2d; }
.mem-btn:active { background: #383838; }
.mem-btn:disabled { opacity: 0.35; cursor: default; }
.mem-btn:disabled:hover { background: transparent; }
/* 键盘 */
.keypad {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2px;
padding: 0 4px 4px;
flex-shrink: 0;
}
.key {
height: 56px;
border: none;
border-radius: 4px;
font-family: inherit;
font-size: 18px;
font-weight: 400;
cursor: pointer;
transition: background 0.08s, transform 0.05s;
color: #ffffff;
background: #323232;
display: flex;
align-items: center;
justify-content: center;
}
.key:hover { background: #3b3b3b; }
.key:active { background: #2a2a2a; transform: scale(0.97); }
/* 数字键稍亮 */
.key.num {
background: #3b3b3b;
font-size: 20px;
font-weight: 600;
}
.key.num:hover { background: #454545; }
.key.num:active { background: #333; }
/* 运算符键 */
.key.op {
font-size: 20px;
}
/* 等号键 */
.key.equals {
background: #4cc2ff;
color: #000;
font-size: 22px;
font-weight: 600;
}
.key.equals:hover { background: #5ccaff; }
.key.equals:active { background: #3eb5f0; }
/* 功能键(C、⌫、%、1/x、x²、√)更暗 */
.key.func {
background: #2d2d2d;
font-size: 16px;
}
.key.func:hover { background: #383838; }
.key.func:active { background: #262626; }
/* 键盘焦点样式 */
.key:focus-visible, .mem-btn:focus-visible {
outline: 2px solid #4cc2ff;
outline-offset: -2px;
}
/* 底部导航栏(模拟 Win11 计算器底部菜单) */
.bottom-nav {
height: 44px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
border-top: 1px solid #2a2a2a;
flex-shrink: 0;
padding: 0 8px;
}
.nav-btn {
background: transparent;
border: none;
color: #8a8a8a;
width: 36px;
height: 32px;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
transition: background 0.1s;
}
.nav-btn:hover { background: #2d2d2d; color: #ccc; }
.nav-btn.active { color: #4cc2ff; }
/* 响应式:窗口较小时微调 */
@media (max-height: 500px) {
.key { height: 44px; font-size: 16px; }
.result { font-size: 36px; }
}
</style>
</head>
<body>
<div class="calc-window">
<!-- 标题栏 -->
<div class="title-bar">
<div class="mode-title">标准</div>
</div>
<!-- 显示区 -->
<div class="display">
<div class="expression" id="expression"></div>
<div class="result" id="result">0</div>
</div>
<!-- 内存按钮行 -->
<div class="memory-row">
<button class="mem-btn" id="memClear" disabled>MC</button>
<button class="mem-btn" id="memRecall" disabled>MR</button>
<button class="mem-btn" id="memAdd">M+</button>
<button class="mem-btn" id="memSub">M−</button>
<button class="mem-btn" id="memStore">MS</button>
</div>
<!-- 键盘 -->
<div class="keypad">
<button class="key func" data-action="percent">%</button>
<button class="key func" data-action="clear">CE</button>
<button class="key func" data-action="clearAll">C</button>
<button class="key func" data-action="backspace">⌫</button>
<button class="key func" data-action="reciprocal">¹/x</button>
<button class="key func" data-action="square">x²</button>
<button class="key func" data-action="sqrt">²√x</button>
<button class="key op" data-op="÷">÷</button>
<button class="key num" data-num="7">7</button>
<button class="key num" data-num="8">8</button>
<button class="key num" data-num="9">9</button>
<button class="key op" data-op="×">×</button>
<button class="key num" data-num="4">4</button>
<button class="key num" data-num="5">5</button>
<button class="key num" data-num="6">6</button>
<button class="key op" data-op="−">−</button>
<button class="key num" data-num="1">1</button>
<button class="key num" data-num="2">2</button>
<button class="key num" data-num="3">3</button>
<button class="key op" data-op="+">+</button>
<button class="key func" data-action="negate">±</button>
<button class="key num" data-num="0">0</button>
<button class="key num" data-num=".">.</button>
<button class="key equals" data-action="equals">=</button>
</div>
<!-- 底部导航(装饰性,模拟 Win11 计算器) -->
<div class="bottom-nav">
<button class="nav-btn active" title="标准">≡</button>
<button class="nav-btn" title="科学">ƒ</button>
<button class="nav-btn" title="程序员"></></button>
<button class="nav-btn" title="日期计算">📅</button>
</div>
</div>
<script>
(function() {
'use strict';
// ===== 状态 =====
let current = '0'; // 当前输入的数字(字符串)
let previous = null; // 上一个操作数(字符串或 null)
let operator = null; // 当前运算符:+ − × ÷
let expression = ''; // 表达式显示文本
let justEvaluated = false; // 是否刚按过 =
let memory = 0; // 内存值
let hasMemory = false; // 是否有内存值
// ===== DOM =====
const resultEl = document.getElementById('result');
const exprEl = document.getElementById('expression');
const memClearBtn = document.getElementById('memClear');
const memRecallBtn = document.getElementById('memRecall');
const memAddBtn = document.getElementById('memAdd');
const memSubBtn = document.getElementById('memSub');
const memStoreBtn = document.getElementById('memStore');
// ===== 数字格式化 =====
function formatNumber(numStr) {
if (numStr === '' || numStr === '-') return numStr;
// 处理科学计数法
if (/e/i.test(numStr)) return numStr;
// 分离整数和小数部分
const neg = numStr.startsWith('-');
if (neg) numStr = numStr.slice(1);
const parts = numStr.split('.');
let intPart = parts[0] || '0';
const decPart = parts.length > 1 ? parts[1] : null;
// 整数部分加千分位
intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
let out = intPart;
if (decPart !== null) out += '.' + decPart;
return (neg ? '-' : '') + out;
}
// ===== 显示更新 =====
function updateDisplay() {
let displayVal = current;
// 结果太长时用科学计数法或缩小字体
if (displayVal !== '' && !/e/i.test(displayVal)) {
const num = Number(displayVal);
if (isFinite(num)) {
if (Math.abs(num) >= 1e21) {
displayVal = num.toExponential(10).replace(/\.?0+e/, 'e');
} else if (Math.abs(num) < 1e-10 && num !== 0) {
displayVal = num.toExponential(10).replace(/\.?0+e/, 'e');
}
}
}
const formatted = formatNumber(displayVal);
resultEl.textContent = formatted;
exprEl.textContent = expression;
// 字体自适应
resultEl.classList.remove('shrink', 'shrink-more');
if (formatted.length > 12) resultEl.classList.add('shrink-more');
else if (formatted.length > 9) resultEl.classList.add('shrink');
// 内存按钮状态
memClearBtn.disabled = !hasMemory;
memRecallBtn.disabled = !hasMemory;
}
// ===== 计算 =====
function compute(a, op, b) {
const x = parseFloat(a);
const y = parseFloat(b);
if (!isFinite(x) || !isFinite(y)) return '0';
let r;
switch (op) {
case '+': r = x + y; break;
case '−': r = x - y; break;
case '×': r = x * y; break;
case '÷':
if (y === 0) return '除数不能为零';
r = x / y;
break;
default: return '0';
}
if (!isFinite(r)) return '0';
// 处理浮点精度:保留最多 15 位有效数字
let out = parseFloat(r.toPrecision(15));
return String(out);
}
// 运算符显示转换
function opDisplay(op) {
return op;
}
// ===== 输入数字 =====
function inputDigit(d) {
if (current === '除数不能为零') current = '0';
if (justEvaluated) {
// 按下 = 后输入数字,开始新计算
current = d;
expression = '';
previous = null;
operator = null;
justEvaluated = false;
} else {
if (current === '0') {
current = d;
} else {
// 限制输入长度,避免溢出显示
if (current.replace(/[-.]/g, '').length >= 16) return;
current += d;
}
}
updateDisplay();
}
// ===== 输入小数点 =====
function inputDot() {
if (current === '除数不能为零') current = '0';
if (justEvaluated) {
current = '0';
expression = '';
previous = null;
operator = null;
justEvaluated = false;
}
if (!current.includes('.')) {
current += '.';
}
updateDisplay();
}
// ===== 选择运算符 =====
function chooseOperator(op) {
if (current === '除数不能为零') {
current = '0';
}
if (operator && previous !== null && !justEvaluated) {
// 连续运算:先算出中间结果
const r = compute(previous, operator, current);
if (r === '除数不能为零') {
current = r;
expression = '';
previous = null;
operator = null;
justEvaluated = true;
updateDisplay();
return;
}
previous = r;
current = r;
} else {
previous = current;
}
operator = op;
justEvaluated = false;
expression = formatNumber(previous) + ' ' + opDisplay(op);
// 下一步输入数字时替换 current
current = '0';
// 但显示保留 previous 的结果
resultEl.textContent = formatNumber(previous);
exprEl.textContent = expression;
resultEl.classList.remove('shrink', 'shrink-more');
if (formatNumber(previous).length > 12) resultEl.classList.add('shrink-more');
else if (formatNumber(previous).length > 9) resultEl.classList.add('shrink');
updateMemButtons();
// 标记等待新输入:让 current 显示为 previous 但下次输入替换
waitingForOperand = true;
}
let waitingForOperand = false;
// 重写 inputDigit 处理等待状态
const _inputDigit = inputDigit;
inputDigit = function(d) {
if (waitingForOperand) {
current = d;
waitingForOperand = false;
updateDisplay();
return;
}
_inputDigit(d);
};
const _inputDot = inputDot;
inputDot = function() {
if (waitingForOperand) {
current = '0.';
waitingForOperand = false;
updateDisplay();
return;
}
_inputDot();
};
// ===== 等号 =====
function equals() {
if (operator === null || previous === null) {
// 没有运算符,只显示当前值
expression = '';
justEvaluated = true;
updateDisplay();
return;
}
const a = previous;
const b = current;
const r = compute(a, operator, b);
expression = formatNumber(a) + ' ' + opDisplay(operator) + ' ' + formatNumber(b) + ' =';
if (r === '除数不能为零') {
current = r;
expression = '';
} else {
current = r;
}
previous = null;
operator = null;
justEvaluated = true;
waitingForOperand = false;
updateDisplay();
}
// ===== 清除 =====
function clearAll() {
current = '0';
previous = null;
operator = null;
expression = '';
justEvaluated = false;
waitingForOperand = false;
updateDisplay();
}
function clearEntry() {
if (current === '除数不能为零') {
current = '0';
} else {
current = '0';
}
justEvaluated = false;
waitingForOperand = false;
updateDisplay();
}
function backspace() {
if (current === '除数不能为零') { current = '0'; updateDisplay(); return; }
if (justEvaluated) { clearAll(); return; }
if (waitingForOperand) return;
if (current.length > 1) {
current = current.slice(0, -1);
if (current === '-') current = '0';
} else {
current = '0';
}
updateDisplay();
}
// ===== 一元运算 =====
function unaryOp(type) {
if (current === '除数不能为零') current = '0';
const x = parseFloat(current);
if (!isFinite(x)) return;
let r;
let label;
switch (type) {
case 'negate':
if (current === '0') return;
if (current.startsWith('-')) current = current.slice(1);
else current = '-' + current;
updateDisplay();
return;
case 'percent':
r = x / 100;
label = '';
expression = formatNumber(current) + '%';
break;
case 'reciprocal':
if (x === 0) { current = '除数不能为零'; expression = ''; updateDisplay(); return; }
r = 1 / x;
label = '1/(' + formatNumber(current) + ')';
expression = label;
break;
case 'square':
r = x * x;
expression = 'sqr(' + formatNumber(current) + ')';
break;
case 'sqrt':
if (x < 0) { current = '无效输入'; expression = ''; updateDisplay(); return; }
r = Math.sqrt(x);
expression = '√(' + formatNumber(current) + ')';
break;
}
if (r !== undefined) {
current = String(parseFloat(r.toPrecision(15)));
justEvaluated = true;
waitingForOperand = false;
updateDisplay();
}
}
// ===== 内存 =====
function updateMemButtons() {
memClearBtn.disabled = !hasMemory;
memRecallBtn.disabled = !hasMemory;
}
function memAdd() {
if (current === '除数不能为零') return;
memory += parseFloat(current) || 0;
hasMemory = true;
updateMemButtons();
}
function memSub() {
if (current === '除数不能为零') return;
memory -= parseFloat(current) || 0;
hasMemory = true;
updateMemButtons();
}
function memStore() {
if (current === '除数不能为零') return;
memory = parseFloat(current) || 0;
hasMemory = true;
updateMemButtons();
}
function memRecall() {
if (!hasMemory) return;
current = String(parseFloat(memory.toPrecision(15)));
justEvaluated = false;
waitingForOperand = false;
updateDisplay();
}
function memClear() {
memory = 0;
hasMemory = false;
updateMemButtons();
}
// ===== 事件绑定 =====
document.querySelectorAll('.key').forEach(btn => {
btn.addEventListener('click', () => {
if (btn.dataset.num !== undefined) {
inputDigit(btn.dataset.num);
} else if (btn.dataset.op !== undefined) {
chooseOperator(btn.dataset.op);
} else if (btn.dataset.action) {
switch (btn.dataset.action) {
case 'equals': equals(); break;
case 'clear': clearEntry(); break;
case 'clearAll': clearAll(); break;
case 'backspace': backspace(); break;
case 'percent': unaryOp('percent'); break;
case 'negate': unaryOp('negate'); break;
case 'reciprocal': unaryOp('reciprocal'); break;
case 'square': unaryOp('square'); break;
case 'sqrt': unaryOp('sqrt'); break;
}
}
});
});
memClearBtn.addEventListener('click', memClear);
memRecallBtn.addEventListener('click', memRecall);
memAddBtn.addEventListener('click', memAdd);
memSubBtn.addEventListener('click', memSub);
memStoreBtn.addEventListener('click', memStore);
// ===== 键盘支持 =====
document.addEventListener('keydown', (e) => {
const k = e.key;
if (/^[0-9]$/.test(k)) { inputDigit(k); e.preventDefault(); }
else if (k === '.') { inputDot(); e.preventDefault(); }
else if (k === '+') { chooseOperator('+'); e.preventDefault(); }
else if (k === '-') { chooseOperator('−'); e.preventDefault(); }
else if (k === '*') { chooseOperator('×'); e.preventDefault(); }
else if (k === '/') { chooseOperator('÷'); e.preventDefault(); }
else if (k === 'Enter' || k === '=') { equals(); e.preventDefault(); }
else if (k === 'Backspace') { backspace(); e.preventDefault(); }
else if (k === 'Escape') { clearAll(); e.preventDefault(); }
else if (k === 'Delete') { clearEntry(); e.preventDefault(); }
else if (k === '%') { unaryOp('percent'); e.preventDefault(); }
});
// ===== 初始化 =====
updateDisplay();
updateMemButtons();
})();
</script>
</body>
</html>