React中使用styled-components实现跳跃文字效果失效,求问题排查
问题:React中实现跳跃文字动画无效果
我想实现跳跃文字动画效果,用React+styled-components创建组件后,测试时没有出现预期效果。以下是我的代码:
App.tsx
import styled from "styled-components"; const Jumper = styled.p` @keyframes trampoline { 0% { transform: translateY(100%); animation-timing-function: ease-out; } 50% { transform: translateY(0); animation-timing-function: ease-in; } } @media (prefers-reduced-motion: no-preference) { [word-animation] { display: inline-flex; flex-wrap: wrap; gap: 1ch; } [word-animation="trampoline"] > span { display: inline-block; transform: translateY(100%); animation: trampoline 3s ease calc(var(--index) * 150 * 1ms) infinite alternate; } } `; export default function App() { const span = (text, index) => { const node = document.createElement("span"); node.textContent = text; node.style.setProperty("--index", index); return node; }; const byWord = (text) => text.split(" ").map(span); const { matches: motionOK } = window.matchMedia( "(prefers-reduced-motion: no-preference)" ); if (motionOK) { const splitTargets = document.querySelectorAll("[split-by]"); splitTargets.forEach((node) => { let nodes = byWord(node.innerText); if (nodes) node.firstChild.replaceWith(...nodes); }); } return <Jumper>split a paragraph of content 🤘💀</Jumper>; }
错误原因及修复方案
1. CSS选择器语法错误
代码中的>是HTML转义字符,CSS无法识别,需替换为原生的>符号:
/* 错误写法 */ [word-animation="trampoline"] > span { ... } /* 正确写法 */ [word-animation="trampoline"] > span { ... }
2. 缺少必要的DOM属性匹配
- CSS样式针对带有
word-animation="trampoline"属性的元素下的span,但<Jumper>组件未添加该属性,需补上; - DOM操作的目标是带有
split-by属性的元素,必须给<Jumper>添加该属性,否则querySelectorAll("[split-by]")找不到目标元素:
return <Jumper word-animation="trampoline" split-by>split a paragraph of content 🤘💀</Jumper>;
3. DOM操作时机错误
在组件函数体直接执行document.querySelectorAll时,组件还未挂载到DOM树,无法找到元素。需用useEffect钩子在组件挂载后执行DOM操作:
import { useEffect } from "react"; export default function App() { const span = (text, index) => { const node = document.createElement("span"); node.textContent = text; node.style.setProperty("--index", index); return node; }; const byWord = (text) => text.split(" ").map(span); useEffect(() => { const { matches: motionOK } = window.matchMedia( "(prefers-reduced-motion: no-preference)" ); if (motionOK) { const splitTargets = document.querySelectorAll("[split-by]"); splitTargets.forEach((node) => { // 清空原有内容后插入分割后的span node.innerHTML = ""; const nodes = byWord(node.innerText); nodes.forEach(spanNode => node.appendChild(spanNode)); }); } }, []); return <Jumper word-animation="trampoline" split-by>split a paragraph of content 🤘💀</Jumper>; }
4. Styled-components选择器作用域问题
Styled-components会给组件添加唯一类名,全局属性选择器[word-animation="trampoline"]可能匹配失效。可以调整CSS写法,直接针对组件内部的span,更符合组件封装特性:
const Jumper = styled.p` @keyframes trampoline { 0% { transform: translateY(100%); animation-timing-function: ease-out; } 50% { transform: translateY(0); animation-timing-function: ease-in; } } @media (prefers-reduced-motion: no-preference) { display: inline-flex; flex-wrap: wrap; gap: 1ch; > span { display: inline-block; transform: translateY(100%); animation: trampoline 3s ease calc(var(--index) * 150 * 1ms) infinite alternate; } } `;
内容的提问来源于stack exchange,提问作者user14992713
相关产品推荐
相关产品推荐

