Zmiany w jQuery 1.4

Zespół jQuery z Johnem Resigiem na czele wypuścił właśnie wersję 1.4 frameworka jQuery, który lubimy i cenimy (choć nie jest doskonały). W związku z tym powstała specjalna strona 14 dni jQuery, gdzie codziennie będzie pojawiać się jakaś niespodzianka związana z premierą nowego jQuery. Przyjrzyjmy się zmianom.

Lepsza dokumentacja API

Przede wszystkim warto zauważyć metamorfozę strony z dokumentacją. Starą docs.jquery.com (pozostanie online jeszcze przez jakiś tydzień) zastąpiła nowa api.jquery.com. Od tej pory wszystkie funkcje jQuery są wylistowane na stronie głównej – nie trzeba szukać i domyślać się, do której kategorii należy to, czego szukamy. Całość działa na WordPressie i co zauważyli twórcy – odbiło się to na szybkości działania. Z większych ciekawostek warto nadmienić, że od teraz każda funkcjonalność posiada informację, kiedy została wprowadzona do jQuery – licząc od wersji 1.0. Oprócz tego dostępny jest też dump API w XML.

Co nowego?

Wersja 1.4 wygląda teraz tak, jeśli chodzi o rozmiar:

Przyspieszyły funkcje empty(), remove(), html(), css(), attr(), addClass(), removeClass(), hasClass(), append(), prepend(), before() oraz after().

Mamy wreszcie settery w funkcjach takich jak ..css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass() oraz .toggleClass(). Czym są settery? Otóż to funkcje, które możemy przekazać jako argument. Muszą one zwracać wartość, która zostanie bezpośrednio zaaplikowana do jednej z powyższych metod.

$('.inner').wrap(function() {
	return '<div class="' + $(this).text() + '" />';
});

Powyższy kawałek kodu opakuje każdy element o klasie inner w div z klasą o nazwie zwróconej przez text, uruchomionej na każdym elemencie .inner.

Ponadto wybrano funkcje, które oferują naszym setterom także aktualne wartości, w zależności od kontekstu. Są nimi .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .offset(), .addClass(), .removeClass() oraz .toggleClass(). Działa to tak, że ta wartość jest dostępna jako drugi argument przekazywanej przez nas funkcji:

$('a').html(function(i, html){
	return html.replace(/&/gi,'&');
});

W tym wypadku pod zmienną html będziemy mieli nic innego, jakby wynik funkcji $(this).html() wywołanej na każdym znalezionym tagu a.

Zmienił się trochę obiekt ajax. Lepsze serializowanie parametrów:

{foo: ["bar", "baz"]}

zamieni się w

foo[]=bar&foo[]=baz

W poprzedniej wersji byłoby to tak:

foo=bar&foo=baz

Jeśli jednak chcemy używać nadal starego sposóbu serializowania, można go uruchomić na trzy sposoby:

// włącza tradycyjny sposób serializowania dla wszystkich operacji ajaxowych
jQuery.ajaxSettings.traditional = true;
 
// włącza tradycyjny sposób serializowania dla pojedynczej operacji
jQuery.param( stuff, true );
 
// włącza tradycyjny sposób serializowania dla pojedynczego requestu ajaxowego
$.ajax({ data: stuff, traditional: true });

Poza tym, kiedy request ajaxowy zwraca application/json, parametr dataType jest równy JSON. Jeśli jest to text/javascript lub application/x-javascript dataType przyjmuje script i kod jest automatycznie wykonywany.

Co więcej, jQuery ignoruje w zapytaniach ajaxowych flagę Last-Modified i za każdym razem dostarcza aktualną, zwróconą wartość żądania, nie sugerując się cache przeglądarki. Można zmienić to zachowanie, ustawiając ifModified: true. jQuery wspiera także nagłówek If-None-Match.

JSON!

jQuery używa teraz natywnego parsowania danych JSON, jeśli tylko takie wspierane jest przez przeglądarkę. Nasze dane są też walidowane, więc coś takiego nie przejdzie:

{foo: "bar"}

HTML5

Co ciekawe, nowe typy formularzy z HTML5, jak np.:

<input type="datetime-local" />

będą uwzględniane przy serializowaniu danych formularzy.

Ajax context

Oprócz tego, przy zapytaniach ajaxowych można teraz ustalić kontekst, w jakim mamy odpalić metodę success:

