ugrás a tartalomhoz

Saját tulajdonságok animálása jQuery-vel

Poetro · 2011. Már. 11. (P), 10.24

A következő budapest.js találkozón fej-fej mellett hasonlítjuk össze a népszerű JavaScript keretrendszereket. Ennek kapcsán elkezdtem kutakodni, hogyan lehet saját attribútumokat, illetve tulajdonságokat animálni, illetve CSS-ként kezelni jQuery segítségével.

A jQuery már alapértelmezetten pár egyedi tulajdonság lekérdezését teszi lehetővé. Ezek például az opacity, scrollLeft és scrollRight. Ezeket mint CSS tulajdonság teszi elérhetővé a jQuery, ugyanakkor nem (feltétlen) azok. Azaz például az opacity CSS tulajdonság Internet Explorer 9 előtt változatokban nincsen semmilyen hatással, mégis:

// Be tudjuk állítani:
$(elem).css('opacity', 0.5);
// Le tudjuk kérdezni:
$(elem).css('opacity');

És ez működik Internet Explorerben is. Hogyan? Hát úgy, hogy ezeket az egyedi tulajdonságokat a jQuery egyedileg kezeli.

Ahhoz, hogy hasonló saját „CSS” tulajdonságokat generáljunk, nem kell túl sokat tenni, csak ki kell bővíteni a jQuery cssHooks objektumát. Például:

  $.each(['height', 'width'], function (i, v) {
    var camelCase = $.camelCase('dialog-' + v);
    $.cssHooks[camelCase] = {
      get: function (elem, computed, extra) {
        return $(elem).dialog('option', v);
      },
      set: function (elem, value) {
        var dialog = $(elem),
            position = dialog.dialog('option', 'position');
        dialog.dialog('option', v, parseFloat(value));
        dialog.dialog('option', 'position', position);
      }
    };
  });

Ezzel hozzáadjuk a dialogWidth, és dialogHeight egyedi tulajdonságot a CSS kezelőhöz. Ezután a következő sorok már működni fognak:

$(elem).css('dialogHeight', 300);
$(elem).css('dialog-height', 300); // ugyanaz a hatása mint az előzőnek
$(elem).css('dialogHeight');
$(elem).css('dialog-height'); // ugyanaz a hatása mint az előzőnek

A jQuery css() függvénye a megkapott tulajdonság nevét camelCase formára alakítja; például abból, hogy dialog-height dialogHeight lesz. Ennek megfelelően kell a saját „CSS” tulajdonságunkat is definiálni, ahogy ezt meg is tettük a $.camelCase() függvény segítségével.

Ahhoz, hogy animálni is tudjuk ezeket, már csak egy kicsi lépés van hátra. A jQuery a $.fx.step objektumot használja az animáció aktuális lépésének lefuttatására. Alapértelmezetten minden tulajdonságra a $.fx.step._default() függvény fut le. Hogy saját függvényt tudjunk lefuttatni, egyszerűen hozzá kell adni a $.fx.step objektumhoz a saját kezelőnket.

  $.each(['height', 'width'], function (i, v) {
    var camelCase = $.camelCase('dialog-' + v);
    $.fx.step[camelCase] = function (fx) {
      jQuery.style( fx.elem, fx.prop, fx.now );
    };
  });

A fenti kód a $.fx.step objektumot kibővíti egy dialogHeight és egy dialogWidth tulajdonsággal, és ezek után, amikor az animate segítségével akarjuk módosítani a tulajdonságot, akkor már a $.cssHooks-ban definiált függvényeket fogja használni.

$(elem).animate({
    dialogHeight: 200,
    dialogWidth: 300
  }, {
    duration: 500
  });

Összefoglalás

Érdekesnek, és igencsak hasznosnak találtam ezen jQuery objektumok és nem igazán dokumentált függvények használatát. Érdemes lehet ezek után más gyöngyszemek után kutatni a jQuery forráskódjában.

