Внедрение постепенно растущей цифровой анимации

внешний интерфейс
Внедрение постепенно растущей цифровой анимации

задний план

Наиболее часто используемым компонентом в проектах визуализации на большом экране является цифровой компонент, который отображает изменение данных.Для улучшения визуального эффекта необходимо добавить к числу эффект прокрутки, чтобы реализовать анимацию прокрутки, которая постепенно увеличивается от одного числа на другое.

Сначала интеллект-карта:

思维导图.png

1. Для достижения эффекта прокрутки контейнер фиксируется, а числа прокручиваются вверх

demo1.gif

Сначала перечислите все возможные значения, чтобы сформировать вертикальный список, затем зафиксируйте контейнер и измените значение смещения числа с постоянной скоростью.

Давайте представим реализацию этой схемы.Есть десять значений от 0 до 9, и каждое число составляет 10% вертикального списка, поэтому значение смещения по вертикали 0% -> -90%.

выполнить:

<ul>
  <li>
    <span>0123456789</span>
  </li>
</ul>
ul{
  margin-top: 200px;
}
ul li{
  margin:0 auto;
  width: 20px;
  height: 30px;
  text-align: center;
  border:2px solid rgba(221,221,221,1);
  border-radius:4px;
}
ul li span{
  position: absolute;
  color: #fff;
  top: 30%;
  left: 50%;
  transform: translate(-50%,0);
  transition: transform 500ms ease-in-out;
  writing-mode: vertical-rl;
  text-orientation: upright;
  letter-spacing: 17px;
}
let spanDom = document.querySelector('span')
let start = 0
setInterval(() =>{
  start++
  if(start>9){
    start = 0
  }
  spanDom.style.transform = `translate(-50%,-${start*10}%)`
}, 1000)

Есть проблема с приведенным выше кодом, когда мы переходим от 9 к 0, смещение контейнера изменяется напрямую от -90% до 0%. Однако из-за фиксированного времени анимации перехода будет ситуация прокрутки в обратном направлении, для решения этой проблемы можно обратиться к идее бесшовной прокрутки

  • Скопируйте 0 после 9,

  • Когда вертикальный список прокрутится до 9, продолжайте прокручивать до скопированного 0

  • При прокрутке до скопированного 0 измените положение смещения списка на 0 и установите время анимации на 0.

<ul>
  <li>
    <span>01234567890</span>
  </li>
</ul>
let spanDom = document.querySelector('span')
let start = 0
var timer = setInterval(fn, 1000);
function fn() {
  start++
  clearInterval(timer)
  timer = setInterval(fn,start >10 ? 0 : 1000);
  if(start>10){
    spanDom.style.transition = `none`
    start = 0
  }else{
    spanDom.style.transition = `transform 500ms ease-in-out`
  }
  spanDom.style.transform = `translate(-50%,-${start/11*100}%)`
}

demo2.gif

Прокрутка с двумя элементами

Посмотрите внимательнее на эффект анимации.На самом деле в окне просмотра всего два элемента,один предыдущее значение, а другой текущее значение.Надо только установить значение смещения прокруткиtranslateY(-100%)

Конкретные идеи:

  • Объявите две переменные для хранения предыдущих значений соответственноprev, а измененное значениеcur; объявить переменнуюplayкак переключатель анимации прокрутки для этих двух значений

  • использоватьuseEffectПрослушайте входящее значение: если это действительное число, присвойте значение до измененияprev, присвоить текущее переданное значениеcurи установитьpalyдляtrueВключить анимацию прокрутки

Вот скорректированная структура кода:

 <div className={styles.slider}>
   {[prev, cur].map((item, index) => (
      <span key={index} className={`${styles['slider-text']} ${playing && styles['slider-ani']} ${(prev === 0 && cur === 0 && index ===0) && styles['slider-hide']}`}>
        {item}
      </span>
    ))}
  </div>
const { value} = props
const [prev, setPrev] = useState(0)
const [cur, setCur] = useState(0)
const [playing, setPlaying] = useState(false)

  const play = (pre, current) => {
    setPrev(pre)
    setCur(current)
    setPlaying(false)
    setTimeout(() => {
      setPlaying(true)
    }, 20)
  }

  useEffect(() => {
    if (!Number.isNaN(value)) {
      play(cur, value)
    } else {
      setPrev(value)
      setCur(value)
    }
  }, [value])
