Bug: jQuery Simple Spy Tidak Bekerja pada jQuery 1.4.3+
Masalah ini sebenarnya sudah cukup lama dibicarakan pada forum Stackoverflow, hanya saja Saya baru mengetahui ini sekitar setengah tahun yang lalu dan baru mendalami cara kerjanya pada bulan-bulan ini. jQuery Simple Spy tidak bekerja pada jQuery 1.4.3+
Pertama-tama akan Saya tunjukkan efek animasi spylist yang dapat berjalan lancar dengan framework jQuery 1.3.2:
Sekarang coba Anda ganti versi jQuery menjadi 1.5.2 atau yang lain di atas 1.4.3, klik Run dan lihat hal buruk apa yang akan terjadi pada efek animasi:
Seperti yang telah Anda lihat bahwa elemen <ul class='spy'></ul>
tidak memuat daftar baru dan itu membuat semuanya menghilang saat semua daftar telah memudar.
Masalahnya Cuma Satu
Masalahnya ada pada baris ini:
Elemen daftar/list telah diset .css()
dengan nilai display:'none'
, padahal di sini kita tahu bahwa rantai animasi yang berjalan hanya berputar di sekitar opacity
dan height
sedangkan animasi display
tidak pernah terjadi. Dan kenyataannya, display
bukan merupakan properti jQuery yang bisa dianimasikan (baca perkenalan properti animasi jQuery):
// 2. effect
function spy() {
// insert a new item with opacity and height of zero
var $insert = $(items[currentItem]).css({height:0,opacity:0,display:'none' }).prependTo($list);
// fade the LAST item out
$list.find('> li:last').animate({opacity:0}, 1000, function() {
// increase the height of the NEW first item
$insert.animate({height:height}, 1000).animate({opacity:1}, 1000);
$(this).remove();
});
currentItem++;
if (currentItem >= total) {
currentItem = 0;
}
setTimeout(spy, interval)
}
Sampai di sini pada dasarnya masalah sudah selesai. Hanya saja Saya telah menambahkan beberapa pembaharuan untuk memperhalus efek animasinya. Sebuah sikap yang sangat umum apabila seseorang menginginkan tampilan yang berbeda dari plugin ini demi kepuasan pribadi. Anda bisa saja menambahkan margin
sebagai pembatas antar daftar, atau menambahkan padding
untuk memberikan kesan bahwa setiap elemen daftar merupakan satu unit boks berisi informasi tertentu yang dikemas dengan rapi. Hingga saat Anda mencoba melakukan semua modifikasi itu, Anda akan menemui satu lagi efek yang tidak Anda inginkan:
Saya telah membuang efek animasi transparasi pada pemuatan daftar baru untuk memperjelas pandangan mengenai apa yang membuat efek animasi menjadi tersentak. Di sini kita akan memfokuskan diri pada efek penyisipan daftar baru dan mengabaikan efek pemudaran daftar di bawahnya:
Animasi pertama menunjukkan bahwa efek pemuatan daftar baru akan tampak sedikit tersentak karena pengaruh padding
. Itu terjadi karena pemuatan daftar baru dilakukan begitu saja dengan cara menyisipkan elemen <li>
yang mengandung nilai height
sebesar 0px
.
Jika kita tidak menggunakan padding
pada elemen ini sejak awal, efek-efek menyentak tersebut pada dasarnya tidak akan timbul. Dalam CSS Box-Model, padding
dan border-width
tidak termasuk dalam perhitungan width
dan height
pada elemen. Ini berarti bahwa meskipun kita telah mengeset nilai height
sebesar 0px
pada elemen, namun karena pada saat yang sama kita juga telah menerapkan padding
sebesar 10px
, maka ukuran elemen setinggi 0 piksel akan sama artinya dengan 20 piksel.
Animasi ke dua menampilkan efek yang jauh lebih lembut karena di sini Saya tidak lagi menggunakan animasi $insert.animate({height:N}, animSpeed)
melainkan cukup menggunakan $insert.slideDown(animSpeed)
.
.slideDown()
berbeda dengan .animate({height:N})
karena .slideDown()
tidak hanya akan menganimasikan tinggi elemen, tetapi juga akan menganimasikan margin dan padding terkait pada saat yang bersamaan:
var elemdisplay = {},
iframe, iframeDoc,
rfxtypes = /^(?:toggle|show|hide)$/,
rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
timerId,
fxAttrs = [ // height animations
[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ], // width animations
[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
// opacity animations
[ "opacity" ]
],
fxNow;
// blablabla...
Dan berikut ini adalah keseluruhan plugin yang sudah Saya perbaiki sedikit:
(function($) {
$.fn.simpleSpy = function(limit, animSpeed, interval, startDelay) {
limit = limit || 4;
interval = interval || 4000;
startDelay = startDelay || 0;
animSpeed = animSpeed || 1000;
return this.each(function() {
// 1. setup
// capture a cache of all the Interesting title s
// chomp the list down to limit li elements
var $list = $(this),
run = true,
items = [], // uninitialised
currentItem = limit,
total = 0, // initialise later on
start = 0, //when the effect first starts
height = $list.find('> li:first').height(),
theMargin = $list.find('> li:first').css('marginTop') + $list.find('> li:first').css('marginBottom');
// capture the cache
$list.find('> li').each(function() {
items.push('<li>' + $(this).html() + '</li>');
});
$list.bind("stop", function() {
run = false
}).bind("start", function() {
run = true
});
total = items.length;
$list.wrap('<div class="spyWrapper"></div>').parent().css({height:height+theMargin*limit});
$list.find('> li').filter(':gt(' + (limit - 1) + ')').remove();
// 2. effect
function spy() {
if (run) {
// insert a new item ass hidden element (display:none)
var $insert = $(items[currentItem]).hide().prependTo($list);
// fade the LAST item out
$list.find('> li:last').animate({opacity:0}, animSpeed, function() {
// increase the height of the NEW first item
$insert.css('opacity', 0).slideDown(animSpeed, function() {
$insert.animate({opacity:1}, animSpeed);
});
$(this).remove();
});
currentItem++;
if (currentItem >= total) {
currentItem = 0;
}
}
setTimeout(spy, interval)
}
if (start < 1) {
setTimeout(spy, startDelay);
start++;
} else {
spy();
}
});
};
})(jQuery);
Konfigurasi jQuery Simple Spy
Buat sebuah grup daftar dengan kelas atau ID tertentu seperti ini:
<ul id='spylist'>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
<li>
<h4>Judul Item</h4>
Teks di sini teks di sini teks di sini...
</li>
</ul>
Seleksi elemen tersebut kemudian terapkan fungsi .simpleSpy()
:
$(document).ready(function() {
$('ul#spylist').simpleSpy(4, 1000, 5000, 0).bind("mouseenter", function() {
// stop the animation when mouseenter
$(this).trigger("stop")
}).bind("mouseleave", function() {
// continue the animation when mouseleave
$(this).trigger("start")
});
});
2 Komentar
orange.net
ketemu lagi mas,, :)
btw jadi pertamax saya,, :D
mo nanya mas ini kl di padupadankan sama accordion bisa ga ya?
jadikl mouse melintas dimenu'a kluar teks tapi ga melebihi batas kotak/body spylist'a,, dengan catatan menu2 yg lain terdorong kebawah tidak terlihat,,
bingung ya mas?
saya juga bingung jelasin mau saya'a,, :P
ya kira2 bgitu lah,,
hehe,, terimakasih,, ^_^
Taufik Nurrohman
@orange.netSepertinya bisa. Kira-kira caranya begini:
Variabel height sudah dideklarasikan di dalam plugin yaitu bernilai
$('> li:first').height()
Nah, tadi kan masnya bilang ingin menganimasikan tinggi setinggi batasan maksimal, jadi harus buat variabel baru yang nilainya menyatakan tinggi satu elemen
<li>
dikalikan jumlah<li>
maksimal yang ternyata nilainya sudah terdapat di dalam variabel limit:Konsepnya kira-kira begitu.