Files
argon-theme/test-gpu-acceleration.html
nanhaoluo f165fac420 feat: 实现 GPU 加速管理功能
- 实现 enableGPU() 方法设置 will-change 属性
- 实现 disableGPU() 方法移除 will-change 属性
- 实现动画数量限制逻辑(最多 3 个同时运行)
- 实现动画队列自动管理
- 添加 startAnimation() 和 endAnimation() 方法
- 添加 getActiveAnimationCount() 和 getQueuedAnimationCount() 查询方法
- 添加 clearAllAnimations() 清理方法
- 添加错误处理机制
- 创建交互式测试页面和自动化测试
- 创建详细的使用文档

验证需求:
- 需求 5.2: 动画时使用 will-change 提示浏览器创建合成层
- 需求 5.3: 动画完成时移除 will-change 属性释放资源
- 需求 5.5: 限制同时运行的动画数量不超过 3 个
2026-01-21 23:20:06 +08:00

448 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GPU 加速管理测试</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
h1 {
color: #333;
}
.test-section {
margin: 30px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
background: #f9f9f9;
}
.test-box {
width: 100px;
height: 100px;
margin: 10px;
display: inline-block;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
transition: transform 0.3s ease;
}
.test-box:hover {
transform: scale(1.1);
}
.controls {
margin: 20px 0;
}
button {
padding: 10px 20px;
margin: 5px;
font-size: 14px;
cursor: pointer;
border: none;
border-radius: 5px;
background: #667eea;
color: white;
transition: background 0.3s;
}
button:hover {
background: #764ba2;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.status {
padding: 15px;
margin: 10px 0;
background: #e8f4f8;
border-left: 4px solid #2196F3;
border-radius: 3px;
}
.status.success {
background: #e8f5e9;
border-left-color: #4CAF50;
}
.status.error {
background: #ffebee;
border-left-color: #f44336;
}
.log {
background: #263238;
color: #aed581;
padding: 15px;
border-radius: 5px;
font-family: 'Courier New', monospace;
font-size: 13px;
max-height: 300px;
overflow-y: auto;
margin: 10px 0;
}
.log-entry {
margin: 5px 0;
}
.log-entry.info {
color: #81d4fa;
}
.log-entry.success {
color: #aed581;
}
.log-entry.error {
color: #ef5350;
}
.metrics {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin: 20px 0;
}
.metric-card {
padding: 15px;
background: white;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.metric-label {
font-size: 12px;
color: #666;
text-transform: uppercase;
margin-bottom: 5px;
}
.metric-value {
font-size: 24px;
font-weight: bold;
color: #333;
}
</style>
</head>
<body>
<h1>🚀 GPU 加速管理测试</h1>
<div class="test-section">
<h2>测试 1: enableGPU() 和 disableGPU()</h2>
<p>测试 GPU 加速属性的设置和移除</p>
<div id="test1-box" class="test-box"></div>
<div class="controls">
<button onclick="testEnableGPU()">启用 GPU 加速</button>
<button onclick="testDisableGPU()">禁用 GPU 加速</button>
<button onclick="checkWillChange()">检查 will-change 属性</button>
</div>
<div id="test1-status" class="status"></div>
</div>
<div class="test-section">
<h2>测试 2: 动画数量限制</h2>
<p>测试同时运行的动画数量限制(最多 3 个)</p>
<div id="animation-boxes">
<div class="test-box" data-index="1">1</div>
<div class="test-box" data-index="2">2</div>
<div class="test-box" data-index="3">3</div>
<div class="test-box" data-index="4">4</div>
<div class="test-box" data-index="5">5</div>
</div>
<div class="controls">
<button onclick="startAllAnimations()">启动所有动画</button>
<button onclick="stopAllAnimations()">停止所有动画</button>
<button onclick="startSingleAnimation()">启动单个动画</button>
</div>
<div class="metrics">
<div class="metric-card">
<div class="metric-label">活动动画</div>
<div class="metric-value" id="active-count">0</div>
</div>
<div class="metric-card">
<div class="metric-label">等待队列</div>
<div class="metric-value" id="queued-count">0</div>
</div>
<div class="metric-card">
<div class="metric-label">最大限制</div>
<div class="metric-value">3</div>
</div>
</div>
<div id="test2-status" class="status"></div>
</div>
<div class="test-section">
<h2>测试 3: 动画队列管理</h2>
<p>测试动画完成后自动启动队列中的下一个动画</p>
<div class="controls">
<button onclick="testAnimationQueue()">测试动画队列</button>
<button onclick="clearAnimations()">清除所有动画</button>
</div>
<div id="test3-status" class="status"></div>
</div>
<div class="test-section">
<h2>测试日志</h2>
<div id="log" class="log"></div>
<button onclick="clearLog()">清除日志</button>
</div>
<script src="argon-performance.js"></script>
<script>
// 初始化渲染优化器
const renderOptimizer = new ArgonRenderOptimizer();
// 日志函数
function log(message, type = 'info') {
const logDiv = document.getElementById('log');
const entry = document.createElement('div');
entry.className = `log-entry ${type}`;
const timestamp = new Date().toLocaleTimeString();
entry.textContent = `[${timestamp}] ${message}`;
logDiv.appendChild(entry);
logDiv.scrollTop = logDiv.scrollHeight;
console.log(message);
}
function clearLog() {
document.getElementById('log').innerHTML = '';
}
// 更新指标显示
function updateMetrics() {
document.getElementById('active-count').textContent = renderOptimizer.getActiveAnimationCount();
document.getElementById('queued-count').textContent = renderOptimizer.getQueuedAnimationCount();
}
// 测试 1: enableGPU
function testEnableGPU() {
const box = document.getElementById('test1-box');
renderOptimizer.enableGPU(box);
const willChange = window.getComputedStyle(box).willChange;
const status = document.getElementById('test1-status');
if (willChange === 'transform, opacity') {
status.className = 'status success';
status.textContent = '✓ GPU 加速已启用will-change = "transform, opacity"';
log('GPU 加速启用成功', 'success');
} else {
status.className = 'status error';
status.textContent = `✗ GPU 加速启用失败will-change = "${willChange}"`;
log('GPU 加速启用失败', 'error');
}
}
// 测试 1: disableGPU
function testDisableGPU() {
const box = document.getElementById('test1-box');
renderOptimizer.disableGPU(box);
const willChange = window.getComputedStyle(box).willChange;
const status = document.getElementById('test1-status');
if (willChange === 'auto') {
status.className = 'status success';
status.textContent = '✓ GPU 加速已禁用will-change = "auto"';
log('GPU 加速禁用成功', 'success');
} else {
status.className = 'status error';
status.textContent = `✗ GPU 加速禁用失败will-change = "${willChange}"`;
log('GPU 加速禁用失败', 'error');
}
}
// 检查 will-change 属性
function checkWillChange() {
const box = document.getElementById('test1-box');
const willChange = window.getComputedStyle(box).willChange;
const status = document.getElementById('test1-status');
status.className = 'status';
status.textContent = `当前 will-change 属性值: "${willChange}"`;
log(`will-change = "${willChange}"`, 'info');
}
// 测试 2: 启动所有动画
function startAllAnimations() {
const boxes = document.querySelectorAll('#animation-boxes .test-box');
const status = document.getElementById('test2-status');
log('开始启动所有动画...', 'info');
boxes.forEach((box, index) => {
const started = renderOptimizer.startAnimation(box, (element) => {
// 模拟动画
element.style.transform = 'rotate(360deg) scale(1.2)';
element.style.transition = 'transform 2s ease';
// 2秒后结束动画
setTimeout(() => {
element.style.transform = '';
renderOptimizer.endAnimation(element);
updateMetrics();
log(`动画 ${index + 1} 完成`, 'success');
}, 2000);
});
if (started) {
log(`动画 ${index + 1} 立即启动`, 'success');
} else {
log(`动画 ${index + 1} 加入等待队列`, 'info');
}
});
updateMetrics();
const activeCount = renderOptimizer.getActiveAnimationCount();
const queuedCount = renderOptimizer.getQueuedAnimationCount();
status.className = 'status';
status.textContent = `已启动 ${activeCount} 个动画,${queuedCount} 个在等待队列中`;
// 验证限制
if (activeCount <= 3) {
log(`✓ 动画数量限制正常:活动动画 ${activeCount} <= 3`, 'success');
} else {
log(`✗ 动画数量限制失败:活动动画 ${activeCount} > 3`, 'error');
}
}
// 测试 2: 停止所有动画
function stopAllAnimations() {
const boxes = document.querySelectorAll('#animation-boxes .test-box');
boxes.forEach(box => {
box.style.transform = '';
box.style.transition = '';
});
renderOptimizer.clearAllAnimations();
updateMetrics();
const status = document.getElementById('test2-status');
status.className = 'status success';
status.textContent = '✓ 所有动画已停止';
log('所有动画已清除', 'success');
}
// 测试 2: 启动单个动画
let singleAnimIndex = 0;
function startSingleAnimation() {
const boxes = document.querySelectorAll('#animation-boxes .test-box');
const box = boxes[singleAnimIndex % boxes.length];
singleAnimIndex++;
const started = renderOptimizer.startAnimation(box, (element) => {
element.style.transform = 'translateY(-50px)';
element.style.transition = 'transform 1s ease';
setTimeout(() => {
element.style.transform = '';
renderOptimizer.endAnimation(element);
updateMetrics();
log(`单个动画完成`, 'success');
}, 1000);
});
updateMetrics();
if (started) {
log(`单个动画立即启动`, 'success');
} else {
log(`单个动画加入等待队列`, 'info');
}
}
// 测试 3: 动画队列管理
function testAnimationQueue() {
const status = document.getElementById('test3-status');
status.className = 'status';
status.textContent = '测试进行中...';
log('开始测试动画队列管理...', 'info');
// 创建 5 个测试元素
const testElements = [];
for (let i = 0; i < 5; i++) {
const div = document.createElement('div');
div.className = 'test-box';
div.textContent = `Q${i + 1}`;
div.style.display = 'inline-block';
testElements.push(div);
}
// 启动 5 个动画
let completedCount = 0;
testElements.forEach((element, index) => {
renderOptimizer.startAnimation(element, (el) => {
log(`队列动画 ${index + 1} 开始执行`, 'info');
setTimeout(() => {
renderOptimizer.endAnimation(el);
completedCount++;
updateMetrics();
log(`队列动画 ${index + 1} 完成 (${completedCount}/5)`, 'success');
if (completedCount === 5) {
status.className = 'status success';
status.textContent = '✓ 动画队列测试完成:所有 5 个动画按顺序执行完毕';
log('✓ 动画队列管理测试通过', 'success');
}
}, 500);
});
});
updateMetrics();
// 验证初始状态
const activeCount = renderOptimizer.getActiveAnimationCount();
const queuedCount = renderOptimizer.getQueuedAnimationCount();
if (activeCount === 3 && queuedCount === 2) {
log(`✓ 初始状态正确3 个活动动画2 个等待`, 'success');
} else {
log(`✗ 初始状态错误:${activeCount} 个活动,${queuedCount} 个等待`, 'error');
}
}
// 清除所有动画
function clearAnimations() {
renderOptimizer.clearAllAnimations();
updateMetrics();
const status = document.getElementById('test3-status');
status.className = 'status success';
status.textContent = '✓ 所有动画已清除';
log('动画队列已清空', 'success');
}
// 初始化
log('GPU 加速管理测试页面已加载', 'success');
log('ArgonRenderOptimizer 已初始化', 'success');
updateMetrics();
</script>
</body>
</html>