25 марта 2010 г.

JavaScript - Визуальные эффекты своими руками (hand made)

Когда рационально использовать js-фреймворки? Вероятно, когда клиентская сторона web-приложения имеет достаточный объем специфического вычисляемого функционала, когда используется специфический, как правило, действительно сложный пользовательский интерфейс. Иными словами использование фреймворков порождается особенностями конкретной задачей, имеющей достаточный объем для обоснования подключения этого фреймворка.

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

Очень часто заказчик требует на совершенно элементарной страничке реализовать тот или иной эффект... Чтож попробуем самостоятельно реализовать несколько эффектов...

1. Пусть будет некоторый элемент, который будет участвовать в преобразованиях:
<div id="message">Hello WORLD!</div> 
К этому элементу вы можете применять различные стили, позиционировать его совершенно по-разному. Но как правило используются два основных css свойства - display и visibility. Оба свойства влияют на отображение элемента и поэтому создают некоторую вариативность при создании эффектов.

2. Проявление элемента.
Проявление элемента основано, естественно, на изменении css свойства - opacity. Поэтому понадобиться некоторая функция, нивелирующая различия в поддержке этого свойства. В качестве примера приведу самый простой вариант, который при желании можно легко усовершенствовать:
function setOpacity(obj, opacity) {
  obj.style.filter = "alpha(opacity:"+opacity+")";
  obj.style.opacity = opacity/100;
} 
Эта функции получает в качестве аргументов собственно сам объект, к которому будем устанавливаться вышеупомянутое свойство, и значение прозрачности в диапазоне от 0 до 100.
Теперь перейдем непосредственно к функции проявления:
function fadeIn(element) {
  if (element) {
    if (element.style.display=="none") {
           setOpacity(element,  0);
      element.style.display="block";
    }
    for (var i= 0;i<=100;i+=5) {
      (function(){ // Замыкаем обработчик на проявление
        var pos=i;
        setTimeout(function() {
            setOpacity(element, pos) 
          },pos*10);         
       })();
    }
  }
} 
Что происходит в этой функции?
Во-первых, передаваемый элемент проверяется на существование (!=null), если он существует, то проверяется свойство display. Это необходимо чтобы эффект действительно отобразился если элемент изначально скрыт, поэтому мы делаем элемент полностью прозрачным с помощью заготовленной функции setOpacity, а затем действительно отображаем элемент установкой свойства display в значение block (но он остается прозрачным). Нужно отметить, что в основном достаточно присвоить свойству display просто пустую строку (тогда установиться значение по умолчанию) .
Во-вторых, создается цикл на 20 итераций в котором последовательно инициируются функции с вызовом некоторого таймаута с функцией изменения прозрачности элемента. Такое нагромождение функции необходимо чтобы обойти некоторый эффект от замыкания, когда переменная из одной области видимости переопределяется до реального ее использования.
Таким образом, у нас есть функция, которая в действительности отработает за 1 секунду (pos*10) эффект из 20 "кадров". Вызывается функция следующим образом:
var element = document.getDocumentById("message");
fadeIn(element); 
По аналогии можем сделать функцию плавного исчезновения элемента:
function fadeOut(element) {
  if (element) {
    for (var i=100;i>= 0;i-=5) {
      (function(){ // Замыкаем обработчик на проявление
        var pos=i;
        setTimeout(function() {
            setOpacity(element, pos) 
            if (pos<= 0) { // Скрываем элемент при последней итерации
             element.style.display="none"; 
            }
          },1000-(pos*10));         
       })();
    }
  } 
} 
Обе функции далеко не идеальны, но вы же можете их доработать или универсализировать)

3. Эффект сворачивания и разворачивания элемента
Данный эффект является несколько более сложным, так как требует вычисления реальной высоты или ширины элемента, а из-за особенностей браузера - это тема для отдельной статьи. Но если у нас есть это значение, то, собственно, ничего не изменяется. Мы можем использовать тот же механизм последовательного вызова функций по таймауту:
function slide(element) {
  if (element && element.style.display == "none") {
    element.style.height="1px"; // Специально не 0, чтоб IE6 не заикался...
    element.style.display = "block";
    element.style.overflow = "hidden";
    for (var i= 0;i<=100;i+=5) {
      (function(){ // Замыкаем обработчик на разворачивание
        var pos=i;
        setTimeout(function() {
            element.style.height = (pos/100)*dropHeight+1+"px";
          },pos*10);         
       })();
    }
  } else if (element && element.style.display == "block") {
    element.style.overflow = "hidden";
    for (var i=100;i>= 0;i-=5) {
      (function(){ // Замыкаем обработчик на сворачивание
        var pos=i;
        setTimeout(function() {
            element.style.height = (pos/100)*dropHeight+"px";
            if (pos<= 0) { // Скрываем елемент
              element.style.height="0px";
              element.style.display = "none";
            }
          },1000-(pos*10));         
       })();
    }
  }  
} 
В этом случае у нас одна функция, которая в зависимости от значения свойства display, либо разворачивает полностью элемент, либо сворачивает. Принципиальным отличием является использование свойства overflow, благодаря которому inline-содержимое не будет сразу раскрывать родительский элемент, а постепенно проявляться. Сразу отмечу, что переменная dropHeight содержит именно реальную высоту элемента в полностью отображаемом состоянии)

В целом, все функции эффектов строятся на таком принципе, но их можно универсализировать в некоторую функцию аналогичную функции animate из jQuery. Можете экспериментировать!)

Комментариев нет:

Отправить комментарий