$.ajax({ 
	url: "test.html", 
	context: document.body,
	success: function(){
		$(this).addClass("done");
	}
});

W ten sposób, po wykonaniu się zapytania, tagowi body ustawiona zostanie klasa done.

$.ajax({ 
	url: "test.html", 
	context: $("#foobar"),
	success: function(data){
		$(this).html(data);
	}
});

Analogicznie, po tej operacji, jeśli wszystko się powiedzie, elementowi #foobar zostanie automatycznie wstawiony, powiedzmy, kawałek HTMLa, który pobraliśmy sobie z pliku test.html, i który jest dostępny pod zmienną data.

Co ważne, funkcja success przyjmuje teraz 3 argumenty:

$.ajax({ 
	url: "test.html", 
	context: $("#foobar"),
	success: function(data, status, xhr){
		$(this).html(data);
	}
});

Pod pierwszym mamy zwróconą przez request wartość, pod drugim status operacji, a pod trzecim obiekt ajax (to co jest pod $.ajax).

Warto też zwrócić uwagę, że tym razem jQuery nie ignoruje contentType w zapytaniach ajaxowych. Jest on teraz zawsze wysyłany. Pojawiła się tez możliwość ustawienia callback‚a dla JSONP – poprzez atrybut jsonpCallback , natomiast zapytania cross-domainowe są teraz o wiele bardziej wydajne.

Szybkość tworzenia nowych obiektów

Zapomnij natychmiast o czymś podobnym:

var obj = $("<div />");
obj.css("background", "#ddd").html("something").click(function() { alert("foobar!"); }).appendTo("body");

Można to teraz zrobić o wiele bardziej kompleksowo:

var obj = $("<div />", {
	css: {
		background: "#ddd"
	},
	html: "something",
	click: function() { alert("foobar!"); }
}).appendTo("body");

.eq(-N), .get(-N)

Od teraz w funkcjach eq i get możemy użyć ujemnych wartości:

$("div").eq(-2);
$("div").get(-2);

W ten sposób wybierzemy elementy drugie od końca.

first() i last()

Jeśli mowa o końcu, developerzy dodali funkcję last, która zwróci nam ostatni element oraz first, analogicznie zwracającą pierwszy.

toArray()

Z nowych rzeczy pojawiła się także metoda toArray, która zamienia wszystko… w tablicę:

var arr = $('a').toArray();
typeof arr; // object
arr // [<a id="foo">, <a id="bar">]
arr[1].html("ustawiamy wartość html dla drugiego z kolei pobranego linka");

jQuery().ready() – nie działa!

Kod $().ready() przestał być wspierany. Zamiast tego użyj:

$(document).ready()

lub

$(function(){})

Wszystko dlatego, że $() zwraca teraz pustą tablicę.

typeof $() // object
$().length // 0

$(„tag”)

Developerzy zarzekają się dumnie, że powyższa konstrukcja znacznie przyspieszyła. Przekonajcie się sami! Co więcej, warto dodać, że przyspieszył również selektor #id tag np.:

$("#foobar div");

toggleClass

toggleClass() może ustawić teraz kilka klas naraz:

$("div").toggleClass("current active");

Efekty

Z fajnych rzeczy dodano także obsługę techniki per-property easing:

$("#clickme").click(function() {
	$("div").animate({
	width: ["+=200px", "swing"],
	height: ["+=50px", "linear"],
	}, 2000, function() {
      		$(this).after("<div>Ukończono animację!</div>");
  	});
});

Co to znaczy? Ano to, że możemy użyć różnych stylów animacji (swing, linear) dla różnych właściwości CSS (powyżej, co jasne, są to: width, height) jednocześnie.

$.proxy()

Co robi nowa funkcja proxy()? Otóż zmienia ona scope dla danej funkcji, co oznacza w gruncie rzeczy to, że łatwo możemy ustawić, co chcemy pod zmienną this:

var obj = {
	name: "John",
	test: function() {
		alert(this.name);
	}
};

$("#foobar").click($.proxy(obj, "test"));

// To także działa:
// $("#foobar").click($.proxy( obj.test, obj ));

W ten sposób funkcja test odwołuje się do obiektu obj poprzez this, stąd tez dostępna własność this.name. Porównajcie sobie to z czymś takim:

$("#foobar").click(function() {
	alert(typeof this.name);
});

Wyświetlone zostanie undefined, ponieważ w tym wypadku skrypt będzie szukal name w obiekcie jQuery.

