задний план
Наиболее часто используемым компонентом в проектах визуализации на большом экране является цифровой компонент, который отображает изменение данных.Для улучшения визуального эффекта необходимо добавить к числу эффект прокрутки, чтобы реализовать анимацию прокрутки, которая постепенно увеличивается от одного числа на другое.
Сначала интеллект-карта:
1. Для достижения эффекта прокрутки контейнер фиксируется, а числа прокручиваются вверх
Сначала перечислите все возможные значения, чтобы сформировать вертикальный список, затем зафиксируйте контейнер и измените значение смещения числа с постоянной скоростью.
Давайте представим реализацию этой схемы.Есть десять значений от 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}%)`
}
Прокрутка с двумя элементами
Посмотрите внимательнее на эффект анимации.На самом деле в окне просмотра всего два элемента,один предыдущее значение, а другой текущее значение.Надо только установить значение смещения прокрутки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;
}
Цифровой компонент, реализующий многократную прокрутку вверх
Используйте 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]);
- Сравните числа в каждой текущей цифре. Если есть изменения, измените смещение. Смещение отражается в разнице между цифрой в текущей цифре и следующей цифрой. Это изменение происходит в каждом кадре. Все объединено вместе, чтобы сформировать прокрутку анимация