Попытка создать эффект набора текста на reactjs

Итак, в основном я уже создал эффект набора текста, но я могу заставить работать только первую строку в массиве. Я хочу записать все в массивах в новых строках, используя эффект набора текста. Я перечислил файлы JSX и CSS ниже. Я также должен указать, что это всего лишь часть большого проекта, поэтому попытка запустить этот JSX и css не сработает.

import React  from 'react';
import "./Content.css";


const content =()=>{
	const message =["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"];
	let i =0 ;
	for(i=0; i<message.length;i++){
		  return(
			<div className='background'>
		  <h1 className = "typewriter">
	  		{message[i]}	
	  	</h1>
	  	</div>

	  	)

	}
	
}

export default content;
background{
	display: flex;
	justify-content: center;
	flex-wrap: wrap;

}

canvas{width: 60;


}

.typewriter {
  text-align: center;
  overflow: hidden; 
  border-right: .15em solid black; 
  color: white;
  font-family: Courier New;
  top:30%;
  font-size: 40px;
  white-space: nowrap; 
  letter-spacing: .30em;
  animation: 
    typing 3.5s steps(30, end),
    blink-caret .75s step-end infinite;
}

/* The typing effect */
@keyframes typing {
  from { width:20% }
  to { width: 50% }
}


@keyframes blink-caret {
  from, to { border-color: transparent }
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
6
0
10 735
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Вы возвращаете один элемент из своей функции на первой итерации цикла. Это неверно. Вам нужно вернуть массив объектов JSX:

const content =()=>{
  const message =["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"];
  let i =0 ;
  let jsxArray = [];
  for(i=0; i<message.length;i++){
    jsxArray.push(
      <div className='background'>
        <h1 className = "typewriter">
            {message[i]}    
        </h1>
      </div>
     );
  }
  return jsxArray;
}

Можно было бы сделать его таким компонентом класса:

class Typer extends React.Component {

  static defaultProps = {
    heading: '',
    dataText: []
  }

  constructor(props) {
    super(props);

    this.state = {
      text: '',
      isDeleting: false,
      loopNum: 0,
      typingSpeed: 150
    }
  }

  componentDidMount() {
    this.handleType();
  }

  handleType = () => {
    const { dataText } = this.props;
    const { isDeleting, loopNum, text, typingSpeed } = this.state;
    const i = loopNum % dataText.length;
    const fullText = dataText[i];

    this.setState({
      text: isDeleting ? fullText.substring(0, text.length - 1) : fullText.substring(0, text.length + 1),
      typingSpeed: isDeleting ? 30 : 150
    });

    if (!isDeleting && text === fullText) {
      
      setTimeout(() => this.setState({ isDeleting: true }), 500);
      
    } else if (isDeleting && text === '') {
      
      this.setState({
        isDeleting: false,
        loopNum: loopNum + 1
      });
      
    }

    setTimeout(this.handleType, typingSpeed);
  };

  render() {    
    return (
      <h1>{ this.props.heading }&nbsp;
        <span>{ this.state.text }</span>
        <span id = "cursor"/>
      </h1>
    );
    
  }
}

ReactDOM.render(
  <Typer
    heading = {'Things I want to type:'}
    dataText = {["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"]} 
  />, 
  document.getElementById('app')
);
@import url('https://fonts.googleapis.com/css?family=VT323');
body {
  font-family: 'VT323', monospace;
  background-color: #003B00;
  padding: 1em 2em;
}

h1 {
  color: #00FF41;
}

#cursor {
  border-left: .1em solid #00FF41;
  animation: blink .7s steps(1) infinite;
}

