Разбиране на анимацията в jQuery
Здравейте. В днешната тема исках да пиша за факта, че механизмът за анимация в jQuery не е ефективен, създава куп таймери, всеки от които работи отделно, което води до прекалено често преначертаване на съдържанието и значително забавя браузъра, и исках да опиша някои техники за писане на "правилна анимация". Докато подготвях примерите, разбрах, чесгреших. Механизмът за анимация на jQuery наистина е неефективен, създава много проблеми, но причините за тези проблеми изобщо не са в създаването на голям брой таймери, а в нещо съвсем различно и изглежда, че съм постигнал забележителни резултати в премахването на тези проблеми.И така, ще говорим за десинхронизиране на движението на анимирани обекти, дори ако всички те са били анимирани от едно извикване на анимация. Нека да разгледаме малък пример за анимиране на голям брой обекти едновременно:
div клас = "контейнер" > div class ="animate" > div > div > script type="text/javascript" > $( function () for ( var i = 0; i '.animate' ).clone().appendTo( '.container' ); > $( '.animate' ).animate( ляво: 800 >, 500); >); скрипт > * Този изходен код беше маркиран с инструмента за открояване на изходния код.
На теория всички тези обекти трябва да се движат синхронно. На практика се получава следната картина:
Ясно е, че тестът е синтетичен, в реална страница родителят на всички тези обекти трябва да бъде преместен, но резултатът е очевиден, анимацията дори в рамките на едно и също извикване на анимация започва и завършва по различно време. Тук би било логично да приемем, че за всеки обект се създава отделен таймер, който го обслужва. Но както казах по-горе, това предположение не е вярно. Като се порових малко в изходните кодове ми стана ясно, че самоедин таймер за анимация на елемент в рамките на едно извикване на анимация. Освен това, за всяка анимация на страницата, направена с jQuery, се използва само един таймер, който се премахва след завършване на последната анимация на страницата и се създава отново, когато нещо трябва да бъде анимирано отново.
Причината за десинхронизацията обаче е близка до множеството таймери, тя се крие във факта, че за всеки елемент началният час на неговата анимация се счита независимо. Ако има много елементи, може да мине доста време между моментите на отчитане на времето за първия и последния елемент. Освен това това време ще бъде колкото по-дълго, толкова по-бавен е javascript двигателят на браузъра, който виждаме на екранната снимка - стойността на десинхронизация за opera е 110 пиксела (екранна снимка в мащаб 1: 2), за chromium 74 пиксела, а за друг, много популярен браузър, десинхронизацията е по-голяма от ширината на тестовото изпълнение, осемстотин пиксела.
В допълнение към разминаването на анимацията на различни обекти, може да има разминаване в анимацията на различни свойства на един и същ обект по същите причини. Това може да съсипе, например, синхронна промяна в подложката и ширината, които като цяло трябва да останат равни. В реална ситуация ръбът на обекта ще скочи.
А сега най-важното. Като се има предвид, че има само един таймер, не е трудно да се коригира началният час на анимацията и след няколко минути бяха направени необходимите корекции за решаване на тези проблеми. Тези корекции се състоят във факта, че началният час на анимацията за всички елементи се разглежда веднъж при влизане във функцията за анимиране. Дори отидох по-далеч, като добавих допълнителен параметър startTime към опциите на функцията за анимиране, който може да приеме персонализирана стойност за начален час на анимация. Това ще позволи произволен брой повиквания към функцията animate да бъдат синхронизирани едно с друго.
В допълнение към синхронизирането, можете да използвате началната времева стойност за още няколко интересни неща: 1) Задайте началния час на анимацията в миналото и започнете анимацията от средата. Удобно е, защото не е необходимо да създавате отделна функция за облекчаване на половината от анимацията. 2) Задайте начален час в бъдещето, позволявайки на бавните браузъри (здравей, IE!) да дъвчат всички обекти. Тук обаче се нуждаем от функция на Изинг, която носи отрицателни времеви отмествания към нулевата координата. стандартните линейни и суинг нямат тези свойства. 3) Направете многопроходна анимация или безкрайна анимация, като зададете началния час на анимацията в бъдещето. За да направите това, ще ви е необходима функция на ising, която може правилно да обработва отрицателно времево отместване. По силата на факта, че стандартната функция за swing ising е изградена на Math.cos, тя удовлетворява това изискване.
Обърнете внимание, за тези, които не са наясно, функциите за облекчаване (облекчаване, на български това вероятно е омекотяване), това са функции, които приемат стойности от 0 до 1, където нула е началният час, 1 е крайният час на анимацията и връщат стойност също от 0 до 1, където 0 е началната стойност на свойството, което се променя, а 1 е краят. Като цяло стойностите на свойствата могат да бъдат извън 0 и 1, а с моя корекция времето също може да бъде по-малко от нула.
Промени, които направих в кода
Текущото време на стъпка е изчислено във функцията jQuery.fx.step, както следва: var t = now(); Добавих друг времеви параметър към функцията и промених дефиницията на време по този начин: var t = time now();
Трябваше да добавя друг параметър startTime към функцията jQuery.fx.custom и да изчисля началното време на анимацията по начин, подобен на предишната функция: this .startTime = startTime now();
В допълнение, вътре в този единствен setInterval беше добавенполучаване на време: var time = now(); и след това предаване на това време на функция от масива, jQuery.timers[], който съдържа функциите jQuery.fx.step.
Във функцията animate обектът optall е разширен с параметъра startTime: optall = jQuery.extend(, optall)
Честно казано, аз лично наистина се нуждая от корекция, ако не открия проблеми, ще я използвам поне в моите проекти. Но това, което ме тревожи, е, че поправката е толкова проста, но разработчиците на jQuery не успяха, въпреки че свършиха много подготвителна работа, за да преместят цялата анимация в един таймер. Може би има логика в това и пропускам нещо? Кой смята, че си струва да се опитвам да прокарам промените си в рамката?
PS И вчера срещнах неработеща прозрачност в Opera 9.2 и последните версии на jQuery. Описание на проблема и решение.
Hardcore conf в C++. Каним само професионалисти.