Trình nghe sự kiện khi nào phần tử hiển thị?


113

Tôi đang xây dựng một thanh công cụ sẽ được đưa vào một trang. div mà nó sẽ được đưa vào sẽ mặc định hiển thị: không có . Có cách nào tôi có thể đặt một trình lắng nghe sự kiện trên thanh công cụ của mình để lắng nghe khi nó hiển thị để nó có thể khởi chạy không? hay tôi sẽ phải chuyển cho nó một biến từ trang chứa?

Cảm ơn


Câu trả lời này có giúp ích gì không? stackoverflow.com/questions/1397251/…
kangax

@kangax, cảm ơn bạn. Nhưng vì nó không được triển khai rộng rãi, tôi nghĩ rằng tôi sẽ làm sơ sài toàn bộ ý tưởng của người nghe sự kiện và đi một con đường khác.
JD Isaacks 23/09/09

Xem câu trả lời này để biết cách triển khai sự kiện "onVible" trong JavaScript: stackoverflow.com/a/3807340/975097
Anderson Green


Xin vui lòng xem điều này. stackoverflow.com/questions/45429746/…
Martin

Câu trả lời:


8

Các sự kiện Javascript liên quan đến Tương tác người dùng , nếu mã của bạn được tổ chức đủ, bạn sẽ có thể gọi hàm khởi tạo ở cùng một nơi mà khả năng hiển thị thay đổi (nghĩa là bạn không nên thay đổi myElement.style.displayở nhiều nơi, thay vào đó, hãy gọi một hàm / phương thức. cái này và bất cứ thứ gì khác mà bạn có thể muốn).


8
Nhưng làm thế nào bạn có thể phát hiện ra sự thay đổi trong khả năng hiển thị (tức là, gọi một hàm ngay khi một phần tử trở nên hiển thị)?
Anderson Green

Tôi nghĩ bạn không thể làm điều đó. Những gì bạn sẽ làm thay vì cố gắng phát hiện ra sự thay đổi, là biết chính xác nơi mà nó bị kích động và thực hiện cuộc gọi của bạn ở đó. Nếu sự thay đổi về khả năng hiển thị không phải là thứ mà mã của bạn trực tiếp chịu trách nhiệm (ví dụ: một số lib) và logic mà điều đó xảy ra rất phức tạp, tôi đoán bạn đã gặp may? :)
maltalef

6
Tôi đã từ chối câu hỏi này vì mặc dù nó có ý nghĩa gì, nhưng nó không liên quan đến vấn đề thực tế. (nếu tôi không hiển thị gì trên khung, tất cả các phần tử con đều trở nên vô hình)
Sebas

2
@Sebas, tôi thực sự không hiểu tại sao tầm nhìn của bọn trẻ lại quan trọng ở đây. Dù sao, nếu câu trả lời không hữu ích cho trường hợp cụ thể của bạn (bất kể nó có thể là gì) nhưng chỉ ra một giải pháp (hoặc giải thích tại sao không có giải pháp) cho hầu hết các lập trình viên, thì đó vẫn là một câu trả lời hợp lệ theo ý kiến ​​khiêm tốn của tôi. Nếu bạn thích một trong những câu trả lời khác tốt hơn (đặc biệt là câu trả lời được đưa ra sau đó, khi công nghệ được cải thiện và các tùy chọn mới có sẵn), tôi tin rằng một yêu cầu thay đổi câu trả lời đúng sẽ phù hợp hơn một phản đối. Trong mọi trường hợp, cảm ơn cho heads-up :)
maltalef

2
@figha, không phải phần tử con, nhưng nếu phần tử bạn đang xem nằm trong khung được hiển thị = none, bạn sẽ không có bất kỳ dấu hiệu nào về nó.
Sebas

66

