Donc, fondamentalement, j'ai déjà créé l'effet de frappe, mais je ne peux que faire fonctionner la première chaîne du tableau. Je veux tout écrire sur les tableaux dans de nouvelles lignes en utilisant l'effet de frappe.J'ai listé les fichiers JSX et CSS ci-dessous. Je dois également souligner que cela fait partie d'un grand projet, donc essayer de lancer ce JSX et css ne fonctionnera pas

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>
4
Udendu Abasili 17 avril 2018 à 22:31

5 réponses

Meilleure réponse

Vous retournez un seul élément de votre fonction à la première itération de votre boucle. Ceci est une erreur. Vous devez renvoyer un tableau d'objets 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;
}
1
Pop-A-Stash 17 avril 2018 à 19:56

Voici mon code dans Typescript & React en utilisant un composant fonctionnel et des crochets:

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

La partie interface TyperProps est comme prop-types. Vous pouvez vous en débarrasser si vous n'en avez pas besoin.

1
Riki No Pantsu 6 sept. 2019 à 18:04

react-mk (oui, je suis l'auteur, non, vous n'avez pas besoin de l'installer ) gère cela en utilisant principalement le crochet useEffect (déclenché par le cycle de vie du composant pour éviter les problèmes de rendu) et un crochet useKeyboard personnalisé.

De plus, je pense qu'une animation de frappe réaliste devrait prendre en charge des délais réalistes entre la frappe de caractères et les phrases. Voir sentenceDelayPerCharRange et keyPressDelayRange dans l'exemple suivant.

// 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),
};

Il existe également des fonctions d'assistance telles que getTimer / s et 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];
}

J'aime cette implémentation car bien que légère, elle conserve son caractère déclaratif. Sans oublier qu'il repose en fait sur le mode de vie des composants au lieu de se limiter à setInterval / setTimeout (si vous avez déjà utilisé une bibliothèque d'animation de frappe qui brouille le texte de temps en temps, cette seule dépendance peut être le coupable.)

1
typekev 23 sept. 2019 à 11:27

Pourrait en faire un composant de classe comme celui-ci:

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>

Lien vers le stylet: https://codepen.io/AliKlein/pen/aPyKjy JSFiddle: https://jsfiddle.net/am9qke3v/

4
Ali Klein 28 déc. 2018 à 03:25

Si vous souhaitez utiliser des crochets pour accomplir cela, vous pouvez faire quelque chose comme ceci:

(un grand merci à @AliKlein pour l'inspiration)

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>
2
Matt Oestreich 22 sept. 2019 à 23:04