Pemroses acara saat elemen menjadi terlihat?

113

Saya sedang membangun toolbar yang akan dimasukkan ke dalam halaman. div yang akan dimasukkan akan secara default menampilkan: none . Adakah cara untuk meletakkan event listener di toolbar saya untuk didengarkan ketika sudah terlihat sehingga bisa diinisialisasi? atau haruskah saya meneruskan variabel dari halaman yang memuatnya?

Terima kasih

JD Isaacks
sumber
Apakah jawaban ini membantu? stackoverflow.com/questions/1397251/…
kangax
@kangax, terima kasih. Tapi karena ini tidak diterapkan secara luas, saya pikir saya akan menggaruk ide pendengar acara secara keseluruhan dan pergi ke rute yang berbeda.
JD Isaacks
Lihat jawaban ini untuk implementasi acara "onVisible" di JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green
kemungkinan duplikat dari Bagaimana menerapkan acara 'onVisible' di Javascript?
pengguna
Bisa melihat ini, tolong. stackoverflow.com/questions/45429746/…
Martin

Jawaban:

8

Peristiwa Javascript berhubungan dengan Interaksi Pengguna , jika kode Anda cukup terorganisir, Anda harus dapat memanggil fungsi inisialisasi di tempat yang sama di mana visibilitas berubah (yaitu Anda tidak boleh mengubah myElement.style.displaydi banyak tempat, sebaliknya, panggil fungsi / metode yang ini dan hal lain yang mungkin Anda inginkan).

maltalef
sumber
8
Tapi bagaimana Anda bisa mendeteksi perubahan dalam visibilitas (yaitu, memanggil fungsi segera setelah elemen menjadi terlihat)?
Anderson Green
Saya pikir Anda tidak bisa melakukan itu. Apa yang akan Anda lakukan daripada mencoba mendeteksi perubahan, adalah mengetahui dengan tepat di mana hal itu diprovokasi, dan menempatkan panggilan Anda di sana. Jika perubahan dalam visibilitas bukanlah sesuatu yang bertanggung jawab langsung oleh kode Anda sendiri (misalnya beberapa lib) dan logika yang menyebabkannya sangat dibuat-buat, saya kira Anda kurang beruntung? :)
maltalef
6
Saya tidak menyukai pertanyaan ini karena terlepas dari semua alasannya, ini tidak relevan dengan masalah yang sebenarnya. (jika saya tidak menampilkannya pada bingkai, semua elemen anak menjadi tidak terlihat)
Sebas
2
@Sebas, saya tidak begitu mengerti mengapa visibilitas anak-anak penting di sini. Bagaimanapun, jika jawabannya tidak berguna untuk kasus tertentu Anda (apa pun itu) tetapi menunjuk ke solusi (atau penjelasan mengapa tidak ada solusi) untuk sebagian besar programmer, itu masih merupakan jawaban yang valid menurut pendapat saya. Jika Anda lebih menyukai salah satu jawaban lain (terutama yang dibuat di lain waktu, ketika teknologi meningkat dan pilihan baru tersedia), saya yakin bahwa permintaan untuk mengubah jawaban yang benar akan lebih tepat daripada suara negatif. Bagaimanapun, terima kasih atas perhatiannya :)
maltalef
2
@figha, bukan anak-anak, tetapi jika elemen yang Anda tonton berada dalam bingkai yang ditampilkan = tidak ada, Anda tidak akan memiliki tanda apa pun.
Sebas
66

Untuk selanjutnya, HTML Intersection Observer API baru adalah hal yang Anda cari. Hal ini memungkinkan Anda untuk mengonfigurasi callback yang dipanggil setiap kali satu elemen, yang disebut target, berpotongan dengan area pandang perangkat atau elemen yang ditentukan. Ini tersedia di versi terbaru Chrome, Firefox dan Edge. Lihat https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API untuk info lebih lanjut.

Contoh kode sederhana untuk mengamati display: none switching:

// Start observing visbility of element. On change, the
//   the callback is called with Boolean visibility as
//   argument:

respondToVisibility(element, callback) {
  var options = {
    root: document.documentElement
  }

  var observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      callback(entry.intersectionRatio > 0);
    });
  }, options);

  observer.observe(element);
}

Beraksi: https://jsfiddle.net/elmarj/u35tez5n/5/

