Обтекание текста тегом <p>, когда каждая буква представляет собой отдельный <span>(для анимации) вact.js - PullRequest
1 голос
/ 09 мая 2019

Мне было поручено создать вводный текст на сайте портфолио, который я создаю на 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-letter в качестве элемента inline-block, анимация будет работать отлично, но пробелы сжимаются (отсюда условие, чтобы проверить, является ли char === ' ' в SingleLetter.js). Если я оставлю свои пробелы в качестве встроенных элементов span, а остальные символы как inline-block span, пробелы будут отображаться правильно, анимация будет работать, но тогда мои разрывы строк не сохранят слова.

Я мог бы разделить мою строку на несколько IntroText компонентов, каждый из которых соответствует одной строке, но это, очевидно, не является жизнеспособным решением на адаптивном сайте. Что мне делать?

редактировать: я сделал пример CodeSandbox: CodeSandbox

1 Ответ

0 голосов
/ 09 мая 2019

Вы можете сделать это, собрав слова вместе в 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>
  );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...