AI 生成: 一个简洁美观的网页计算器,支持加、减、乘、除和清除功能,使用纯 HTML/CSS/JavaScript 实现。
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
# Simple Calculator Web
|
||||||
|
|
||||||
|
一个简洁美观的网页计算器,支持加、减、乘、除和清除功能。
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
- 数字 0-9 输入
|
||||||
|
- 小数点输入
|
||||||
|
- 加法(+)、减法(-)、乘法(×)、除法(÷)
|
||||||
|
- 等号(=)计算结果
|
||||||
|
- 清除(C)重置计算器
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
simple-calculator-web/
|
||||||
|
├── index.html # 主页面
|
||||||
|
├── style.css # 样式文件
|
||||||
|
├── script.js # 计算逻辑
|
||||||
|
└── README.md # 说明文档
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
1. 下载或克隆本项目到本地。
|
||||||
|
2. 直接用浏览器打开 `index.html` 即可使用。
|
||||||
|
3. 无需安装任何依赖。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- HTML5
|
||||||
|
- CSS3(Flexbox + Grid 布局)
|
||||||
|
- 原生 JavaScript(ES6)
|
||||||
|
|
||||||
|
## 预览
|
||||||
|
|
||||||
|
界面采用深色主题,按钮带有悬停和点击反馈效果,操作直观。
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>简易计算器</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="calculator">
|
||||||
|
<!-- 显示区域 -->
|
||||||
|
<div class="display" id="display">0</div>
|
||||||
|
|
||||||
|
<!-- 按键区域 -->
|
||||||
|
<div class="keys">
|
||||||
|
<button class="key key-clear" data-action="clear">C</button>
|
||||||
|
<button class="key key-op" data-action="operator" data-op="÷">÷</button>
|
||||||
|
<button class="key key-op" data-action="operator" data-op="×">×</button>
|
||||||
|
<button class="key key-op" data-action="operator" data-op="-">−</button>
|
||||||
|
|
||||||
|
<button class="key" data-action="number" data-value="7">7</button>
|
||||||
|
<button class="key" data-action="number" data-value="8">8</button>
|
||||||
|
<button class="key" data-action="number" data-value="9">9</button>
|
||||||
|
<button class="key key-op" data-action="operator" data-op="+">+</button>
|
||||||
|
|
||||||
|
<button class="key" data-action="number" data-value="4">4</button>
|
||||||
|
<button class="key" data-action="number" data-value="5">5</button>
|
||||||
|
<button class="key" data-action="number" data-value="6">6</button>
|
||||||
|
<button class="key key-equals" data-action="equals" rowspan="2">=</button>
|
||||||
|
|
||||||
|
<button class="key" data-action="number" data-value="1">1</button>
|
||||||
|
<button class="key" data-action="number" data-value="2">2</button>
|
||||||
|
<button class="key" data-action="number" data-value="3">3</button>
|
||||||
|
|
||||||
|
<button class="key key-zero" data-action="number" data-value="0">0</button>
|
||||||
|
<button class="key" data-action="decimal">.</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
// ===== 计算器状态 =====
|
||||||
|
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();
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/* ===== 全局重置 ===== */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(135deg, #1e1e2f 0%, #2d2d44 100%);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 计算器容器 ===== */
|
||||||
|
.calculator {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
background: #2a2a3d;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 显示区域 ===== */
|
||||||
|
.display {
|
||||||
|
background: #1b1b2a;
|
||||||
|
color: #f5f5f5;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
font-weight: 300;
|
||||||
|
text-align: right;
|
||||||
|
padding: 20px 18px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
min-height: 80px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 按键网格 ===== */
|
||||||
|
.keys {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 按键基础样式 ===== */
|
||||||
|
.key {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #eaeaea;
|
||||||
|
background: #3a3a52;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 18px 0;
|
||||||
|
transition: transform 0.08s ease, background 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
box-shadow: 0 4px 0 #26263a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key:hover {
|
||||||
|
background: #45456a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key:active {
|
||||||
|
transform: translateY(2px);
|
||||||
|
box-shadow: 0 2px 0 #26263a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 运算符按钮 ===== */
|
||||||
|
.key-op {
|
||||||
|
background: #4a4a78;
|
||||||
|
color: #ffd166;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 4px 0 #2e2e4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-op:hover {
|
||||||
|
background: #5a5a92;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 清除按钮 ===== */
|
||||||
|
.key-clear {
|
||||||
|
background: #e63946;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0 4px 0 #a8232e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-clear:hover {
|
||||||
|
background: #ff4d5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 等号按钮(跨两行) ===== */
|
||||||
|
.key-equals {
|
||||||
|
grid-row: span 2;
|
||||||
|
background: linear-gradient(180deg, #06d6a0, #04b184);
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
box-shadow: 0 4px 0 #028a66;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key-equals:hover {
|
||||||
|
background: linear-gradient(180deg, #0be0aa, #05c492);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 0 按钮跨两列 ===== */
|
||||||
|
.key-zero {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 响应式 ===== */
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.display {
|
||||||
|
font-size: 1.9rem;
|
||||||
|
padding: 16px 14px;
|
||||||
|
}
|
||||||
|
.key {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 15px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user