Trong tương lai, API trình quan sát giao lộ HTML mới là thứ bạn đang tìm kiếm. Nó cho phép bạn định cấu hình một lệnh gọi lại được gọi bất cứ khi nào một phần tử, được gọi là đích, giao nhau giữa khung nhìn thiết bị hoặc một phần tử được chỉ định. Nó có sẵn trong các phiên bản mới nhất của Chrome, Firefox và Edge. Xem https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API để biết thêm thông tin.

Ví dụ mã đơn giản để quan sát màn hình: không chuyển đổi:

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

Đang hoạt động: https://jsfiddle.net/elmarj/u35tez5n/5/


2
> API Intersection Observer cho phép bạn định cấu hình một lệnh gọi lại được gọi bất cứ khi nào một phần tử, được gọi là đích, giao nhau giữa khung nhìn thiết bị hoặc một phần tử được chỉ định;
stil

1
Lưu ý rằng InteractionObserver hiện không hoạt động trên Safari. caniuse.com/#feat=intersectionobserver Có vẻ như đang có một bản vá. bug.webkit.org/show_bug.cgi?id=159475
Pic Mickael

8
Khi nào việc IE thiếu hỗ trợ cho những thứ hay ho như thế này sẽ ngừng hủy hoại cuộc sống của chúng ta?
Peter Moore

5
@PeterMoore ngay sau khi bạn ngừng cố gắng hỗ trợ nó. Đừng.
johny tại sao

4
CƯỜI LỚN. Đôi khi đó không phải là quyết định của chúng ta.
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 });

Tôi có thể đến muộn một chút, nhưng bạn có thể sử dụng MutationObserver để quan sát bất kỳ thay đổi nào trên phần tử mong muốn. Nếu có bất kỳ thay đổi nào xảy ra, bạn sẽ chỉ phải kiểm tra xem phần tử có được hiển thị hay không.


4
Điều này không hoạt động khi targetNode không được hiển thị vì tổ tiên không được hiển thị nhưng sau đó được hiển thị.
Marco Eckstein

Đã ủng hộ! Tôi đã sử dụng này trong một câu trả lời stackoverflow: stackoverflow.com/questions/48792245/...
Nick Timmer

Thật không may, điều này chỉ hoạt động khi sử dụng các kiểu nội tuyến trên phần tử, không phải khi thay đổi là kết quả của việc thay đổi lớp CSS (đó là trường hợp có nhiều khả năng xảy ra hơn, vì trong tình huống trước đây, bạn có thể đã có toàn quyền kiểm soát theo chương trình). Fiddle hiển thị sự cố: jsfiddle.net/elmarj/uye62Lxc/4 . Xem ở đây cho một cuộc thảo luận đầy đủ hơn về làm thế nào để quan sát phong cách thay đổi: dev.to/oleggromov/observing-style-changes---d4f
Elmar Jansen

Trên thực tế, Trình quan sát chính xác để sử dụng ở đây sẽ là IntersectionObserver- stackoverflow.com/a/52627221/2803743
kano

Giải pháp này hữu ích khi bạn muốn bật và tắt một phần tử và không có quyền kiểm soát trực tiếp phần tử đó và muốn phản ứng với sự thay đổi giá trị hiển thị
Eran Goldin

15

Có ít nhất một cách, nhưng nó không phải là một cách tốt. Bạn chỉ có thể thăm dò ý kiến ​​phần tử cho những thay đổi như sau:

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

Tiêu chuẩn DOM cũng chỉ định các sự kiện đột biến , nhưng tôi chưa bao giờ có cơ hội sử dụng chúng và tôi không chắc chúng được hỗ trợ tốt như thế nào. Bạn sẽ sử dụng chúng như thế này:

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

Mã này nằm ngoài đầu tôi, vì vậy tôi không chắc liệu nó có hoạt động hay không.

Giải pháp tốt nhất và dễ dàng nhất là có một lệnh gọi lại trong hàm hiển thị mục tiêu của bạn.


