js和Css3实现打字特效动画效果

js和Css3实现打字特效动画效果5203
核心js代码
<script>const getEl = el => document.getElementById(el)const setStyle = (el, prop, val) => el.style[prop] = valconst setAttr = (el, attr, val) => el.setAttribute(attr, val)const addClass = (el, className) => el.classList.add(className)const removeClass = (el, className) => el.classList.remove(className)const resetStyles = el => el.removeAttribute('style')const removeAllChildren = el => {  while (el.hasChildNodes()) el.removeChild(el.lastChild)}const WRAPPER = getEl('wrapper'),      PAPER = getEl('paper'),      LETTERS = getEl('letters'),      CURSOR = getEl('cursor')let HAS_STARTED_TYPING = false,    LAST_TYPE_TIMESTAMP = 0const MIN_COL = 9,      MAX_COL = (LETTERS.clientWidth / 10) - 2,      MIN_ROW = 4,      MAX_ROW = 34,      LETTER_WIDTH = 10,      LETTER_HEIGHT = 20,      COLORS = {        BLUE: 'rgb(3,169,244)',        RED: 'rgb(239,83,80)',        PURPLE: 'rgb(171,71,188)',        GREEN: 'rgb(67,160,71)',        YELLOW:' rgb(253,216,53)'      }const STATE = {  range: 0.1,  pos: {    row: MIN_ROW,    col: MIN_COL  }}const getRandColor = () => {  const rand = Math.floor((Math.random() * 5) + 1)  switch(rand){    case 1:      return COLORS.BLUE    case 2:      return COLORS.RED    case 3:      return COLORS.PURPLE    case 4:      return COLORS.GREEN    case 5:      return COLORS.YELLOW  }}const getRandPosOffScreen = () => {  const lowX1 = 0 - (window.innerWidth * 0.3),        highX1 = 0 - (window.innerWidth * 0.2),        lowY1 = 0,        highY1 = window.innerHeight,                lowX2 = window.innerWidth * 1.2,        highX2 = window.innerWidth * 1.3,        lowY2 = 0,        highY2 = window.innerHeight,                lowX3 = 0,        highX3 = window.innerWidth,        lowY3 = 0 - (window.innerHeight * 0.3),        highY3 = 0 - (window.innerHeight * 0.2),                lowX4 = 0,        highX4 = window.innerWidth,        lowY4 = window.innerHeight * 1.2,        highY4 = window.innerHeight * 1.3    const rand = Math.floor((Math.random() * 4) + 1)    let x = 0,      y = 0    switch(rand){    case 1:      x = Math.floor(Math.random() * (highX1 - lowX1 + 1)) + lowX1      y = Math.floor(Math.random() * (highY1 - lowY1)) + lowY1      break    case 2:      x = Math.floor(Math.random() * (highX2 - lowX2 + 1)) + lowX2      y = Math.floor(Math.random() * (highY2 - lowY2)) + lowY2      break    case 3:      x = Math.floor(Math.random() * (highX3 - lowX3 + 1)) + lowX3      y = Math.floor(Math.random() * (highY3 - lowY3)) + lowY3      break    case 4:      x = Math.floor(Math.random() * (highX4 - lowX4 + 1)) + lowX4      y = Math.floor(Math.random() * (highY4 - lowY4)) + lowY4      break  }    return { x, y }}const setLetterPos = (letter, x, y) => {  setStyle(letter, 'left', x + 'px')  setStyle(letter, 'top', y + 'px')}const setLetterColor = letter => {  const color = getRandColor()  setStyle(letter, 'color', color)}const Letter = key => {  const letter = document.Element('div')  letter.innerHTML = key  setLetterColor(letter)  addClass(letter, 'off-screen')  addClass(letter, 'letter')  return letter}const setInitialLetterPos = letter => {  const pos = getRandPosOffScreen()  setLetterPos(letter, pos.x, pos.y)}const isValidLetter = e => {  return !e.ctrlKey     && e.key !== 'Enter'    && !(e.key === ' ' && STATE.pos.col === MIN_COL)}const isEndOfPage = () => {  return STATE.pos.row === MAX_ROW && STATE.pos.col === MAX_COL}const initializeLetter = key => {  const letter = Letter(key)  setInitialLetterPos(letter)  LETTERS.appendChild(letter)  return letter}const bumpLetterPos = isUp => {  if(isUp){    if(STATE.pos.col < MAX_COL){      STATE.pos.col = Math.min(STATE.pos.col + 1, MAX_COL)    }    else{      STATE.pos.col = MIN_COL      STATE.pos.row = Math.min(STATE.pos.row + 1, MAX_ROW)    }  }  else{    if(STATE.pos.col > MIN_COL){      STATE.pos.col = Math.max(STATE.pos.col - 1, MIN_COL)    }    else{      STATE.pos.col = MAX_COL      STATE.pos.row = Math.max(STATE.pos.row - 1, MIN_ROW)    }  }}const bumpCursorPos = () => {  const x = STATE.pos.col * LETTER_WIDTH + CURSOR.clientWidth,        y = STATE.pos.row * LETTER_HEIGHT  setLetterPos(CURSOR, x, y)}const determineFinalLetterPos = () => {  let x = 0,      y = 0  if(STATE.pos.col <= MAX_COL){    x = STATE.pos.col * LETTER_WIDTH    y = STATE.pos.row * LETTER_HEIGHT  }  else{    x = STATE.pos.col * LETTER_WIDTH    y = (STATE.pos.row + 1) * LETTER_HEIGHT  }    bumpLetterPos(true)  bumpCursorPos()    return {x, y}}const setFinalLetterPos = letter => {  const pos = determineFinalLetterPos()  setLetterPos(letter, pos.x, pos.y)}const getLastLetter = () => {  const letters = LETTERS.childNodes  let letter = null  for(let i = letters.length - 1; i >= 0; i--){    if(!letters[i].dataset.removed){      letter = letters[i]      break    }  }  return letter}const setLeavingLetterPos = letter => {  const pos = getRandPosOffScreen()  setLetterPos(letter, pos.x, pos.y)  addClass(letter, 'off-screen')}const removeLetter = () => {  const letter = getLastLetter(),        color = getRandColor()  if(letter === null) return 0  LAST_TYPE_TIMESTAMP = moment()  setStyle(letter, 'color', color)  setLeavingLetterPos(letter)  setAttr(letter, 'data-removed', true)  bumpLetterPos(false)  bumpCursorPos()  setTimeout(() => {    LETTERS.removeChild(letter)  }, 500)}const handleAlternateKeys = e => {  switch(e.keyCode){    case 8: // Backspace      removeLetter()      break    case 9: // Tab      e.preventDefault()      break    case 13: // Enter      break  }}const typeLetter = key => {  LAST_TYPE_TIMESTAMP = moment()  const letter = initializeLetter(key)  setFinalLetterPos(letter)  setTimeout(() => {    removeClass(letter, 'off-screen')    setTimeout(() => setStyle(letter, 'color', 'black'), 500)  }, 13)}let typeInterval = nullconst typeSentence = sentence => {  let i = 0  typeInterval = setInterval(() => {    typeLetter(sentence[i])    if(i === sentence.length - 1) clearInterval(typeInterval)    i++  }, 200)}const onInitialType = () => {  STATE.pos.row = MIN_ROW  STATE.pos.col = MIN_COL  removeAllChildren(LETTERS)  clearInterval(typeInterval)  HAS_STARTED_TYPING = true}const checkIfTyping = () => {  const timeToLastType = moment() - LAST_TYPE_TIMESTAMP  if(!PAPER.classList.contains('typing') && timeToLastType <= 300){    addClass(PAPER, 'typing')  }  else if(PAPER.classList.contains('typing') && timeToLastType > 300){    removeClass(PAPER, 'typing')  }}window.onkeypress = e => {  if(!HAS_STARTED_TYPING) onInitialType()  if(!isEndOfPage() && isValidLetter(e)) typeLetter(e.key)}window.onkeydown = e => {  if(!HAS_STARTED_TYPING) onInitialType()  handleAlternateKeys(e)}window.onload = () => {  typeSentence('Start typing something!')  setInterval(() => checkIfTyping(), 300)}</script>

也许你还喜欢