如何在SVG中同步重启多动画并保留起始时间(React嵌入场景)
Alright, let's break down how to fix your SVG animation sync issue and get this embedded into a React component smoothly.
Your original setup uses fixed start times (0s, 3s, 6s) which makes it hard to restart all animations in sync. The solution is to tie all animations to a shared trigger event that repeats every 9 seconds (the total duration of your full sequence). Here's how to adjust your SVG:
First, we'll add a hidden "trigger" animation that runs on a 9-second loop. Then, each line's animation will start relative to this trigger's start time instead of fixed timestamps.
Here's the revised SVG code:
<svg viewBox="0 0 74 2" height="2" width="74"> <!-- Static background lines --> <line x1="0" y1="0" x2="20" y2="0" style="stroke:black;stroke-width:3" /> <line x1="27" y1="0" x2="47" y2="0" style="stroke:black;stroke-width:3" /> <line x1="54" y1="0" x2="74" y2="0" style="stroke:black;stroke-width:3" /> <!-- Animated red fill lines --> <line x1="0" y1="0" x2="0" y2="0" style="stroke:red;stroke-width:4"> <animate id="first" dur="3s" attributeName="x2" from="0" to="20" begin="restartTrigger.begin+0s" fill="freeze" /> </line> <line x1="27" y1="0" x2="27" y2="0" style="stroke:red;stroke-width:4"> <animate id="second" dur="3s" attributeName="x2" from="27" to="47" begin="restartTrigger.begin+3s" fill="freeze" /> </line> <line x1="54" y1="0" x2="54" y2="0" style="stroke:red;stroke-width:4"> <animate id="third" dur="3s" attributeName="x2" from="54" to="74" begin="restartTrigger.begin+6s" fill="freeze" /> </line> <!-- Hidden loop trigger to sync restarts every 9s --> <animate id="restartTrigger" attributeName="visibility" from="visible" to="visible" dur="9s" repeatCount="indefinite" /> </svg>
How this works:
- The
restartTriggeris a hidden animation that runs on a 9-second loop (matching your total sequence length). - Each line's animation uses
restartTrigger.begin+[delay]as its start time. This means every time the trigger restarts, the first line animates immediately, the second starts 3 seconds later, and the third starts 6 seconds later—keeping your original timing. - After each 9-second cycle, the trigger restarts, and all animations reset and run through their sequence again in sync.
There are two straightforward ways to do this, depending on whether you need programmatic control over the animation.
Option 1: Inline SVG Component
Just drop the revised SVG into a React component, adjusting the style attributes to fit React's JSX syntax (using object-style style props instead of inline strings):
import React from 'react'; const StaggeredLoadingLines = () => { return ( <svg viewBox="0 0 74 2" height="2" width="74"> {/* Static background lines */} <line x1="0" y1="0" x2="20" y2="0" style={{ stroke: 'black', strokeWidth: 3 }} /> <line x1="27" y1="0" x2="47" y2="0" style={{ stroke: 'black', strokeWidth: 3 }} /> <line x1="54" y1="0" x2="74" y2="0" style={{ stroke: 'black', strokeWidth: 3 }} /> {/* Animated red lines */} <line x1="0" y1="0" x2="0" y2="0" style={{ stroke: 'red', strokeWidth: 4 }} > <animate id="first" dur="3s" attributeName="x2" from="0" to="20" begin="restartTrigger.begin+0s" fill="freeze" /> </line> <line x1="27" y1="0" x2="27" y2="0" style={{ stroke: 'red', strokeWidth: 4 }} > <animate id="second" dur="3s" attributeName="x2" from="27" to="47" begin="restartTrigger.begin+3s" fill="freeze" /> </line> <line x1="54" y1="0" x2="54" y2="0" style={{ stroke: 'red', strokeWidth: 4 }} > <animate id="third" dur="3s" attributeName="x2" from="54" to="74" begin="restartTrigger.begin+6s" fill="freeze" /> </line> {/* Restart trigger */} <animate id="restartTrigger" attributeName="visibility" from="visible" to="visible" dur="9s" repeatCount="indefinite" /> </svg> ); }; export default StaggeredLoadingLines;
Option 2: Programmatic Restart Control (e.g., Button Click)
If you want to manually trigger a restart (like with a button), use React's useRef to access the trigger animation and call beginElement() on it:
import React, { useRef } from 'react'; const StaggeredLoadingLines = () => { const restartTriggerRef = useRef(null); const handleManualRestart = () => { // Trigger the animation sequence to restart immediately restartTriggerRef.current?.beginElement(); }; return ( <div> <svg viewBox="0 0 74 2" height="2" width="74"> {/* Same lines and animations as above */} <animate ref={restartTriggerRef} id="restartTrigger" attributeName="visibility" from="visible" to="visible" dur="9s" repeatCount="indefinite" /> </svg> <button onClick={handleManualRestart}>Restart Loading Animation</button> </div> ); }; export default StaggeredLoadingLines;
This lets you restart the entire sequence on demand, while still keeping the staggered start times for each line.
内容的提问来源于stack exchange,提问作者Max

