首页 > 解决方案 > 将文本包装在一个

标签,当每个字母在 react.js 中都是单独的(用于动画目的)时

问题描述

我的任务是在我正在构建的投资组合网站上创建一个介绍性文本,gatsby.js每个字母都有一个单独的动画 - 所以当你将鼠标悬停在一个字母上时,它会反弹并放大,然后离开光标反弹并缩小。

我编写了一个组件,它接收文本,将字符串拆分为一个数组,将每个字母映射到另一个组件中,并使用足够的事件侦听器和类名将每个字符包装在标签中。

这是它的外观:

IntroText.js

export default function IntroText({children}) {
    return (
    <div>
        <p className='intro-text'>
            {children.split('').map((e, i) => <IntroLetter key={i} char={e}/>)}
        </p>
    </div>
  )
}

IntroLetter.js

export default function IntroLetter({char}) {
  const [ hoverClass, setHoverClass ] = useState('single-letter')

  if (char === ' ') {
    return <span> </span>
  } else {
    return (
      <span
        className={hoverClass}
        onMouseOver={() => setHoverClass('single-letter hovered')}
        onMouseLeave={() => setHoverClass('single-letter unhovered')}
      >
        { char }
      </span>
    )
  }
}

和CSS:

.intro-text {
    width: 80%;

    .single-letter {
        display: inline-block;
        transform-origin: 50% 84%;      
    }

    .hovered {
        animation-name: stretch;
        animation-duration: 0.15s;
        animation-timing-function: linear;
        animation-fill-mode: forwards    
    }

    .unhovered {
        animation-name: stretch-back;
        animation-duration: 0.25s;
        animation-timing-function: linear;
    }
}

如果我.single-letter作为内联元素离开,则动画将不起作用,但文本呈现良好,因此,尽管每个字符都包含在单独<span>的 中,但线条会在正确的位置中断。如果我设置.single-letterinline-block元素,则动画效果很好,但空格会崩溃(因此有条件检查 if char === ' 'in SingleLetter.js)。如果我将空格保留为内联 span 元素,将其余字符保留为 span inline-block,则空格会正确呈现,动画可以正常工作,但是我的换行符不会保留单词。

我可以将我的字符串分成几个IntroText组件,每个组件对应一行,但这显然不是响应式站点上的可行解决方案。我应该怎么办?

编辑:我制作了 CodeSandbox 示例:CodeSandbox

标签: javascripthtmlcssreactjsgatsby

解决方案


您可以通过将单词放在一起来完成此操作inline-block。检查此沙箱以获取工作示例:https ://codesandbox.io/embed/jpw2l4j4py

function IntroLetter({ char }) {
  const [hoverClass, setHoverClass] = useState("single-letter");
  return (
    <span
      className={hoverClass}
      onMouseOver={() => setHoverClass("single-letter hovered")}
      onMouseLeave={() => setHoverClass("single-letter unhovered")}
    >
      {char}
    </span>
  );
}

function IntroWord({ word }) {
  return (
    <span style={{ display: "inline-block" }}>
      {word.split("").map((letter, letterIndex) => (
        <IntroLetter index={letterIndex} char={letter} />
      ))}
    </span>
  );
}

function IntroText({ children }) {
  return (
    <div>
      <p className="intro-text">
        {children.split(" ").map((word, wordIndex) => (
          <Fragment>
            <IntroWord key={wordIndex} word={word} />
            <span> </span>
          </Fragment>
        ))}
      </p>
    </div>
  );
}

推荐阅读