Elmar Jansen
sumber
2
> Intersection Observer API memungkinkan Anda mengonfigurasi callback yang dipanggil setiap kali satu elemen, yang disebut target, berpotongan dengan viewport perangkat atau elemen yang ditentukan;
stil
1
Perhatikan bahwa InteractionObserver tidak berfungsi di Safari saat ini. caniuse.com/#feat=intersectionobserver Sepertinya ada patch yang sedang berlangsung. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael
8
Kapan kurangnya dukungan IE untuk hal keren seperti ini akan berhenti menghancurkan hidup kita?
Peter Moore
5
@PeterMoore segera setelah Anda berhenti mencoba mendukungnya. Jangan.
johny mengapa
4
LOL. Terkadang itu bukan keputusan kami.
Peter Moore
45
var targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
    if(targetNode.style.display != 'none'){
        // doSomething
    }
});
observer.observe(targetNode, { attributes: true, childList: true });

Saya mungkin sedikit terlambat, tetapi Anda bisa menggunakan MutationObserver untuk mengamati setiap perubahan pada elemen yang diinginkan. Jika ada perubahan yang terjadi, Anda hanya perlu memeriksa apakah elemen tersebut ditampilkan.

pengguna3588429
sumber
4
Ini tidak bekerja ketika targetNode tidak ditampilkan karena leluhur tidak ditampilkan tapi kemudian ditampilkan.
Marco Eckstein
Suara positif! Saya menggunakan ini di jawaban stackoverflow lain: stackoverflow.com/questions/48792245/…
Nick Timmer
Sayangnya, ini hanya berfungsi saat menggunakan gaya sebaris pada elemen, bukan saat perubahan tersebut merupakan hasil dari perubahan kelas CSS (yang merupakan skenario yang lebih mungkin, mengingat dalam situasi sebelumnya Anda mungkin sudah memiliki kontrol programatik penuh). Biola yang menunjukkan masalah: jsfiddle.net/elmarj/uye62Lxc/4 . Lihat di sini untuk diskusi yang lebih lengkap tentang cara mengamati perubahan gaya: dev.to/oleggromov/observing-style-changes---d4f
Elmar Jansen
Sebenarnya Pengamat yang tepat untuk digunakan di sini adalah IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano
Solusi ini berguna saat Anda ingin mengaktifkan dan menonaktifkan elemen, dan tidak memiliki kontrol langsung atas elemen tersebut, dan ingin bereaksi terhadap perubahan nilai tampilan
Eran Goldin
15

Setidaknya ada satu cara, tapi itu tidak terlalu bagus. Anda bisa mengumpulkan elemen untuk perubahan seperti ini:

var previous_style,
    poll = window.setInterval(function()
{
    var current_style = document.getElementById('target').style.display;
    if (previous_style != current_style) {
        alert('style changed');
        window.clearInterval(poll);
    } else {
        previous_style = current_style;
    }
}, 100);

Standar DOM juga menentukan peristiwa mutasi , tetapi saya tidak pernah memiliki kesempatan untuk menggunakannya, dan saya tidak yakin seberapa baik mereka didukung. Anda akan menggunakannya seperti ini:

target.addEventListener('DOMAttrModified', function()
{
    if (e.attrName == 'style') {
        alert('style changed');
    }
}, false);

Kode ini di luar kepala saya, jadi saya tidak yakin apakah itu akan berhasil.

Solusi terbaik dan termudah adalah memiliki panggilan balik dalam fungsi yang menampilkan target Anda.

slikts
sumber
1
Menarik, terima kasih. Beberapa tahun kemudian, status DOMAttrModified telah berubah: "Tidak digunakan lagi. Fitur ini telah dihapus dari standar Web. Meskipun beberapa browser mungkin masih mendukungnya, fitur ini sedang dalam proses dihentikan." (Mozilla)
BurninLeo
MutationObserver adalah yang baru.
mindplay.dk
14

Saya memiliki masalah yang sama dan membuat plugin jQuery untuk menyelesaikannya untuk situs kami.

https://github.com/shaunbowe/jquery.visibilityChanged

Berikut adalah cara Anda menggunakannya berdasarkan contoh Anda:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});
Shaun Bowe
sumber
4
Solusi ini digunakan .is(':visible')bersama dengan setTimeout.
Hp93
7