Ezek után bármilyen egyedi tulajdonságot tudunk majd animálni, valamint CSS tulajdonságként kezelni. Sajnos a css és az animate ezen tulajdonságai csak jQuery 1.4.3 óta érhetők el, a korábbi változatokban az opacity kezelése például be volt drótozva a kódba.

 
1

És ez mire jó?

nemeseri · 2011. Már. 13. (V), 00.14
Az opacitynél a jQuery nyilván maszkolja az IE specifikus filtereket.

És mire jó, hogy saját tulajdonságot animálsz? Az animate-el eddig is tudtál bármit animálni, akár összefűzve több dolgot. Mondasz egy példát, h miért jó ez?
Mintha kimaradt volna a cikkből a mondanivaló. :P
2

CSS3, widget, HTML tulajdonság

Poetro · 2011. Már. 13. (V), 01.50
Például rengeteg CSS3 tulajdonság van, aminek nem lenne egyértelmű, hogyan animálod, mégis megoldható. Például teszem az, animálni akarod a CSS3 gradient tulajdonságát egy elemnek. Mondjuk mozgatod a gradiens pozícióit, vagy színeit és a többi. Ezen kívül például a jQuery UI widgetjei közül a slider-nek a pontját akarod animálni de függetlenül az aktuális CSS tulajdonságaitól, pusztán a beépített API-ra építve, akkor azt megteheted. Ez azért is hasznos, mert az objektum megfelelő tulajdonsága így frissül is az animáció során, nem csak úgy látszik, mintha ott lenne.
jQuery(function ($) {
  $.cssHooks.sliderValue = {
    get: function (elem) {
      return $(elem).slider('option', 'value');
    },
    set: function (elem, value) {
      $(elem).slider('option', 'value', parseFloat(value));
    }
  };
  $.fx.step.sliderValue = function (fx) {
    jQuery.style( fx.elem, fx.prop, fx.now );
  };
  $('#slider').slider().animate({sliderValue: 50}, 5000);
});
Megtekinthető.

Másik példa HTML tulajdonság animálására:
  <input type="number" min="0" max="100" step="2" value="0">
  <input type="range" min="0" max="100" step="2" value="0">
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
  <script type="text/javascript">
    jQuery(function ($) {
      $.cssHooks.numberValue = {
        get: function (elem) {
          return elem.value;
        },
        set: function (elem, value) {
          elem.value = Math.round(parseFloat(value) / elem.step) * elem.step;
        }
      };
      $.fx.step.numberValue = function (fx) {
        jQuery.style( fx.elem, fx.prop, fx.now );
      };
      $('input[type=number], input[type=range]').animate({numberValue: 50}, 2000);
    });
  </script>
Szintén megtekinthető.
3

Király, köszi! :)

nemeseri · 2011. Már. 13. (V), 15.01
Király, köszi! :)
4

A második példa nálam nem

bugadani · 2011. Már. 13. (V), 16.18
A második példa nálam nem működik, mindkét szövegmezőben NaN jelenik meg (Firefox 4.0 RC).
Egyébként érdekes cikk, köszönet érte!
5

Firefox

Poetro · 2011. Már. 13. (V), 17.00
Úgy tűnik a Firefox kicsit furcsán kezeli a HTML5 elemeket, ugyanis azok nem szövegmezők, hanem number illetve range mezők. Ennek megfelelően a step mező teljesen valid. Viszont a Firefox nem fér hozzá valamiért ebben az esetben a step attribútumhoz elem.step formában.
Ennek megfelelően frissítettem a kódot:
jQuery(function ($) {
  $.cssHooks.numberValue = {
    get: function (elem) {
      return parseFloat(elem.value);
    },
    set: function (elem, value) {
      var step = parseFloat($(elem).attr('step'));
      elem.value = Math.round(parseFloat(value) / step) * step;
    }
  };
  $.fx.step.numberValue = function (fx) {
    jQuery.style( fx.elem, fx.prop, fx.now );
  };
  $('input[type=number], input[type=range]').animate({numberValue: 50}, 5000);
});
Ami megtekinthető.