@keyframes blink {
  50% {
    border-color: transparent;
  }
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>

<div id = "app"></div>

Ссылка на перо: https://codepen.io/AliKlein/pen/aPyKjy JSFiddle: https://jsfiddle.net/am9qke3v/

есть ли способ написать это в терминах функционального компонента с помощью хуков? Я пытаюсь, но безуспешно ...

Seamus.Reeve 03.08.2019 05:09

Тот же вопрос выше ... Я безуспешно пробовал хуки ... Было бы здорово, если бы вы научили нас

Johnny88520 11.09.2019 06:45

@ Seamus.Reeve вот пример показывает, как это можно сделать с помощью хуков ..

Matt Oestreich 22.09.2019 23:24

@ Johnny88520 вот пример показывает, как это можно сделать с помощью хуков ..

Matt Oestreich 22.09.2019 23:24

Вот мой код в Typescript & React с использованием функционального компонента и хуков:

import React, { useState, useEffect } from 'react'
const Typer = ({ title = '', dataText }: TyperProps) => {
  const [text, setText] = useState('')
  const [isDeleting, setIsDeleting] = useState(false)
  const [speed, setSpeed] = useState(150)
  const [loop, setLoop] = useState(0)

  const i: number = loop % dataText.length
  const fullText: string = dataText[i]

  const handleTyping = () => {
    setText(
      isDeleting
        ? fullText.substring(0, text.length - 1)
        : fullText.substring(0, text.length + 1)
    )

    setSpeed(isDeleting ? 30 : 150)

    if (!isDeleting && text === fullText) {
      setTimeout(() => setIsDeleting(true), 500)
    } else if (isDeleting && text === '') {
      setIsDeleting(false)
      setLoop(loop + 1)
    } 
  }

  useEffect(() => {
    const timer = setTimeout(() => {
      handleTyping()
    }, speed)
    return () => clearTimeout(timer)
  })

  return <h1>{title} {text}</h1>
}

interface TyperProps {
  dataText: string[]
  title?: string
}

export default Typer

Компонент interface TyperProps такой же, как и prop-types. Вы можете избавиться от него, если вам это не нужно.

Если вы хотите использовать для этого хуки, вы можете сделать что-то вроде этого:

(большое спасибо @AliKlein для вдохновения)

const { render } = ReactDOM;
const { useState, useEffect } = React;

const CONSTANTS = {
  DELETING_SPEED: 30,
  TYPING_SPEED: 150,
}

function TypeWriter({ messages, heading }) {
  const [state, setState] = useState({
    text: "",
    message: "",
    isDeleting: false,
    loopNum: 0,
    typingSpeed: CONSTANTS.TYPING_SPEED,
  });

  useEffect(() => {
    let timer = "";
    const handleType = () => {
      setState(cs => ({
        ...cs, // cs means currentState
        text: getCurrentText(cs),
        typingSpeed: getTypingSpeed(cs)
      }));
      timer = setTimeout(handleType, state.typingSpeed);
    };
    handleType();
    return () => clearTimeout(timer);
  }, [state.isDeleting]);

  useEffect(() => {
    if (!state.isDeleting && state.text === state.message) {
      setTimeout(() => {
        setState(cs => ({
          ...cs,
          isDeleting: true
        }))
      }, 500);
    } else if (state.isDeleting && state.text === "") {
      setState(cs => ({
        ...cs, // cs means currentState
        isDeleting: false,
        loopNum: cs.loopNum + 1,
        message: getMessage(cs, messages)
      }));
    }
  }, [state.text, state.message, state.isDeleting, messages]);

  function getCurrentText(currentState) {
    return currentState.isDeleting
      ? currentState.message.substring(0, currentState.text.length - 1)
      : currentState.message.substring(0, currentState.text.length + 1);
  }

  function getMessage(currentState, data) {
    return data[Number(currentState.loopNum) % Number(data.length)];
  }

  function getTypingSpeed(currentState) {
    return currentState.isDeleting
      ? CONSTANTS.TYPING_SPEED
      : CONSTANTS.DELETING_SPEED;
  }

  return (
    <h1>
      {heading}&nbsp;
        <span>{state.text}</span>
      <span id = "cursor" />
    </h1>
  );
}

let msgs = ["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"];
render(<TypeWriter heading = {"Things I want to type:"} messages = {msgs} />, document.body);
@import url('https://fonts.googleapis.com/css?family=VT323');
body {
  font-family: 'VT323', monospace;
  background-color: #003B00;
  padding: 1em 2em;
}

h1 {
  color: #00FF41;
}

#cursor {
  border-left: .1em solid #00FF41;
  animation: blink .7s steps(1) infinite;
}