Seperti yang dikatakan @figha, jika ini adalah halaman web Anda sendiri , Anda harus menjalankan apa pun yang Anda perlukan untuk menjalankan setelah Anda membuat elemen terlihat.

Namun, untuk tujuan menjawab pertanyaan (dan siapa pun yang membuat Ekstensi Chrome atau Firefox , di mana ini adalah kasus penggunaan umum), Ringkasan Mutasi dan Pengamat Mutasi akan mengizinkan perubahan DOM untuk memicu peristiwa.

Misalnya, memicu peristiwa untuk elemen dengan data-widgetatribut yang ditambahkan ke DOM. Meminjam contoh luar biasa ini dari blog David Walsh :

var observer = new MutationObserver(function(mutations) {
    // For the sake of...observation...let's output the mutation to console to see how this all works
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
    });    
});

// Notify me of everything!
var observerConfig = {
    attributes: true, 
    childList: true, 
    characterData: true 
};

// Node, config
// In this case we'll listen to all changes to body and child nodes
var targetNode = document.body;
observer.observe(targetNode, observerConfig);

Tanggapan meliputi added, removed, valueChangeddan banyak lagi . valueChangedmencakup semua atribut, termasuk displaydll.

mikemaccana
sumber
Mungkin karena dia ingin tahu kapan itu sebenarnya ada di layar. Ya, saya hanya bisa berasumsi bahwa downvoter memiliki alasan yang sama.
Dave Hillier
Tidak menjawab pertanyaan, dan hanya memposting tautan tidak disarankan.
Alex Holsgrove
@AlexHolsgrove Saya telah menambahkan contoh, dari tautan. Karena poster berbicara tentang menambahkan toolbar ke halaman, sepertinya mereka menambahkan toolbar ke halaman pihak ketiga dan menunggu elemen ditambahkan ke DOM, dalam hal ini Mutasi adalah API terbaik.
mikemaccana
Perhatikan bahwa ini masih tidak mencakup bagian yang menjelaskan di bagian mana dalam proses pengamatan mutasi "visibilitas" masuk.
Mike 'Pomax' Kamermans
3

Hanya untuk mengomentari dukungan browser event listener DOMAttrModified:

Dukungan lintas browser

Peristiwa ini tidak diterapkan secara konsisten di berbagai browser, misalnya:

  • IE sebelum versi 9 sama sekali tidak mendukung peristiwa mutasi dan tidak menerapkan beberapa di antaranya dengan benar di versi 9 (misalnya, DOMNodeInserted)

  • WebKit tidak mendukung DOMAttrModified (lihat bug webkit 8191 dan solusinya)

  • "peristiwa nama mutasi", yaitu DOMElementNameChanged dan DOMAttributeNameChanged tidak didukung di Firefox (mulai versi 11), dan mungkin juga di browser lain.

Sumber: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events

Josh
sumber
-2

solusi saya:

; (function ($) {
$.each([ "toggle", "show", "hide" ], function( i, name ) {
    var cssFn = $.fn[ name ];
    $.fn[ name ] = function( speed, easing, callback ) {
        if(speed == null || typeof speed === "boolean"){
            var ret=cssFn.apply( this, arguments )
            $.fn.triggerVisibleEvent.apply(this,arguments)
            return ret
        }else{
            var that=this
            var new_callback=function(){
                callback.call(this)
                $.fn.triggerVisibleEvent.apply(that,arguments)
            }
            var ret=this.animate( genFx( name, true ), speed, easing, new_callback )
            return ret
        }
    };
});

$.fn.triggerVisibleEvent=function(){
    this.each(function(){
        if($(this).is(':visible')){
            $(this).trigger('visible')
            $(this).find('[data-trigger-visible-event]').triggerVisibleEvent()
        }
    })
}
})(jQuery);

sebagai contoh:

if(!$info_center.is(':visible')){
    $info_center.attr('data-trigger-visible-event','true').one('visible',processMoreLessButton)
}else{
    processMoreLessButton()
}

function processMoreLessButton(){
//some logic
}
pengguna2699000
sumber
5
Anda harus memberi tahu semua orang bahwa Anda telah menggunakan kode jQuery asli, itu akan menginspirasi lebih banyak kepercayaan;)
aemonge
1
"solusi saya". Keberanian pada orang ini.
André Silva
@ AndréSilva Mungkin dia menulis jQuery. : O
Andrew