.slider {
  display: flex;
  flex-direction: column;
  height: 36px;
  margin-top: 24%;
  overflow: hidden;
  text-align: left;
}

.slider-text {
  display: block;
  height: 100%;
  transform: translateY(0%);
}

.slider-ani {
  transform: translateY(-100%);
  transition: transform 1s ease;
}
.slider-hide {
  opacity: 0;
}

Цифровой компонент, реализующий многократную прокрутку вверх

组件.gif

Используйте API-интерфейс requestAnimationFrame() H5, чтобы реализовать анимационный эффект постепенного увеличения чисел.

Реализуйте постепенно увеличивающуюся анимацию прокрутки числа и завершите ее в течение заданного времени. Чтобы увидеть плавный эффект анимации, вам нужно обновлять состояние элемента с определенной частотой Анимация JS выполняется путем рендеринга/рисования элементов за короткий промежуток времени, поэтому таймер всегда Javascript Основная технология анимации, ключ интервал обновления,Время обновления должно быть как можно короче, чтобы эффект анимации выглядел более плавным и не застревал; в то же время интервал обновления не должен быть слишком коротким, и необходимо убедиться, что браузер способен отображать анимации.

Большинство компьютерных мониторов имеют частоту обновления 60 Гц или 60 перерисовок в секунду. Таким образом, лучший интервал цикла для плавной анимации обычно составляет 1000 мс/60, что составляет около 16,6 мс.

сравнение таймеров

  • В отличие от setTimeout и setInterval, requestAnimationFrame не требует от программиста самостоятельной установки интервала. Проблема с setTimeout и setInterval — низкая точность. Их внутренняя работа определяет, что параметр interval на самом деле просто указывает, как долго код анимации должен быть добавлен в очередь потоков пользовательского интерфейса браузера, чтобы ожидать выполнения. Если в начало очереди были добавлены другие задачи, код анимации будет выполнен после завершения предыдущих задач.

  • requestAnimationFrame принимает системный временной интервал, он потребует от браузера перерисовки один раз в соответствии с его собственной частотой для поддержания наилучшей эффективности отрисовки и не приведет к чрезмерному рисованию и увеличению накладных расходов, поскольку интервал времени слишком короткий; использование анимации недопустимо. плавный, так что различные эффекты анимации веб-страниц могут иметь единый механизм обновления, тем самым экономя системные ресурсы, повышая производительность системы и улучшая визуальные эффекты.

  • requestAnimationFrame агрегирует все операции DOM в каждом кадре и завершает их за одну перерисовку или перекомпоновку, а интервал перерисовки или перекомпоновки близко соответствует частоте обновления браузера.

  • requestAnimationFrame не будет перерисовывать или переформатировать скрытые или невидимые элементы, что означает меньшее использование ЦП, графического процессора и памяти.

  • requestAnimationFrame — это API, предоставляемый браузером специально для анимации. Браузер автоматически оптимизирует вызов метода во время выполнения, и если страница не находится в активном состоянии, анимация будет автоматически приостановлена, что эффективно снижает нагрузку на ЦП.

requestAnimationFrame реализует идеи анимации прокрутки

  • Анимация начинается, записывая время, когда анимация началасьstartTimeRef.current
const startTimeRef = useRef(Date.now());
const [t, setT] = useState(Date.now());
  • После каждого кадра анимации записывайте, сколько времени прошло с начала анимации, и вычисляйте, каким должен быть номер текущего кадра, т. е.currentValue
useEffect(() => {
    const rafFunc = () => {
      const now = Date.now();
      const t = now - startTimeRef.current;
      if (t >= period) {
        setT(period);
      } else {
        setT(t);
        requestAnimationFrame(rafFunc);
      }
    };
    let raf;
    if (autoScroll) {
      raf = requestAnimationFrame(rafFunc);
      startTimeRef.current = Date.now();
    } else {
      raf && cancelAnimationFrame(raf);
    }
    return () => raf && cancelAnimationFrame(raf);
}, [period, autoScroll]);

const currentValue = useMemo(() => ((to - from) / period) * t + from, [t, period, from, to]);

  • Сравните числа в каждой текущей цифре. Если есть изменения, измените смещение. Смещение отражается в разнице между цифрой в текущей цифре и следующей цифрой. Это изменение происходит в каждом кадре. Все объединено вместе, чтобы сформировать прокрутку анимация

Дисплей достижений

成果.gif

成果2.gif