<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算器8.2动画测试版</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-bg: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
--calculator-bg: rgba(255, 255, 255, 0.15);
--display-bg: rgba(0, 0, 0, 0.3);
--btn-bg: rgba(255, 255, 255, 0.1);
--btn-hover: rgba(255, 255, 255, 0.25);
--btn-active: rgba(255, 255, 255, 0.4);
--operator-bg: rgba(255, 215, 0, 0.3);
--operator-hover: rgba(255, 215, 0, 0.4);
--equals-bg: rgba(255, 87, 34, 0.4);
--equals-hover: rgba(255, 87, 34, 0.6);
--text-color: white;
--shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--border-radius: 20px;
--transition: all 0.3s ease;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: var(--primary-bg);
padding: 20px;
transition: background 1s ease;
}
.calculator-container {
width: 100%;
max-width: 400px;
padding: 25px;
background: var(--calculator-bg);
backdrop-filter: blur(10px);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
border: 1px solid rgba(255, 255, 255, 0.2);
transform: translateY(0);
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.theme-selector {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 25px;
}
.theme-btn {
width: 35px;
height: 35px;
border-radius: 50%;
border: 2px solid white;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
.theme-btn:hover {
transform: scale(1.1);
}
.theme-1 { background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); }
.theme-2 { background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%); }
.theme-3 { background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%); }
.theme-4 { background: linear-gradient(135deg, #654ea3 0%, #da98b4 100%); }
.theme-5 { background: linear-gradient(135deg, #141e30 0%, #243b55 100%); }
.display {
background: var(--display-bg);
border-radius: 15px;
padding: 20px;
margin-bottom: 25px;
text-align: right;
position: relative;
overflow: hidden;
min-height: 120px;
box-shadow: inset 0 4px 10px rgba(0, 0, 0, 0.2);
}
.display::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #ff8a00, #e52e71, #00b3ff);
animation: gradientBG 3s ease infinite;
background-size: 300% 300%;
}
@keyframes gradientBG {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.previous-operand {
color: rgba(255, 255, 255, 0.7);
font-size: 1.2rem;
min-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
}
.current-operand {
color: var(--text-color);
font-size: 2.5rem;
font-weight: 600;
margin-top: 10px;
min-height: 42px;
overflow: hidden;
text-overflow: ellipsis;
transition: transform 0.2s;
}
.buttons-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
.btn {
border: none;
border-radius: 15px;
padding: 18px 0;
font-size: 1.3rem;
font-weight: 600;
color: var(--text-color);
background: var(--btn-bg);
cursor: pointer;
transition: var(--transition);
position: relative;
overflow: hidden;
backdrop-filter: blur(5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.1);
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.btn:hover {
background: var(--btn-hover);
transform: translateY(-3px);
box-shadow: 0 7px 20px rgba(0, 0, 0, 0.2);
}
.btn:hover::before {
transform: translateX(100%);
}
.btn:active {
transform: translateY(1px);
background: var(--btn-active);
}
.btn.operator {
background: var(--operator-bg);
}
.btn.operator:hover {
background: var(--operator-hover);
}
.btn.span-two {
grid-column: span 2;
}
.btn.equals {
background: var(--equals-bg);
}
.btn.equals:hover {
background: var(--equals-hover);
}
.btn.clear {
background: rgba(255, 99, 132, 0.3);
}
.btn.clear:hover {
background: rgba(255, 99, 132, 0.5);
}
.btn.delete {
background: rgba(54, 162, 235, 0.3);
}
.btn.delete:hover {
background: rgba(54, 162, 235, 0.5);
}
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none;
}
@keyframes ripple {
to {
transform: scale(2.5);
opacity: 0;
}
}
.animation-text {
animation: textScale 0.3s ease;
}
@keyframes textScale {
0% { transform: scale(1.2); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
.calculator-title {
text-align: center;
color: white;
font-size: 1.8rem;
margin-bottom: 20px;
font-weight: 600;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.calculator-subtitle {
text-align: center;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 25px;
font-size: 1rem;
}
@media (max-width: 480px) {
.calculator-container {
padding: 20px 15px;
}
.btn {
padding: 16px 0;
font-size: 1.2rem;
}
.current-operand {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="calculator-container">
<h1 class="calculator-title">计算器8.2动画测试版</h1>
<p class="calculator-subtitle"></p>
<div class="theme-selector">
<div class="theme-btn theme-1" data-theme="1"></div>
<div class="theme-btn theme-2" data-theme="2"></div>
<div class="theme-btn theme-3" data-theme="3"></div>
<div class="theme-btn theme-4" data-theme="4"></div>
<div class="theme-btn theme-5" data-theme="5"></div>
</div>
<div class="display">
<div class="previous-operand" id="previous-operand"></div>
<div class="current-operand" id="current-operand">0</div>
</div>
<div class="buttons-grid">
<button class="btn clear span-two" data-action="clear">AC</button>
<button class="btn delete" data-action="delete">DEL</button>
<button class="btn operator" data-operation="÷">÷</button>
<button class="btn" data-number="7">7</button>
<button class="btn" data-number="8">8</button>
<button class="btn" data-number="9">9</button>
<button class="btn operator" data-operation="*">×</button>
<button class="btn" data-number="4">4</button>
<button class="btn" data-number="5">5</button>
<button class="btn" data-number="6">6</button>
<button class="btn operator" data-operation="-">−</button>
<button class="btn" data-number="1">1</button>
<button class="btn" data-number="2">2</button>
<button class="btn" data-number="3">3</button>
<button class="btn operator" data-operation="+">+</button>
<button class="btn" data-number="0">0</button>
<button class="btn" data-number=".">.</button>
<button class="btn equals" data-action="calculate">=</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// 计算器状态
let currentOperand = '0';
let previousOperand = '';
let operation = undefined;
let resetScreen = false;
// DOM 元素
const currentOperandElement = document.getElementById('current-operand');
const previousOperandElement = document.getElementById('previous-operand');
const buttons = document.querySelectorAll('.btn');
// 更新显示
function updateDisplay() {
currentOperandElement.textContent = currentOperand;
if (operation != null) {
previousOperandElement.textContent =
`${previousOperand} ${getOperationSymbol(operation)}`;
} else {
previousOperandElement.textContent = previousOperand;
}
}
// 获取操作符的显示符号
function getOperationSymbol(op) {
switch(op) {
case '+': return '+';
case '-': return '−';
case '*': return '×';
case '÷': return '÷';
default: return op;
}
}
// 添加数字
function appendNumber(number) {
if (currentOperand === '0' || resetScreen) {
currentOperand = number;
resetScreen = false;
} else {
// 防止输入多个小数点
if (number === '.' && currentOperand.includes('.')) return;
currentOperand += number;
}
animateText(currentOperandElement);
}
// 选择操作
function chooseOperation(op) {
if (currentOperand === '') return;
if (previousOperand !== '') {
calculate();
}
operation = op;
previousOperand = currentOperand;
resetScreen = true;
animateText(previousOperandElement);
}
// 计算
function calculate() {
let computation;
const prev = parseFloat(previousOperand);
const current = parseFloat(currentOperand);
if (isNaN(prev) || isNaN(current)) return;
switch (operation) {
case '+':
computation = prev + current;
break;
case '-':
computation = prev - current;
break;
case '*':
computation = prev * current;
break;
case '÷':
if (current === 0) {
computation = "错误";
} else {
computation = prev / current;
}
break;
default:
return;
}
currentOperand = computation.toString();
operation = undefined;
previousOperand = '';
resetScreen = true;
animateResult(currentOperandElement);
}
// 清除
function clear() {
currentOperand = '0';
previousOperand = '';
operation = undefined;
}
function deleteNumber() {
currentOperand = currentOperand.toString().slice(0, -1);
if (currentOperand === '') {
currentOperand = '0';
}
animateText(currentOperandElement);
}
function animateText(element) {
element.classList.remove('animation-text');
void element.offsetWidth;
element.classList.add('animation-text');
}
function animateResult(element) {
element.style.transform = 'scale(1.2)';
setTimeout(() => {
element.style.transform = 'scale(1)';
}, 300);
}
function createRipple(event) {
const button = event.currentTarget;
const circle = document.createElement('span');
const diameter = Math.max(button.clientWidth, button.clientHeight);
const radius = diameter / 2;
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - button.getBoundingClientRect().left - radius}px`;
circle.style.top = `${event.clientY - button.getBoundingClientRect().top - radius}px`;
circle.classList.add('ripple');
const ripple = button.getElementsByClassName('ripple')[0];
if (ripple) {
ripple.remove();
}
button.appendChild(circle);
}
document.querySelectorAll('.theme-btn').forEach(btn => {
btn.addEventListener('click', () => {
const theme = btn.getAttribute('data-theme');
changeTheme(theme);
});
});
function changeTheme(theme) {
document.documentElement.style.setProperty('--primary-bg', getThemeGradient(theme));
document.documentElement.style.setProperty('--operator-bg', getThemeOperator(theme));
document.documentElement.style.setProperty('--equals-bg', getThemeEquals(theme));
}
function getThemeGradient(theme) {
switch(theme) {
case '1': return 'linear-gradient(135deg, #6a11cb 0%, #2575fc 100%)';
case '2': return 'linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%)';
case '3': return 'linear-gradient(135deg, #00b09b 0%, #96c93d 100%)';
case '4': return 'linear-gradient(135deg, #654ea3 0%, #da98b4 100%)';
case '5': return 'linear-gradient(135deg, #141e30 0%, #243b55 100%)';
default: return 'linear-gradient(135deg, #6a11cb 0%, #2575fc 100%)';
}
}
function getThemeOperator(theme) {
switch(theme) {
case '1': return 'rgba(255, 215, 0, 0.3)';
case '2': return 'rgba(255, 193, 7, 0.3)';
case '3': return 'rgba(76, 175, 80, 0.3)';
case '4': return 'rgba(156, 39, 176, 0.3)';
case '5': return 'rgba(33, 150, 243, 0.3)';
default: return 'rgba(255, 215, 0, 0.3)';
}
}
function getThemeEquals(theme) {
switch(theme) {
case '1': return 'rgba(255, 87, 34, 0.4)';
case '2': return 'rgba(244, 67, 54, 0.4)';
case '3': return 'rgba(139, 195, 74, 0.4)';
case '4': return 'rgba(233, 30, 99, 0.4)';
case '5': return 'rgba(63, 81, 181, 0.4)';
default: return 'rgba(255, 87, 34, 0.4)';
}
}
// 按钮事件
buttons.forEach(button => {
button.addEventListener('click', () => {
createRipple(event);
if (button.hasAttribute('data-number')) {
appendNumber(button.getAttribute('data-number'));
} else if (button.hasAttribute('data-operation')) {
chooseOperation(button.getAttribute('data-operation'));
} else if (button.getAttribute('data-action') === 'calculate') {
calculate();
} else if (button.getAttribute('data-action') === 'clear') {
clear();
} else if (button.getAttribute('data-action') === 'delete') {
deleteNumber();
}
updateDisplay();
});
});
document.addEventListener('keydown', event => {
if (event.key >= 0 && event.key <= 9) appendNumber(event.key);
if (event.key === '.') appendNumber('.');
if (event.key === '=' || event.key === 'Enter') calculate();
if (event.key === 'Backspace') deleteNumber();
if (event.key === 'Escape') clear();
if (event.key === '+' || event.key === '-' || event.key === '*' || event.key === '/') {
chooseOperation(event.key === '/' ? '÷' : event.key);
}
updateDisplay();
});
updateDisplay();
});
</script>
</body>
</html>
index.html