Im Grunde habe ich den Tippeffekt bereits erstellt, aber ich kann nur die erste Zeichenfolge im Array zum Laufen bringen. Ich möchte alle Arrays in neuen Zeilen mit dem Tippeffekt ausschreiben. Ich habe die JSX- und CSS-Dateien unten aufgelistet. Ich sollte auch darauf hinweisen, dass dies nur ein Teil eines großen Projekts ist, so dass der Versuch, JSX und CSS auszuführen, nicht funktioniert

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>
6
Udendu Abasili 17 Apr. 2018 im 22:31

5 Antworten

Beste Antwort

Sie geben bei der ersten Iteration Ihrer Schleife ein einzelnes Element von Ihrer Funktion zurück. Das ist falsch. Sie müssen ein Array von JSX-Objekten zurückgeben:

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 Apr. 2018 im 19:56

Hier ist mein Code in Typescript & React mit Funktionskomponente und Hooks:

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

Der interface TyperProps Teil ist genau wie prop-types. Sie können es loswerden, wenn Sie nicht müssen.

1
Riki No Pantsu 6 Sept. 2019 im 18:04

react-mk (Ja, ich bin der Autor, nein, Sie müssen es nicht installieren ) behandelt dies hauptsächlich mit dem useEffect-Hook (ausgelöst durch den Komponentenlebenszyklus, um Rendering-Probleme zu vermeiden) und einem benutzerdefinierten useKeyboard-Hook.

Ich denke auch, dass eine realistische Schreibanimation realistische Verzögerungen zwischen der Eingabe von Zeichen und Sätzen unterstützen sollte. Siehe satzDelayPerCharRange und keyPressDelayRange im folgenden Beispiel.

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

Es gibt auch einige Hilfsfunktionen wie getTimer / s und 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];
}

Ich mag diese Implementierung, weil sie zwar leicht ist, aber dennoch deklarativ ist. Ganz zu schweigen davon, dass es sich tatsächlich um den Lebensstil der Komponenten handelt und nicht nur um setInterval / setTimeout (wenn Sie jemals eine Schreibanimationsbibliothek verwendet haben, die gelegentlich Text verstümmelt, kann dieses alleinige Vertrauen der Schuldige sein.)

1
typekev 23 Sept. 2019 im 11:27

Könnte es zu einer Klassenkomponente wie dieser machen:

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>

Link zum Stift: https://codepen.io/AliKlein/pen/aPyKjy JSFiddle: https://jsfiddle.net/am9qke3v/

4
Ali Klein 28 Dez. 2018 im 03:25

Wenn Sie dazu Hooks verwenden möchten, können Sie Folgendes tun:

(Vielen Dank an @AliKlein für die 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 im 23:04