bind i zdarzenia

W wersji 1.4 funkcja bind przyjmuje wiele zdarzeń:

$("#foobar").bind({	
	click:  function() {},
	mouseover: function() {}
});

Jeśli mowa o nich to wprowadzono także zdarzenia focusin i focusout. Czym różnią się one od focus i blur? Są to bowiem zdarzenia bąbelkowe i na tym polega cały myk. Zainteresowanym polecam przeczytać na temat różnic na temat bubble oraz capture events.

Usprawnień doznały także live eventy. Teraz każde tradycyjne zdarzenie może być użyte przez live(). Wcześnie niektóre eventy były nieobsługiwane.

detach()

Nowa metoda detach usuwa dany tag z drzewa DOM, ale jQuery nadal trzyma go w pamięci, dzięki czemu możemy szybko dodać go gdzie indziej, tym bardziej, że zachowane są zdarzenia, które zaaplikowaliśmy wcześniej:

var foo = $("#foo").click(function() {});
foo.detach();
foo.appendTo("body");

W powyższym przykładzie usuwamy #foo z drzewa DOM w 2 linijce, ale nadal możemy go dodać gdzieś indziej, np. do body.

unwrap()

Co robi unwrap? Usuwa opakowanie według danego taga:

Kod:

<body>
    <div>
        <p>he</p> <p>he</p> <p>he</p>
    </div>
</body>
$('div').unwrap();

zwróci nam:

<body>
   <p>he</p> <p>he</p> <p>he</p>
</body>

Inne

Z ważniejszych rzeczy pojawiła się metoda, a w zasadzie setter offset, który pozwala ustawić offest dla elementu. Wcześniej mogliśmy tylko takowy pobrać. Jest także delay(), dzięki której możemy opóźniać animacje:

$("div").fadeIn().delay(4000).fadeOut();

W ten sposób animacja fadeOut wykona się dopiero po 4 sekundach po zakończeniu fadeIn.

Wprowadzono też clearQueue(), która czyści zdefiniwaną kolejkę. Usuwa ona tylko funkcje, które nie zostały jeszcze wykonane.

Poza tym poprawiono zachowanie metody index:

$("div.current").index();

Coś takiego zwróci 1 w podobnej sytuacji:

<p></p>
<div class="current"></div>
<p></p>

Wprowadzono także metodę has(). Dzięki niej z łatwością sprawdzimy, czy dany element zawiera w sobie inny:

<div id="foobar">
	<p class="foo"></p>
</div>
$("#foobar").has("p.foo").length; // 1

Zachowuje się tak samo jak:

$("#foobar:has(p.foo)").length;

Wprowadzono też: nextUntil(), prevUntil(), parentsUntil(). Działają one podobnie do next i analogicznych, z tym wyjątkiem, że wyszukujemy elementy aż do znalezienia tego, który podaliśmy jako argument. Np.:

$("body").nextUntil("#foobar").css("display", "none");

ukryje wszystkie elementy aż do wystąpienia tego o id foobar.

Z innych zmian (oj, napracowali się chłopaki, napracowali…) mamy funkcje takie jak:

Z innych ciekawostek .clone(true) kopiuje także dane z funkcji data(). Nie tylko zdarzenia!

To prawdopodobnie nie wszystkie zmiany w najnowszej wersji jQuery, lecz z pewnością wszystkie najważniejsze. Jak zawsze chłopaki z teamu Resiga odwalili kawał dobrej roboty. Warto więc przyjrzeć się nowemu jQuery oraz projektowi 14 dni z jQuery. Dawno nie działo się aż tyle pozytywnych rzeczy w tym projekcie.

Komentarze

1

Dzięki za fajne wylistowanie nowych ficzerów! :-)

Maciek
2

Oj napracowali się chłopaki od jQuery, Ty przy tym wpisie też :)

Takie małe pytanko:
$("div").fadeIn().delay(4000).fadeOut();

„W ten sposób animacja fadeOut wykona się dopiero po 4 sekundach po zakończeniu fadeIn.”

Może się mylę, ale fadeOut wykona się 4 sekundy po rozpoczęciu fadeIn. Aby wykonało się 4 sekundy po zakończeniu trzeba by to podać jako callback dla fadeIn, np:
$("div").fadeIn(function(){
$(this).delay(4000).fadeOut();
});

3