@keyframes blink {
  50% {
    border-color: transparent;
  }
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>

+1 из-за крючков, я тоже так справляюсь. Хотя я думаю, что лучше с переменной typingSpeed ​​(на символ / предложение)

typekev 23.09.2019 13:23

React-MK (да, я автор, нет, вам не нужно его устанавливать) обрабатывает это, используя в основном ловушку useEffect (запускаемую жизненным циклом компонента, чтобы избежать проблем с рендерингом) и настраиваемую ловушку useKeyboard.

Кроме того, я думаю, что реалистичная анимация набора текста должна поддерживать реалистичные задержки между набором символов и предложений. Смотрите предложениеDelayPerCharRange и keyPressDelayRange в следующем примере.

// Keyboard.js
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import getTimer from './getTimer';
import useKeyboard from './useKeyboard';
import { defaultKeyPressDelay } from './constants';

const initialState = [];

export const type = (...actions) => [...actions];

export default function Keyboard({ children, sentenceDelayPerCharRange, keyPressDelayRange }) {
  const [text, setText, clearText] = useKeyboard();
  const [remainingActions, setRemainingActions] = useState(initialState);

  useEffect(
    /* istanbul ignore next */
    () => {
      if (remainingActions.length === initialState.length) {
        setRemainingActions(
          typeof children === 'function' ? children({ type }) : [children.toString()],
        );
      }
    },
    [children],
  );

  useEffect(() => {
    if (remainingActions.length > initialState.length) {
      const [newAction, ...newRemainingActions] = remainingActions;

      const doAction =
        /* istanbul ignore next */
        action =>
          setText(action, keyPressDelayRange).then(
            /* istanbul ignore next */
            () => setRemainingActions(newRemainingActions),
          );
      const doClear =
        /* istanbul ignore next */
        action => clearText(action).then(doAction);
      getTimer(newAction, sentenceDelayPerCharRange).then(doClear);
    }
  }, [remainingActions]);

  return text;
}

Keyboard.propTypes = {
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]).isRequired,
  keyPressDelayRange: PropTypes.arrayOf(PropTypes.number),
  sentenceDelayPerCharRange: PropTypes.arrayOf(PropTypes.number),
};

Keyboard.defaultProps = {
  keyPressDelayRange: defaultKeyPressDelay,
  sentenceDelayPerCharRange: defaultKeyPressDelay.map(delay => delay * 1.25),
};

Также есть несколько вспомогательных функций, таких как getTimer / s и getDelay.

// useKeyboard.js
import { useState, useRef, useEffect } from 'react';
import getTimers from './getTimers';
import getTimer from './getTimer';

const initialState = '';

export const backspace = (chars, setChars) =>
  setChars(chars.length > 1 ? chars.slice(0, chars.length - 1) : initialState);

export const type = (chars, nextChar, setChars) => setChars(`${chars}${nextChar}`);

export default function useKeyboard() {
  const [chars, setChars] = useState(initialState);
  const [remainingChars, setRemainingChars] = useState(initialState);
  const [resolver, setResolver] = useState(undefined);
  const [delayRange, setDelayRange] = useState(undefined);

  const charsRef = useRef(chars);
  charsRef.current = chars;

  useEffect(() => {
    /* istanbul ignore next */
    if (remainingChars.length > initialState.length) {
      const [nextChar, ...newRemainingChars] = remainingChars;
      const doType = () => type(chars, nextChar, setChars);
      const doSetRemainingChars = () => setRemainingChars(newRemainingChars);
      getTimer(nextChar, delayRange)
        .then(doType)
        .then(doSetRemainingChars);
    } else if (typeof resolver === 'function') {
      resolver();
      setResolver(undefined);
      setRemainingChars(initialState);
    }
  }, [remainingChars]);

  const setText = (text, keyPressDelayRange) =>
    new Promise(resolve => {
      setResolver(() => resolve);
      setDelayRange(keyPressDelayRange);
      setChars(initialState);
      /* istanbul ignore else */
      if (typeof text === 'string') {
        setRemainingChars(text);
      } else {
        resolve();
      }
    });

  const clearText = action =>
    new Promise(resolve =>
      /* istanbul ignore next */
      !chars
        ? resolve(action)
        : getTimers(charsRef.current.split(''), () => {
            /* istanbul ignore next */
            backspace(charsRef.current, setChars);
            /* istanbul ignore next */
            return charsRef.current.length === 0 && resolve(action);
          }),
    );

  const text = chars;

  return [text, setText, clearText];
}

Мне нравится эта реализация, потому что, несмотря на малый вес, она сохраняет декларативный характер. Не говоря уже о том, что он на самом деле полагается на образ жизни компонентов, а не только на setInterval / setTimeout (если вы когда-либо использовали библиотеку анимации набора текста, которая иногда искажает текст, это может быть единственная зависимость).

Отметьте этот новый компонент https://www.npmjs.com/package/reactjs-typing-effect

пряжа добавить эффект реакции

  import ReactJsTyping from 'reactjs-typing-effect';

  const list=['Reactjs Typing','custom speed']
  render(){
      <div style = {{ fontSize: 20, color: '#2196F3'}}>
      <ReactJsTyping StringList = {list} speed = {500}/>
       </div>
   }

Другие вопросы по теме