Bug: jQuery Simple Spy Tidak Bekerja pada jQuery 1.4.3+

Tabel Konten
  1. Masalahnya Cuma Satu 
  • Konfigurasi jQuery Simple Spy 
  • Variabel: 
  • jQuery Simple Spy Bug

    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:

    Lihat Efek Animasi

    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:

    Mengganti versi jQuery

    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:

    display tidak termasuk dalam properti yang bisa dianimasikan

    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:

    Lihat Contoh Modifikasi

    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:

    jQuery Spy List
    Fokuskan pandangan pada efek penyisipan daftar baru dan abaikan 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")
        });
    });

    Variabel: 

    $('#selektor').simpleSpy(limit, animSpeed, interval, startDelay);
    • Tentukan batasan daftar yang akan ditampilkan pada variabel limit
    • Tentukan kecepatan animasi pada variabel animSpeed
    • Tentukan interval animasi pada variabel interval
    • Tentukan delay start pada variabel startDelay

    Lihat Demo Download Revisi

    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:

      $('ul.spy li').hover(function() {
      $(this).stop().animate({height:maxHeight}, 400);
      }, function() {
      $(this).stop().animate({height:height}, 400);
      });

      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:

      var maxHeight = height * limit;

      Konsepnya kira-kira begitu.

    Komentar telah ditutup.