http://api.jquery.com/delay/

Hm, chyba jest tak, jak piszę ;-):

When this statement is executed, the element slides up for 300 milliseconds and then pauses for 800 milliseconds before fading in for 400 milliseconds.

4

Świetny artykuł. Od długiego czasu nie widziałem tak dobrego wpisu o changelogu. „Dodano X, dodano Y, dodano Z” każdy potrafi powiedzieć. ;)

5

@ferrante
Rzeczywiście, to jednak w innej sytuacji chain nie działał tak jak się spodziewałem, tak że trzeba było używać callback. Mój błąd.

Np w połączeniu z funkcją css(). W przykładzie poniżej, kolor zmieni się wraz z rozpoczęciem pierwszej akcji, a nie po zakończeniu fadeOut() i fadeIn(). Jednak tutaj delay() też nie pomoże.
$('#wrap').fadeOut(2000).fadeIn(2000).css({'color': 'green'});

Dopiero taka konstrukcja zadziała:
$('#wrap').fadeOut(2000).fadeIn(2000,function(){
$(this).css({'color': 'red'});
});

6

@Vokiel: ale $(‚#wrap’).fadeOut(2000).fadeIn(2000).delay(4000).css({‚color’: ‚green’}); czemu ma nie zadziałać niby?

7

> czemu ma nie zadziałać niby?

IMO nie zadziała, tj. funkcja $.css wykona się zaraz po rozpoczęciu animacji. Wiąże się to ze sposobem działania $.delay.
$.delay wewnętrznie korzysta z kombinacji $.queue(callback) i $.dequeue, co oznacza obsługę kolejki wywołań. Zaś kolejkowane są funkcje z modułu Effects/Fx, a nie funkcje typu $.css.
Każde wywołanie funkcji animacyjnej dodaje tę funkcję do kolejki, dlatego zostaną one wywołane jedna po drugiej a nie jednocześnie.
Wywołanie $.queue(callback) wpycha kolejną funkcję do kolejki. Funkcja ta powinna wewnętrznie (bezpośrednio lub pośrednio) wykonać $.dequeue, inaczej nie wykonają się pozostałe funkcje z kolejki. I ten fakt wykorzystuje funkcja $.delay, która wykonuje $.dequeue po określonym interwale czasu (setTimeout). Algorytm działania jest po prostu banalny.

8

Dobra robota, Ferr :)

9

Świetny wpis! Strasznie się napracowałeś, ale — jak zwykle — efekt jest bardzo dobry :) Szkoda, że tak rzadko się tu coś nowego pojawia.

Damian
10

Wow, good job :)

Dobre uzupełnienie wiadomości z tego artykułu:

http://net.tutsplus.com/tutorials/javascript-ajax/jquery-1-4-released-the-15-new-features-you-must-know/

Jutro trzeba bedzie siąść i jeszcze raz na spokojnie przeanalizować twój wpis :)

le_banana
11

No no, jQuery się rozbudowuje i udoskonala ;) Dobrze, może kiedyś, w idealnym świecie gdy Windows będzie Open Source’owy i nikt nie będzie używał IE6, to będę miał czas na poznanie jQuery bliżej. No, ale pozostanę przy Mootools. Myślę też o Prototype, który z Zend’em ładnie współgra ;D Ferrante, utrzymuj swój blog na wysokim poziomie i zdobądź odrobinkę czasu na nowe wpisy.

12

A co jest lepsze jquery czy dojo czy motols czy prototype? W czym lepiej robić animacje i bajerki do stron?

thjgfj
13

A czy da się już może zrobić tak, żeby działały eventy przypisane do elementów dynamicznie ładowanych? Bo rozwiązanie podawane do tej pory w FAQ jest „trochę” karykaturalne. Co by tam złego o „klasycznym” JS nie mówić, ale da się do niego załadować dziada z babą i działa bez odprawiania tajemnych obrządków :)

Zgryzol
14

[…] Więcej: Zmiany w jQuery 1.4 […]

15

[…] resztę artykułu: Zmiany w jQuery 1.4 Tags: czym-lepiej, eventy-przypisane, faq, jest-, tej-pory, zanie-podawane Comments RSS […]

16

w sekcji „Inne”:
„…a w zasadzie setter offset, który pozwala ustawić offest dla…”
offest zamiast offset

Dodaj komentarz

Dozwolone tagi: <blockquote>, <code>, <strong>