предисловие
Сначала последний вопрос на собеседовании: выполнение внешнего интерфейса необходимо для работы с анимацией, так как же можно реализовать анимацию?
-
JavaScript:
setTimeout
иsetInterval
-
Css3:
transition
иanimation
-
Html:
canvas
иSVG
- requestAnimationFrame API
- ...
- Знаете ли вы какие-либо другие способы достижения анимации?
requestAnimationFrame API
что
Эта статья в основном изучаетrequestAnimationFrame API
, как следует из названия,запрос кадра анимации, также называемыйрамка петля.
размещено в текстеjs
Весь код — настоящий код, просто скопируйте и запустите.
Как играть
Когда мы что-то узнаем, мы должны сначала посмотреть на этоMDN
как сказать.
window.requestAnimationFrame()
Сообщите браузеру, что вы хотите выполнить анимацию, и попросите браузер вызвать указанную функцию обратного вызова, чтобы обновить анимацию перед следующей перерисовкой. Этот метод должен передать функцию обратного вызова в качестве параметра, функция обратного вызова будет выполнена до следующей перерисовки браузера.
Браузерная перерисовка и переформатированиеПозже будет отдельная статья. Неважно, если вы сейчас не понимаете, это не влияет на наше обучение.requestAnimationFrame API
.
Давайте сначала познакомимся с ним, согласно документации. Мы передаем ему функцию обратного вызоваtest
.
//html代码全文通用,所以只在此贴出一次
<body>
<h1>requestAnimationFrame API</h1>
<button id='begin' class="begin">开始</button>
<button id='end' class="end">停止</button>
</body>
//js
(() => {
function test() {
console.log('🚀🚀hello ~ requestAnimationFrame');
}
requestAnimationFrame(test)
})()
Как видите, консоль успешно вывела один разlog
.
Но он выполняется только один раз, как его оживить? не волнуйся, посмотри еще разMDN
Как сказать.
Примечание. Если вы хотите продолжить обновление следующего кадра анимации перед следующей перерисовкой браузера, сама функция обратного вызова должна быть вызвана снова.
window.requestAnimationFrame()
Получается снова вызывается в callback-функцииrequestAnimationFrame
Только после этого измените код и повторите попытку.
(() => {
let n = 0
function test() {
n++
console.log(`🚀🚀hello ~ requestAnimationFrame ${n}`);
requestAnimationFrame(test)
}
requestAnimationFrame(test)
})()
Проверьте это, это действительно работает.
частота выполнения
В это время некоторые друзья собираются спросить, мне не нравитсяsetTimeout
иsetInterval
Установите время так, почему оно выполняется с интервалами?
Посмотрите, что написано в документации.
Количество выполнений функции обратного вызова обычно в секунду60раз, но в большинстве случаев
W3C
В рекомендуемых браузерах количество выполнений функции обратного вызова обычно равноВремя обновления экрана браузерасовпадение.
В этот раз я знаю, получается, что ему вообще не нужно вручную задавать интервал выполнения, а согласноВремя обновления экрана браузераАвтоматически настраивается, то есть столько раз, сколько обновляется экран браузера, столько же раз и выполняется. Я просто хочу что-то сказать, когда увижу этосильно сломан.
Так что жеВремя обновления экрана браузераШерстяная ткань?
Частота обновления экрана (количество раз):Количество раз, которое изображение появляется на экране в секунду. Обычные ноутбуки имеют частоту 60 Гц.
параметр обратного вызова
Старые правила, сначала посмотрите документацию.
Функция обратного вызова будет передана в
DOMHighResTimeStamp
параметр,DOMHighResTimeStamp
Указывает, что в настоящее времяrequestAnimationFrame()
Время срабатывания отсортированной функции обратного вызова.
Измените код, чтобы увидеть этот параметр.
(() => {
function test(timestamp) {
console.log(`🚀🚀hello ~ requestAnimationFrame ${timestamp}`);
requestAnimationFrame(test)
}
requestAnimationFrame(test)
})()
Хороший парень, с точностью до трех знаков после запятой. Так что же означает этот текст в документе?
в том же кадреНесколько функций обратного вызова, каждый из которых получитта же временная метка, даже если рабочая нагрузка предыдущей функции обратного вызова была рассчитанапотребовалось некоторое время. Отметка времени представляет собой десятичное число в миллисекундах с минимальной точностью 1 мс (1000 мкс).
Модифицируем код, выполняем два одновременноrequestAnimationFrame
Посмотри.
(() => {
function test1(timestamp) {
console.log(`🚀🚀hello ~ requestAnimationFrame1 ${timestamp}`);
requestAnimationFrame(test1)
}
function test2(timestamp) {
console.log(`🚀🚀hello ~ requestAnimationFrame2 ${timestamp}`);
requestAnimationFrame(test2)
}
requestAnimationFrame(test1)
requestAnimationFrame(test2)
})()
Видно, что дваrequestAnimationFrame
Вывод метки времени в консоли такой же. То есть, когда браузер обновится один раз, выполните всеrequestAnimationFrame
, и их параметры обратного вызова точно такие же.
Самосохранение браузера
Чтобы улучшить производительность и время работы от батареи, в большинстве браузеров при
requestAnimationFrame()
работать в фоновых вкладках или скрыто<iframe>
миля,requestAnimationFrame()
Вызовы приостанавливаются для повышения производительности и увеличения срока службы батареи.
Это удивительно. Если вы не просматривали страницу в это время и не закрыли ее, тоrequestAnimationFrame()
Работает здесь все время, потребляет много производительности. Другие разработчики уже давно об этом подумали, то есть пока вы меня не смотрите, то мне будет лень(是不是跟你们上班一样,领导没盯着你,你就刷掘金摸鱼
).
Проверьте предыдущий код. Для удобства я добавилbutton
.
const beginBtn = document.querySelector("#begin")
beginBtn.addEventListener("click", () => {
requestAnimationFrame(test)
})
let n = 0
function test() {
n++
console.log(`🚀🚀hello ~ requestAnimationFrame ${n}`);
requestAnimationFrame(test)
}
Как вы можете видеть, когда консоль печатает наполовину (высоту), я вырезаю другую страницу, а когда через несколько секунд я сокращаю, она все еще выводится в половинном положении.
возвращаемое значение
Один
long
Целое число, идентификатор запроса, является уникальным идентификатором в списке обратного вызова. является ненулевым значением и не имеет никакого другого значения.
Когда следующий код щелкает для запуска, выводrequestAnimationFrame
Возвращаемое значение. Видно, что при каждом его выполнении значение будет+1
(() => {
const beginBtn = document.querySelector("#begin")
let myRef;
beginBtn.addEventListener("click", () => {
myRef = requestAnimationFrame(test)
})
function test() {
myRef = requestAnimationFrame(test)
console.log('🚀🚀~ myRef:', myRef);
}
})()
прекратить выполнение
Вы можете передать это значение
window.cancelAnimationFrame()
для отмены функции обратного вызова.
тогда, если я хочу прекратить при определенных условияхrequestAnimationFrame
Что делать, чиновник тоже дал ответ, т.е.cancelAnimationFrame API
. просто поставьrequestAnimationFrame
Возвращаемое значение передается в качестве параметраcancelAnimationFrame
Вот и все.
(() => {
const beginBtn = document.querySelector("#begin")
const endBtn = document.querySelector("#end")
let myRef;
beginBtn.addEventListener("click", () => {
myRef = requestAnimationFrame(test)
})
endBtn.addEventListener("click", () => {
cancelAnimationFrame(myRef)
})
function test() {
myRef = requestAnimationFrame(test)
console.log('🚀🚀~ myRef:', myRef);
}
})()
Как видите, когда я нажимаю «Пуск», консоль продолжает выводить контент, а когда я нажимаю «Стоп», консоль прекращает вывод.
На самом деле это не нужноAPI
Он также может достичь цели прекращения выполнения, например простогоif语句
.
(() => {
function test(timestamp) {
console.log(`🚀🚀hello ~ requestAnimationFrame ${timestamp}`);
if (timestamp < 500) {
requestAnimationFrame(test)
}
}
requestAnimationFrame(test)
})()
Видно, что когдаtimestamp
Он останавливается, когда превышает 500. Возможностей, конечно, больше, а пользоваться умными головами - дело друзей.
Советы
Таким образом, мы можем передать временной интервал между каждыми двумя выполнениями для внешнего использования. Получив его извне, вы можете делать вещи, например, интервал времени накапливается до1000просто делай что угодно~
(() => {
let startTime = Date.now();
function handleTicker() {
foo(Date.now() - startTime);
startTime = Date.now();
requestAnimationFrame(handleTicker);
}
requestAnimationFrame(handleTicker);
let t = 0
function foo(timeInterval) {
t += timeInterval
console.log('🚀🚀~ t:', t);
if (t > 1000) {
console.log('🚀🚀~ 搞事情');
t = 0
}
}
})()
Видно, что когдаt
Совокупный более1000
Когда я что-то делал, то сбрасывалt
, и так далее.
анимация
В заголовке написано, что это анимация артефактаAPI
Ну, если ты не будешь делать вид, что выкладываешь анимацию, тебе скажут«Автор сенсационных заголовков». Поэтому я решил реализовать простойdemo
Бар.
<style>
#box {
width: 0px;
height: 50px;
background-color: blue;
}
</style>
<body>
<h1>requestAnimationFrame API</h1>
<button id='begin' class="begin">开始</button>
<button id='end' class="end">停止</button>
<div id='box'></div>
</body>
(() => {
const beginBtn = document.querySelector("#begin")
const endBtn = document.querySelector("#end")
const box = document.querySelector("#box")
let myRef;
beginBtn.addEventListener("click", () => {
myRef = requestAnimationFrame(test)
})
endBtn.addEventListener("click", () => {
cancelAnimationFrame(myRef)
})
function test() {
box.style.width = `${myRef}%`
myRef = requestAnimationFrame(test)
}
})()
совместимость
Совместимость показана на рисунке, а ссылка размещена здесь.Если вам нужно проверить детали, нажмите, чтобы найти их самостоятельно.
В этой статье рассказывается о некоторых основополагающих принципах и даетсяrequestAnimationFrame
Полноплатформенная обработка, я не у всех обнаруживал мины, серфил сам, если надо~
Глубокое понимание requestAnimationFrame
тестовый тест
setTimeout && setInterval
setTimeout
иsetInterval
Проблема в том, что они недостаточно точны. Их внутренний рабочий механизм определяетпараметр интервала временина самом деле просто указывает, что код анимации добавляется вОчередь потоков пользовательского интерфейса браузерав ожидании времени выполнения. Если в начало очереди добавлены другие задачи, код анимации будет ждать предыдущей задачи.После выполнения задачиВыполните еще раз, и если временной интервал будет слишком коротким (менее 16,7 мс), это приведет к потере кадров, поэтому анимация может не выполняться в соответствии с предустановкой, что снижает удобство работы пользователя.
requestAnimationFrame
использоватьвременной интервал браузера, чтобы поддерживать наилучшую эффективность рисования, это не приведет к чрезмерному рисованию и потреблению производительности, потому что время интервала слишком короткое; это не приведет к зависанию анимации и не будет плавным, потому что время интервала слишком велико, так что различные веб-страницы анимационные эффекты могут иметь одинОбъединитьМеханизм обновления экономит системные ресурсы, повышает производительность системы и улучшает визуальные эффекты.
CSS3 анимация
CSS3
изtransition
иanimation
Можно сказать, что он очень силен при совместном использовании, но есть также места, до которых нельзя добраться щупальцами, например,scrollTop
,Кроме тогоCSS3
Кривые Безье, поддерживаемые анимацией, также ограничены.
Так,CSS3
Используйте то, что вы не можете сделатьrequestAnimationFrame
чтобы решить это.
Ссылаться на
MDN window.requestAnimationFrame