Слухач подій, коли елемент стає видимим?


113

Я будую панель інструментів, яка буде включена в сторінку. дів, до якого він буде включений, за замовчуванням відобразиться: немає . Чи є спосіб я помістити слухача подій на свою панель інструментів для прослуховування, коли він стає видимим, щоб він міг ініціалізуватися? чи мені доведеться передати йому змінну зі сторінки, що містить?

Дякую


Чи допомагає ця відповідь? stackoverflow.com/questions/1397251 / ...
kangax

@kangax, дякую. Але оскільки його широко не реалізовано, я думаю, я збираюся почухати всю ідею слухача події та піти іншим маршрутом.
JD Isaacks

Дивіться цю відповідь на реалізацію події "onVisible" у JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green


Побачили це, будь ласка. stackoverflow.com/questions/45429746/…
Мартін

Відповіді:


8

Події Javascript стосуються взаємодії користувачів , якщо ваш код достатньо організований, ви повинні мати можливість викликати функцію ініціалізації в тому самому місці, де змінюється видимість (тобто ви не повинні змінюватись myElement.style.displayу багатьох місцях, натомість викликайте функцію / метод, який робить це та все, що ви хочете).


8
Але як би ви змогли виявити зміну видимості (тобто викликати функцію, як тільки елемент стає видимим)?
Андерсон Грін

Я думаю, ти цього не можеш зробити. Що ви робите замість того, щоб намагатися виявити зміну, це точно знати, де вона спровокована, і подати свій дзвінок туди. Якщо зміна видимості не є чимось, за який безпосередньо відповідає ваш власний код (наприклад, якийсь ліб), а логіка, за якою це відбувається, дуже надумана, я думаю, вам не пощастило? :)
maltalef

6
Я спростував це питання, тому що, незважаючи на весь сенс, це не має значення для власне питання. (якщо я не відображаю жодного на кадрі, всі дитячі елементи стають невидимими)
Себас

2
@Sebas, я не дуже розумію, чому тут важлива наочність дітей. У будь-якому випадку, якщо відповідь не була корисною для конкретного випадку (як би це не було), але вказує на рішення (або пояснення, чому немає рішення) для більшості програмістів, на мою скромну думку все-таки є правильною відповіддю. Якщо вам більше подобається один з інших відповідей (особливо той, який був зроблений у більш пізній час, коли технологія вдосконалилася і стали доступні нові варіанти), я вважаю, що прохання змінити правильну відповідь було б більш доречним, ніж зворотне звернення. У будь-якому випадку, спасибі за
хед

2
@figha, не діти, але якщо елемент, який ви переглядаєте, знаходиться у кадрі, який відображається = жоден, ви не матимете жодних ознак цього.
Себас

66

У майбутньому новий інтерфейс HTML Intersection Observer - те, що ви шукаєте. Це дозволяє налаштувати зворотний виклик, який викликається кожен раз, коли один елемент, названий цільовим, перетинає або область перегляду пристрою, або вказаний елемент. Він доступний в останніх версіях Chrome, Firefox та Edge. Докладнішу інформацію див. У https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API .

Простий приклад коду для спостереження за дисплеєм: жодна комутація:

// 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);
}

У дії: https://jsfiddle.net/elmarj/u35tez5n/5/


2
> API перехрестя Intersection дозволяє налаштувати зворотний виклик, який викликається кожного разу, коли один елемент, названий цільовим, перетинає або область перегляду пристрою, або вказаний елемент;
стіл

1
Зауважте, що InteractionObserver наразі не працює на Safari. caniuse.com/#feat=intersectionobserver Схоже, виправлення працює. bugs.webkit.org/show_bug.cgi?id=159475
Pic Mickael

8
Коли відсутність IE підтримки для чогось крутого, як це, перестане руйнувати наше життя?
Пітер Мур

5
@PeterMoore, як тільки ви перестанете намагатися його підтримати. Просто ні.
Джоні, чому

4
ЛОЛ. Іноді це не наше рішення.
Пітер Мур

45
var targetNode = document.getElementById('elementId');
var observer = new MutationObserver(function(){
    if(targetNode.style.display != 'none'){
        // doSomething
    }
});
observer.observe(targetNode, { attributes: true, childList: true });

Я можу трохи запізнитися, але ви можете просто скористатися MutationObserver, щоб спостерігати за будь-якими змінами на потрібному елементі. Якщо якісь зміни відбудуться, вам доведеться просто перевірити, чи відображається елемент.


4
Це не працює, коли targetNode не відображається, оскільки предка не відображається, але потім відображається.
Марко Екштейн

