Создание анимации с использованием javascript. Более сложный пример: перемещение и изменение размера. Определение целевых элементов

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

WOW.js – это маленькая библиотека, которая позволяет включать анимацию на определенном этапе прокрутки страницы. Весит очень мало, и к тому же полностью самостоятельна – то есть нет необходимости подключать jQuery или других монстров.

Animate.CSS – скрипт, который непосредственно отвечает за саму анимацию. По сути wow.js берет анимации именно из этой штуки.

Как скачать и подключить.

1 шаг. Для работы нам понадобиться скачать скрипты wow.js и animate.css

Файл animate.css – библиотека, в которой прописаны стили для анимации элементов на странице. Для того, чтобы визуально оценить и выбрать вид анимации, обычно, я использую страничку ресурса http://daneden.github.io/animate.css/

2 шаг. Подключаем скрипты

Тег script необходимо всегда добавлять в конец body. Это делается для быстроты загрузки страницы. Каждый раз, когда браузер доходит до тега script, загрузка и рендеринг всего сайта замораживается, пока скрипт не будет загружен. От этого зачастую мы видим сайты, которые долгое время просто белый лист. А так же, если скрипт размещён в конце body, у вас есть гарантия что body - ready и скрипт точно отработает.

Шаг 3. Необходимо инициализировать скрипт добавив вот такой код, сразу после его подключения:

new WOW().init();

На этом подключение заканчивается, и настает пора второго этапа.

Использование WOW.js

Шаг 1. Выбираем элемент, который хотим анимировать и добавляем ему класс class="wow" . В коде ниже, я показал это на примере картинки:

Шаг 2. Выбираем анимацию, и добавляем её дополнительным классом к нашей картинке:

Шаг 3 (не обязательно). Добавляем настройки для анимации если надо, при помощи специальных data-атрибутов:

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

Настройки WOW.js анимации через атрибуты

data-wow-duration – указываем время проигрывания анимации

data-wow-delay – ставим задержку перед проигрыванием анимации

data-wow-offset – включение анимации, когда элемент проходит определнное количество пикселей от низа экрана

data-wow-iteration – количество повторов анимации

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

Аннотация: Простой пример: метод угасания желтого цвета. Анимация с помощью библиотек JavaScript. Более сложный пример: перемещение и изменение размера. Переходы CSS.

Принцип в основе угасания состоит в том, что задается желтый цвет фона элемента угасания, а затем, за некоторую последовательность шагов его цвет возвращается к исходному. Поэтому, если исходный цвет фона был красный, то затем цвет задается желтым, затем оранжево-желтым, затем оранжевым, затем красно-оранжевым, и затем красным. Число использованных шагов определяет, насколько плавно происходит изменение цвета, а время между шагами определяет, как долго продолжается изменение цвета. При изменении цвета можно использовать полезный факт из CSS : цвет можно определить как тройку обычных чисел или как шестнадцатеричную строку. Поэтому #FF0000 (красный цвет) можно определить также как rgb(255,0,0) . Изменение от желтого цвета до красного за пять шагов означает, поэтому, переход от rgb(255,255,0) (желтый) к rgb(255,0,0) за пять следующих шагов:

rgb(255,255,0) rgb(255,192,0) rgb(255,128,0) rgb(255,64,0) rgb(255,0,0)

Более сложный пример: перемещение и изменение размера

