2025-09-09 07:13:16 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<title>双箭头填充动画</title>
|
2025-09-09 07:13:16 +08:00
|
|
|
|
<style>
|
|
|
|
|
body {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
height: 100vh;
|
|
|
|
|
margin: 0;
|
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
|
}
|
|
|
|
|
.container {
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
button {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
padding: 10px 20px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
background-color: #4CAF50;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
button:hover {
|
|
|
|
|
background-color: #45a049;
|
|
|
|
|
}
|
|
|
|
|
button:disabled {
|
|
|
|
|
background-color: #cccccc;
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="container">
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<h1>双箭头填充动画演示</h1>
|
|
|
|
|
<!-- 扩展SVG尺寸以容纳两个相对的箭头 -->
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="500px" height="61px" viewBox="-0.5 -0.5 500 61">
|
2025-09-09 07:13:16 +08:00
|
|
|
|
<!-- 定义裁剪路径,用于限制填充区域为箭头形状 -->
|
|
|
|
|
<defs>
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<!-- 从左到右箭头的裁剪路径 -->
|
|
|
|
|
<clipPath id="arrowClipPathLeft">
|
2025-09-09 07:13:16 +08:00
|
|
|
|
<path d="M 0 8.1 L 174 18 L 164 0 L 240 30 L 164 60 L 174 42 L 0 51.9 L 0 30 Z" />
|
|
|
|
|
</clipPath>
|
2025-09-09 07:17:39 +08:00
|
|
|
|
|
|
|
|
|
<!-- 从右到左箭头的裁剪路径 -->
|
|
|
|
|
<clipPath id="arrowClipPathRight">
|
|
|
|
|
<path d="M 240 8.1 L 66 18 L 76 0 L 0 30 L 76 60 L 66 42 L 240 51.9 L 240 30 Z" />
|
|
|
|
|
</clipPath>
|
2025-09-09 07:13:16 +08:00
|
|
|
|
</defs>
|
|
|
|
|
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<!-- 左侧箭头:从左到右 -->
|
2025-09-09 07:13:16 +08:00
|
|
|
|
<!-- 背景箭头轮廓 - 保持不变 -->
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<path id="outlineArrowLeft"
|
2025-09-09 07:13:16 +08:00
|
|
|
|
d="M 0 8.1 L 174 18 L 164 0 L 240 30 L 164 60 L 174 42 L 0 51.9 L 0 30 Z"
|
|
|
|
|
fill="white"
|
|
|
|
|
stroke="black"
|
|
|
|
|
stroke-width="2"/>
|
|
|
|
|
|
|
|
|
|
<!-- 填充层 - 使用裁剪路径限制填充范围 -->
|
2025-09-09 07:17:39 +08:00
|
|
|
|
<rect id="fillAnimationLeft"
|
2025-09-09 07:13:16 +08:00
|
|
|
|
x="0" y="0" width="0" height="61"
|
|
|
|
|
fill="red"
|
2025-09-09 07:17:39 +08:00
|
|
|
|
clip-path="url(#arrowClipPathLeft)"/>
|
|
|
|
|
|
|
|
|
|
<!-- 右侧箭头:从右到左 (通过平移和水平翻转实现) -->
|
|
|
|
|
<!-- 背景箭头轮廓 - 保持不变 -->
|
|
|
|
|
<g transform="translate(500, 0) scale(-1, 1)">
|
|
|
|
|
<path id="outlineArrowRight"
|
|
|
|
|
d="M 0 8.1 L 174 18 L 164 0 L 240 30 L 164 60 L 174 42 L 0 51.9 L 0 30 Z"
|
|
|
|
|
fill="white"
|
|
|
|
|
stroke="black"
|
|
|
|
|
stroke-width="2"/>
|
|
|
|
|
|
|
|
|
|
<!-- 填充层 - 使用裁剪路径限制填充范围 -->
|
|
|
|
|
<rect id="fillAnimationRight"
|
|
|
|
|
x="0" y="0" width="0" height="61"
|
|
|
|
|
fill="red"
|
|
|
|
|
clip-path="url(#arrowClipPathLeft)"/>
|
|
|
|
|
</g>
|
2025-09-09 07:13:16 +08:00
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
|
|
<button id="startButton">开始填充</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
// 获取DOM元素
|
2025-09-09 07:17:39 +08:00
|
|
|
|
const fillAnimationLeft = document.getElementById('fillAnimationLeft');
|
|
|
|
|
const fillAnimationRight = document.getElementById('fillAnimationRight');
|
2025-09-09 07:13:16 +08:00
|
|
|
|
const startButton = document.getElementById('startButton');
|
|
|
|
|
let animationId = null;
|
|
|
|
|
let isAnimating = false;
|
|
|
|
|
|
|
|
|
|
// 开始填充动画
|
|
|
|
|
function startFillAnimation() {
|
|
|
|
|
if (isAnimating) return;
|
|
|
|
|
|
|
|
|
|
isAnimating = true;
|
|
|
|
|
startButton.disabled = true;
|
|
|
|
|
startButton.textContent = "填充中...";
|
|
|
|
|
|
|
|
|
|
const duration = 2000; // 动画持续时间(毫秒)
|
|
|
|
|
const startTime = performance.now();
|
|
|
|
|
const startWidth = 0;
|
|
|
|
|
const endWidth = 241; // 箭头的总宽度
|
|
|
|
|
|
|
|
|
|
function animate(currentTime) {
|
|
|
|
|
const elapsedTime = currentTime - startTime;
|
|
|
|
|
const progress = Math.min(elapsedTime / duration, 1);
|
|
|
|
|
|
|
|
|
|
// 计算当前的填充宽度,从0逐渐变为241
|
|
|
|
|
const currentWidth = startWidth + (endWidth - startWidth) * progress;
|
2025-09-09 07:17:39 +08:00
|
|
|
|
|
|
|
|
|
// 同时更新两个箭头的填充宽度
|
|
|
|
|
fillAnimationLeft.setAttribute('width', currentWidth);
|
|
|
|
|
fillAnimationRight.setAttribute('width', currentWidth);
|
2025-09-09 07:13:16 +08:00
|
|
|
|
|
|
|
|
|
if (progress < 1) {
|
|
|
|
|
animationId = requestAnimationFrame(animate);
|
|
|
|
|
} else {
|
|
|
|
|
// 动画完成
|
|
|
|
|
isAnimating = false;
|
|
|
|
|
startButton.disabled = false;
|
|
|
|
|
startButton.textContent = "重新填充";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animationId = requestAnimationFrame(animate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绑定按钮点击事件
|
|
|
|
|
startButton.addEventListener('click', startFillAnimation);
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|