1
Thú vị, cảm ơn bạn. Một vài năm sau, trạng thái của DOMAttrModified đã thay đổi: "Không được dùng nữa. Tính năng này đã bị xóa khỏi các tiêu chuẩn Web. Mặc dù một số trình duyệt có thể vẫn hỗ trợ nhưng nó đang trong quá trình bị loại bỏ." (Mozilla)
BurninLeo

MutationObserver là cái mới.
mindplay.dk

14

Tôi cũng gặp vấn đề này và đã tạo một plugin jQuery để giải quyết nó cho trang web của chúng tôi.

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

Đây là cách bạn sẽ sử dụng nó dựa trên ví dụ của bạn:

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

4
Giải pháp này sử dụng .is(':visible')cùng với setTimeout.
Hp93,

7

Như @figha nói, nếu đây là trang web của riêng bạn, bạn chỉ nên chạy bất cứ thứ gì bạn cần để chạy sau khi bạn hiển thị phần tử.

Tuy nhiên, với mục đích trả lời câu hỏi (và bất kỳ ai tạo Tiện ích mở rộng của Chrome hoặc Firefox , nơi đây là trường hợp sử dụng phổ biến), Tóm tắt đột biến và Trình quan sát đột biến sẽ cho phép các thay đổi DOM kích hoạt sự kiện.

Ví dụ: kích hoạt sự kiện cho một phần tử có data-widgetthuộc tính được thêm vào DOM. Mượn ví dụ tuyệt vời này từ blog của 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);

Responses bao gồm added, removed, valueChangedvà nhiều hơn nữa . valueChangedbao gồm tất cả các thuộc tính, bao gồm displayv.v.


Có lẽ vì anh ấy muốn biết khi nào nó thực sự xuất hiện trên màn hình. Tôi làm, tôi chỉ có thể cho rằng người downvoter có cùng lý do.
Dave Hillier

Không trả lời câu hỏi và chỉ đăng liên kết không được khuyên.
Alex Holsgrove,

@AlexHolsgrove Tôi đã thêm một ví dụ, từ liên kết. Vì người đăng nói về việc thêm thanh công cụ vào trang, có vẻ như họ có thể đang thêm thanh công cụ vào trang của bên thứ ba và chờ một phần tử được thêm vào DOM, trong trường hợp đó thì Mutations là API tốt nhất.
mikemaccana

Lưu ý rằng điều này vẫn không bao gồm phần đó giải thích vị trí trong quá trình quan sát đột biến, "khả năng hiển thị" xuất hiện.
Mike 'Pomax' Kamermans 8/10/19


3

Chỉ để nhận xét về hỗ trợ trình duyệt trình nghe sự kiện DOMAttrModified:

Hỗ trợ nhiều trình duyệt

Các sự kiện này không được triển khai nhất quán trên các trình duyệt khác nhau, ví dụ:

  • IE trước phiên bản 9 hoàn toàn không hỗ trợ các sự kiện đột biến và không triển khai chính xác một số trong số chúng trong phiên bản 9 (ví dụ: DOMNodeInserted)

  • WebKit không hỗ trợ DOMAttrModified (xem lỗi webkit 8191 và cách giải quyết)

  • "sự kiện tên đột biến", tức là DOMElementNameChanged và DOMAttributeNameChanged không được hỗ trợ trong Firefox (kể từ phiên bản 11) và có thể trong các trình duyệt khác.

Nguồn: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events


-2

giải pháp của tôi:

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

ví dụ:

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

function processMoreLessButton(){
//some logic
}

5
Bạn nên nói với mọi người rằng bạn đã sử dụng mã gốc của jQuery, nó sẽ truyền cảm hứng cho sự tự tin hơn;)
aemonge

1
"giải pháp của tôi". Thần kinh trên anh chàng này.
André Silva

@ AndréSilva Có lẽ anh ấy đã viết jQuery. : O
Andrew
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.