Хотя метод угасания желтого цвета демонстрирует анимацию, он несколько скучен. Когда большинство людей представляют себе анимацию, они обычно имеют в виду движение. Интересный прием предупреждения пользователя о том, что что-то произошло, не прерывая его рабочего процесса , состоит в немодальном сообщении. Вместо вывода диалогового окна alert() , которое требует от пользователя щелчка на OK , прежде чем он сможет продолжить, поместите сообщение просто в плавающий div на странице, который ненавязчиво остается там, пока не получит подтверждение. Второй достаточно интересной вещью затем может быть предоставление пользователю возможности вернуться к сообщению, для которого он подтвердил желание прочитать его еще раз. Поэтому давайте реализуем плавающее сообщение, которое, после щелчка на нем, "схлопывается" в угол экрана, и затем по щелчку может быть снова восстановлено. Вы можете посмотреть небольшую демонстрацию такого "схлопывающегося сообщения" (http://dev.opera.com/articles/view/javascript-animation/moving_messages_jq.html), чтобы понять общую идею.

Если вы делаете какую-то серьезную анимационную работу, или какую-то серьезную работу с JavaScript, почти всегда стоит использовать библиотеку JavaScript. Это позволит создать требуемое представление для пользователей, не беспокоясь о математических тонкостях, требуемых для выполнения анимации. (Познакомившись с представленным выше первым примером, вы знаете теперь, как выполнить математические вычисления и как использовать setInterval , но вы сохраните время и собственные силы, используя готовые решения.)

Приведенный выше демонстрационный пример использует для работы библиотеку jQuery (http://jquery.com/), но как упоминалось, большинство библиотек предоставляют достаточно похожую концепцию анимации, и поэтому вы сможете реализовать принципиальную часть, используя предпочитаемую библиотеку. По существу, необходимо сделать следующее:

  • Показать плавающее сообщение в центре экрана
  • Когда на нем производится щелчок:
  • Переместить его горизонтальную позицию в крайнее правое положение
  • Переместить его вертикальную позицию вверх
  • Задать его ширину равной 20px
  • Задать его высоту равной 20px
  • Сделать его плотность равной 20%, так что оно становится почти прозрачно и скрыть в нем текст
  • Когда выполняется щелчок на этой "мини"-версии сообщения, восстановить его в центре экрана (т.е., обратное тому, что мы делали для его сжатия) и чтобы пользователь получил четкую картину того, что произошло с его сообщением, переход от полноразмерного сообщения к мини-сообщению должен быть анимирован (чтобы они видели, что сообщение "сжалось" в угол окна).
  • Выполнить анимацию с помощью jQuery очень легко: используйте просто функцию . animate () и предоставьте желательный конечный результат анимации (и как долго она должна выполняться):

    $(ourObject).animate({ width: "20px", height: "20px", top: "20px", right: "20px", marginRight: "0px", opacity: "0.2" }, 300);

    Функция получает ourObject и, за 300 миллисекунд, заменяет его ширину и высоту на 20px, его верхнюю и правую позиции на 20px, его свойство стиля margin-right на 0px, и его плотность (в браузерах, которые поддерживают плотность изображения) на 20%. Затем это просто вопрос программирования в стиле

    В финальной части будут описаны различные обратные вызовы (callback-функции), используемые для выполнения функций в зависимости от прогресса анимации. Почти в каждом примере в предыдущих статьях использовались свойства CSS, чтобы показать, как работают различные методы и параметры. Возможно, у вас могло создаться впечатление, что библиотека Anime.js больше подходит для анимации CSS-свойств. В этом уроке вы узнаете, что её также можно использовать для анимации SVG-файлов.

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

    Callback-функции

    Обратные вызовы используются для выполнения функций, основанных на прогрессе анимации. В Anime.js существует 4 функции обратного вызова: begin , run , update и comlete . Каждая из них запускается в определённое время и принимает объект анимации в качестве своего аргумента.

    Функция begin() вызывается, когда анимация начинается. Это значит, что если у анимации есть параметр delay со значением 800 миллисекунд, то begin() будет вызвана только через 800 миллисекунд. Можно проверить, запустилась анимация или нет, используя функцию animationName.begin , которая возвращает true (запустилась) или false (не запустилась).

    Run используется для выполнения функции в каждом кадре после запуска анимации. Если нужно выполнить функцию в каждом кадре с самого начала анимации, независимо от параметра delay , то используйте callback-функцию update .

    Callback-функция complete похожа на begin , только вызывается она после окончания. Чтобы проверить, завершилась анимация или нет, используйте animationName.complete , как и в случае с begin .

    Callback-функцию update мы использовали ещё в для обновления количества сканированных и заражённых файлов. В этой статье мы дополним пример со сканированием, и вы увидите, как работают все callback-функции.

    Var filesScanned = { count: 0, infected: 0 }; var scanCount = document.querySelector(".scan-count"); var infected = document.querySelector(".infected-count"); var scanning = anime({ targets: filesScanned, autoplay: false, count: 100, infected: 8, delay: 1000, duration: 2000, easing: "linear", round: 1, update: function(anim) { if (anim.currentTime < 1000) { document.querySelector(".update-cb").innerHTML = "Creating an Index..."; } }, begin: function() { document.querySelector(".begin-cb").innerHTML = "Starting the Scan..."; }, run: function() { scanCount.innerHTML = filesScanned.count; infected.innerHTML = filesScanned.infected; }, complete: function() { document.querySelector(".complete-cb").innerHTML = "Scan Complete..."; } });

    В примере выше намеренно была добавлена задержка анимации, чтобы можно было заметить разницу во времени выполнения разных функций обратного вызова. Callback-функция update начинает выполняться сразу после создания объекта анимации.

    Сама анимация начинается с задержкой в 1000 миллисекунд, и именно в этот момент срабатывает функция begin , которая показывает пользователю сообщение «Starting the Scan…». В то же время run начинает выполняться и обновлять числовые значения объекта после каждого кадра. После окончания анимации функция обратного вызова complete отображает сообщение «Scan Complete…».

    Функции плавности

    Функции плавности используются для контроля перехода начального значения свойства в конечное. Эти функции можно определить с помощью параметра easing , который может принимать значения как в виде строк, так и в виде пользовательских координат кривых Безье (в виде массива).

    Существует 31 встроенная функция плавности. Одна из них называется linear , остальные 30 состоят из разных вариаций easeIn , easeOut и easeInOut . Класc elastic определяет три функции плавности: easeInElastic , easeOutElastic и easeInOutElastic . Вы можете управлять ими с помощью параметра elasticity . Значение этого параметра может находиться только в диапазоне от 0 до 1000.

    Использование easeIn ускоряет изменение значения, начиная с нуля. Это значит, что изменяться оно будет сначала медленно, а в конце - быстро. Скорость изменения в начале равна нулю, а в конце - 1000.

    Функция easeOut замедляет изменение значения, начиная с максимальной скорости.

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

    С помощью anime.easings можно создавать собственные функции плавности. Ниже приведён пример создания пользовательских функций плавности:

    Anime.easings["tanCube"] = function(t) { return Math.pow(Math.tan(t * Math.PI / 4), 3); } anime.easings["tanSqr"] = function(t) { return Math.pow(Math.tan(t * Math.PI / 4), 2); } var tanCubeSequence = anime({ targets: ".tan-cube", translateX: "75vw", duration: 2000, easing: "tanCube", autoplay: false }); var tanSqrSequence = anime({ targets: ".tan-sqr", translateX: "75vw", duration: 2000, easing: "tanSqr", autoplay: false });

    Анимации на основе SVG-файлов

    Во всех связанных с движением анимациях, которые были созданы до этого момента, целевые элементы перемещались по прямой линии. В Anime.js можно перемещать элементы по сложным SVG-контурам с большим количеством кривых с возможностью контроля положения и угла анимируемых элементов на контуре. Чтобы переместить элемент по оси X на контуре, используйте path("x") . Подобным образом элементы можно перемещать по оси Y, используя path("y") .

    Если контур не представлен в виде прямой линии, то он почти всегда будет формировать угол относительно основной горизонтальной линии. При вращении любого некруглого элемента анимации общая картинка будет выглядеть более естественно, если элемент будет перемещаться по углу контура. Это можно сделать, установив значение свойства rotate равным path("angle") . Ниже представлен пример кода, который анимирует четыре элемента с разными значениями плавности по SVG-контуру:

    Var path = anime.path("path"); var easings = ["linear", "easeInCubic", "easeOutCubic", "easeInOutCubic"]; var motionPath = anime({ targets: ".square", translateX: path("x"), translateY: path("y"), rotate: path("angle"), easing: function (el, i) { return easings[i]; }, duration: 10000, loop: true });

    Во вставке ниже видно, что красный квадрат с функцией плавности easeInCubic двигается медленнее всех в начале, но быстрее всех в конце. Похожая ситуация и в случае с оранжевым квадратом - быстрее всего он двигается в начале, но медленнее всех в конце.

    Существует возможность анимирования преобразований разных SVG-форм из одной в другую с помощью Anime.js. Единственным условием для преобразования фигур является наличие равного количества опорных точек. Это значит, что треугольники можно преобразовать только в другие треугольники, четырёхугольники - в четырёхугольники и так далее. Попытка преобразования элементов с неравным количеством опорных точек приведёт к резкому изменению формы. Ниже представлен пример трансформаций треугольника:

    Var morphing = anime({ targets: "polygon", points: [ { value: "143 31 21 196 286 223" }, { value: "243 31 21 196 286 223" }, { value: "243 31 121 196 286 223" }, { value: "243 31 121 196 386 223" }, { value: "543 31 121 196 386 223" } ], easing: "linear", duration: 4000, direction: "alternate", loop: true });

    Одним из наиболее интересных эффектов Anime.js является возможность создания линейных рисунков. Всё, что нужно сделать - предоставить библиотеке контур, который вы хотите использовать для линейного рисунка; предоставить другие параметры, с помощью которых контролируется продолжительность, задержка и плавность. В примере ниже использовалась функция обратного вызова complete , чтобы сделать заливку рисунка якоря из Font Awesome жёлтым цветом.

    Var lineDrawing = anime({ targets: "path", strokeDashoffset: , easing: "easeInOutCubic", duration: 4000, complete: function(anim) { document.querySelector("path").setAttribute("fill", "yellow"); } });

    Используя знания всех изученных понятий, вы сможете создавать более сложные линейные изображения с гораздо лучшим контролем над тем, как они рисуются. Ниже приводится пример отрисовки имени с помощью SVG:

    Var letterTime = 2000; var lineDrawing = anime({ targets: "path", strokeDashoffset: , easing: "easeInOutCubic", duration: letterTime, delay: function(el, i) { return letterTime * i; }, begin: function(anim) { var letters = document.querySelectorAll("path"), i; for (i = 0; i < letters.length; ++i) { letters[i].setAttribute("stroke", "black"); letters[i].setAttribute("fill", "none"); } }, update: function(anim) { if (anim.currentTime >= letterTime) { document.querySelector(".letter-m").setAttribute("fill", "#e91e63"); } if (anim.currentTime >= 2 * letterTime) { document.querySelector(".letter-o").setAttribute("fill", "#3F51B5"); } if (anim.currentTime >= 3 * letterTime) { document.querySelector(".letter-n").setAttribute("fill", "#8BC34A"); } if (anim.currentTime >= 4 * letterTime) { document.querySelector(".letter-t").setAttribute("fill", "#FF5722"); } if (anim.currentTime >= 5 * letterTime) { document.querySelector(".letter-y").setAttribute("fill", "#795548"); } }, autoplay: false });

    Есть ошибочное мнение среди веб-разработчиков, что CSS анимация — единственный производительный способ анимирования в сети. Этот миф принудил много разработчиков отказаться от основанной на JavaScript анимации в целом. Таким образом:

  • Вынудили себя управлять сложным взаимодействием UI в таблицах стилей
  • Блокировали себя в поддержке Internet Explorer 8 и 9
  • Воздерживаются от возможности построения физики движения, которая возможна только в JavaScript
  • Проверка в реальных условиях: основанная на JavaScript анимация так же быстра, как и анимация, основанная на CSS - иногда еще быстрее. Анимация CSS имеет преимущество, как правило, только по сравнению с $.animate() jQuery, которая является, по сути, очень медленным. Однако библиотеки для анимации JavaScript, которые обходят jQuery, показывают невероятную производительность, избегая манипулирования DOM насколько это возможно. Эти библиотеки могут быть до 20 раз быстрее, чем jQuery.

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

    Почему JavaScript?

    CSS анимации удобны, когда вы должны сделать переходы свойств в свои таблицы стилей. Плюс, они показывают фантастическую производительность из коробки - без добавления библиотеки на страницу. Однако, когда вы используете переходы CSS, чтобы привести в действие богатый проект движения (подобное вы увидите в последних версиях IOS и Android), они становятся слишком трудными в управлении, или их функции просто сыпятся ошибками.

    В конечном счете, CSS анимации ограничивают вас определенной спецификацией. В JavaScript, по самой природе любого языка программирования, у вас есть бесконечное количество логического контроля. Механизмы JavaScript анимации усиливают этот факт, чтобы обеспечить новые функции, которые позволяют вам осуществлять некоторые очень полезные приемы:

    Примечание: Если вас интересует тема производительности, то можете почитать Джулиана Шапиро “CSS vs. S Animation: что быстрее?” и Джека Дойла: “Разрушение мифа: CSS Animations vs. JavaScript” . Для демо производительности, обратитесь к панели производительности в документации Velocity и демо GSAP «Библиотека сравнения скорости».

    Velocity и GSAP

    Две самых популярных библиотеки для JavaScript анимации — Velocity.js и GSAP . Обе работают с и без jQuery. При использовании этих библиотек совместно с jQuery, нет никакого ухудшения производительности, потому что они полностью обходят стек jQuery анимации.

    Если jQuery присутствует на вашей странице, вы можете использовать Velocity и GSAP точно так же как и $.animate() jQuery. Например, $element.animate({ opacity: 0.5 }); просто становится $element.velocity({ opacity: 0.5 }) .

    Эти две библиотеки также работают, когда jQuery не присутствует на странице. Это означает, что вместо того, чтобы объединить вызов анимации в цепочку в элемент jQuery объекта - как просто показано - вы передали бы целевой элемент(ы) к вызову анимации:

    1
    2
    3
    4
    5

    /* Работа без jQuery */

    Velocity(element, { opacity: 0.5 } , 1000 ) ; // Velocity

    TweenMax.to (element, 1 , { opacity: 0.5 } ) ; // GSAP

    Как видно Velocity сохраняет тот же синтаксис что и $.animate () jQuery, даже когда это используется без jQuery; просто сместите все параметры вправо на одну позицию, чтобы создать место для передачи в предназначенных элементах в первой позиции.

    GSAP, напротив, использует объектно-ориентированный API проект, а также удобные статические методы. Так, вы можете получить полный контроль над анимациями.

    В обоих случаях вы больше не анимируете объект элемента jQuery ,а скорее необработанный DOM узел. Как напоминание, вы получаете доступ к необработанным DOM узлам при помощи document.getElementByID , document.getElementsByTagName , document.getElementsByClassName или document.querySelectorAll (который работает так же к селекторному механизму jQuery). Мы будем работать с этими функциями в следующем разделе.

    Работа без jQuery

    (Примечание: если вы нуждаетесь в базовом учебнике для начинающих в работе с $.animate() jQuery, обратитесь к первым нескольким разделам в документации Velocity .)

    Давайте исследовать querySelectorAll потому что, вероятно, вы будете использовать именно это оружие при выборе элементов без jQuery:

    Как показано вы просто передаете querySelectorAll CSS селектор (те же селекторы, которые Вы использовали бы в своих таблицах стилей), и он возвратит все соответствующие элементы в массив. Следовательно, вы можете сделать это:

    1
    2
    3
    4
    5

    /* Получите все элементы div. */
    var divs = document.querySelectorAll ("div" ) ;
    /* Анимируйте все div сразу. */
    Velocity(divs, { opacity: 0.5 } , 1000 ) ; // Velocity
    TweenMax.to (divs, 1 , { opacity: 0.5 } ) ; // GSAP

    Поскольку мы больше не присоединяем анимации к объектам элемента jQuery, вы можете задаться вопросом, как мы можем объединить анимации в цепочку:

    В Velocity вы просто вызываете анимации одну за другой:

    /* Эти анимации автоматически становятся цепочкой. */
    Velocity(element, { opacity: 0.5 } , 1000 ) ;
    Velocity(element, { opacity: 1 } , 1000 ) ;

    У анимации этого пути нет недостатка производительности (вы кэшируете элемент, анимируемый к переменной, вместо того, чтобы неоднократно делать querySelectorAll выборку для того же элемента).

    (Подсказка: С пакетом Velocity UI вы можете создать свои собственные анимации мультивызова и дать им пользовательские имена, которые сможете использовать в дальнейшем как первый параметр Velocity. См. UI Pack документацию Velocity для получения дополнительной информации.)

    Velocity вызов-обработки-за-один-раз, обладает огромным преимуществом: если вы будете использовать promises со своими Velocity анимациями, то каждый Velocity вызов возвратит действенный promise объект. Можно узнать больше о работе с promises в статье Джейка Арчибальда . Они невероятно сильны.

    В случае GSAP его выразительный объектно-ориентированный API позволяет вам помещать свои анимации во временную шкалу, давая вам контроль над планированием и синхронизацией. вы не ограничены цепочечными анимациями; можно вложить временные шкалы, заставить анимации наложиться, и т.д.:

    Удивительность JavaScript: Workflow

    Анимация является по сути экспериментальным процессом, в котором необходимо играть с timing и easing для получения правильного ощущения, в котором нуждается приложение. Конечно, даже если вы будете считать дизайн прекрасным, клиент будет часто запрашивать нетривиальные изменения. В этих ситуациях управляемый workflow становится важным.

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

    Однако базовый недостаток API ключевых кадров — в том, что вы должны определить разделы в процентах, который не интуитивен. Например:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    @ keyframes myAnimation {
    0 % {
    opacity: 0 ;
    transform: scale(0 , 0 ) ;
    }
    25 % {
    opacity: 1 ;
    transform: scale(1 , 1 ) ;
    }
    50 % {
    transform: translate(100px, 0 ) ;
    }
    100 % {
    transform: translate(100px, 100px) ;
    }
    }

    #box {
    animation: myAnimation 2.75s;
    }

    Что происходит, если клиент просит, чтобы вы сделали translateX анимацию на секунду длиннее? Это требует восстановления математики и изменения всех (или большинства) процентов.

    Этот материал посвящён анимации на HTML страницах, о производительности анимации, перспективности использования, а так же анимации в HTML5 мобильных приложениях и играх.

    Javascript анимация

    Первым делом начнём с рассмотрения JS анимации на HTML странице. Анимация на яваскрипте может проводиться либо с setInterval, с помощью которой можно задать статично кадры в секунду, либо с помощью обычной функции которая в конце вызывает саму себя ну или с window.requestAnimationFrame.

    Вот простейшая логика работы анимации в JS:

    var el=document.getElementById("elem");
    mar=10; //статичные начальные данные
    //цикл начинается
    mar=mar+1;
    el.style.marginLeft=mar+"px";
    //цикл заканчивается

    Прелесть JS в том что можно удобным способом расширить нативный инструментарий и использовать например анимацию на jQuery или использовать Velocity . Это существенно ускоряет производительность. Однако в частности Velocity использует JS не совсем для анимации, так ака само анимирование производиться там в CSS о котором речь пойдёт ниже.

    SVG анимация

    Нельзя не упомянуть о SVG анимации. Сама она очень хороша, но в мобильных браузерах она не работает. Вернее работает только SMIL на Андроид 3.0-выше. Как бы неприятно было это говорить сам SVG работает в методе WebView, но всё что связано с анимацией в этом тэге увы...

    Везде где она работает - она показывает хорошую производительность. Убедитесь сами.



    В продолжение темы:
    Windows

    Часть вторая : "Важнейшие характеристики каждого семейства процессоров Intel Core i3/i5/i7. Какие из этих чипов представляют особый интерес" Введение Сначала мы приведём...

    Новые статьи
    /
    Популярные