Оголошено! Я використав це в іншій відповіді stackoverflow: stackoverflow.com/questions/48792245/…
Нік Тіммер

На жаль, це працює лише при використанні стилів вбудованого елемента, а не тоді, коли зміна є результатом зміни класу CSS (що є більш вірогідним сценарієм, якщо врахувати, що в попередній ситуації ви, мабуть, вже маєте повний програмний контроль). Скрипка, що показує проблему: jsfiddle.net/elmarj/uye62Lxc/4 . Дивіться тут для більш повної дискусії про те, як спостерігати за змінами стилю: dev.to/oleggromov/observing-style-changes---d4f
Ельмар Янсен

На насправді правильний спостерігач використовувати тут би IntersectionObserver- stackoverflow.com/a/52627221/2803743
Kano

Це рішення корисно для тих випадків, коли ви хочете вмикати та вимикати елемент, не маючи прямого контролю над цим елементом, і хочете реагувати на зміну значення відображення
Еран Голдін

15

Існує хоча б один спосіб, але він не дуже хороший. Ви можете просто опитувати елемент на такі зміни:

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);

Стандарт DOM також визначає події мутації , але я ніколи не мав можливості їх використовувати, і я не впевнений, наскільки вони підтримуються. Ви використовуєте їх так:

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

Цей код у мене в голові, тому я не впевнений, чи спрацює він.

Краще і саме просте рішення матиме функцію зворотного виклику в функції відображаються ваші цілі.


1
Цікаво, дякую. Через кілька років статус DOMAttrModified змінився: "Застаріло. Ця функція була вилучена з веб-стандартів. Хоча деякі веб-переглядачі все ще можуть її підтримувати, вона вже відмінена". (Mozilla)
BurninLeo

MutationObserver - це нове нове.
mindplay.dk

14

У мене була ця сама проблема і я створив плагін jQuery, щоб вирішити його для нашого сайту.

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

Ось як би ви його використовували на основі прикладу:

$('#contentDiv').visibilityChanged(function(element, visible) {
    alert("do something");
});

4
Це рішення використовується .is(':visible')разом з setTimeout.
Hp93

7

Як говорить @figha, якщо це ваша власна веб-сторінка , вам слід просто запустити все, що потрібно для запуску після того, як ви зробите елемент видимим.

Однак для того, щоб відповісти на запитання (а також хтось, хто робить Chrome або Firefox Extensions , де це звичайний випадок використання), Підсумок мутацій та спостерігач за мутаціями дозволять змінам DOM викликати події.

Наприклад, запуск події для елементів, data-widgetщо додають атрибут до DOM. Позичив цей чудовий приклад з блогу Девіда Уолша :

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);

Відповіді включають added, removed, valueChangedі багато інших . valueChangedвключає всі атрибути, включаючи displayі т.д.


Можливо, тому, що він хоче знати, коли це насправді на екрані. Я це можу, можу лише припустити, що у потоку є та сама причина.
Дейв Хіллєр

Не відповідає на питання, і розміщувати лише посилання не рекомендується.
Алекс Холсгроув

@AlexHolsgrove Я додав приклад за посиланням. Оскільки на плакаті йдеться про додавання панелі інструментів до сторінки, схоже, вони можуть додавати панель інструментів до сторонньої сторінки та чекати, коли елемент буде доданий до DOM, і в цьому випадку мутації є найкращим API.
mikemaccana

Зауважте, що це все ще не стосується тієї частини, яка пояснює, де в процесі спостереження за мутацією надходить "видимість".
Майк "Pomax" Камерманс


3

Просто прокоментуйте підтримку веб-переглядача слухача подій DOMAttrModified:

Підтримка крос-браузера

Ці події не реалізуються послідовно у різних браузерах, наприклад:

  • IE до версії 9 взагалі не підтримував події мутації і не реалізував деякі з них правильно у версії 9 (наприклад, DOMNodeInserted)

  • WebKit не підтримує DOMAttrModified (див. Помилку webkit 8191 та спосіб вирішення)

  • "події імені мутації", тобто DOMElementNameChanged та DOMAttributeNameChanged, не підтримуються у Firefox (станом на версію 11), і, мабуть, і в інших браузерах.

Джерело: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events


-2

моє рішення:

; (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);

наприклад:

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

function processMoreLessButton(){
//some logic
}

5
Ви повинні сказати всім, що ви використовували оригінальний код jQuery, це
вселило

1
"моє рішення". Нерв у цього хлопця.
Андре Сілва

@ AndréSilva Можливо, він написав jQuery. : O
Андрій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.