6

ben teknik olarak konuşursak,Bir öğeye başvuruda bulunulduğunda, belgeye eklendiğinde nasıl tespit edilir? .</p> <pre><code>onceAppended(element, callback); </code></pre> <p><code>element</code> bir geçerli:

o kullanılacak olan çevre hakkında hiçbir şey bilmeyen bir JavaScript modülü, gelişmekte Ve ediyorum, ben bir sonraki işlevi uygulamak istiyoruz HTMLElement ve bu öğenin üst kısmı modül başlatılırken bilinmeyebilir. callback, sayfada element görüntülendiğinde tetiklenmesi gereken bir işlevdir.

Öğe, belgeye eklenmişse hemen çağrılmalıdır. element'un henüz eklenmemesi durumunda, belgesinde element görüntülendiğinde işlev tetiklenir.

element ek olayını DOMNodeInserted mutasyon olayı kullanarak algılayabiliriz. Ancak mutasyon olayları şimdi deprecated. Ve öyle görünüyor ki MutationObserver bu görevi halledemiyor, değil mi?

function onceAppended (element, callback) { 
    let el = element, 
     listener; 
    while (el.parentNode) 
     el = el.parentNode; 
    if (el instanceof Document) { 
     callback(); 
     return; 
    } 
    if (typeof MutationObserver === "undefined") { // use deprecated method 
     element.addEventListener("DOMNodeInserted", listener = (ev) => { 
      if (ev.path.length > 1 && ev.path[ev.length - 2] instanceof Document) { 
       element.removeEventListener("DOMNodeInserted", listener); 
       callback(); 
      } 
     }, false); 
     return; 
    } 
    // Can't MutationObserver detect append event for the case? 
} 

bu konuda herhangi bir yardım için şimdiden teşekkür ederiz:

İşte benim kod parçacığı olduğunu!

+0

@wOxxOm Konuyu biliyorsanız, işlevimi tamamlayabilir misiniz? Bunu MutationObservers ile uygulamaya çalıştım ve sonuç bulunamadı. – ZitRo

+0

MutationObserver'ın bu görevi neden başaramadığını anlamıyorum. Ne denedin? Her eklenen düğümü belgelemek ve kontrol etmek için gözlemciyi eklemeniz gerekecek. Yine de çok etkisiz olacak. Yani belki de HTMLElement ve Node prototiplerinde “appendChild”, “replaceChild” ve diğer ilgili işlevleri geçersiz kılabilirsiniz. – wOxxOm

+0

Ayrıca bakınız [DOMNodeInserted'e alternatif] (http://stackoverflow.com/a/10343915) – wOxxOm

cevap

0

wOxxOm'un Alternative to DOMNodeInserted hakkındaki ipucunu ve skyline3000'in yanıtını alarak bu görev çözümünün iki yöntemini geliştirdim. İlk yöntem onceAppended hızlıdır, ancak callback'un tetiklenmesinden önce yaklaşık 25 ms'lik bir gecikme vardır. İkinci yöntem, eleman eklendikten hemen sonra callback'u tetikler, ancak uygulamada birçok öğe eklendiğinde yavaş olabilir.

Çözüm, GitHub ve npmES6 modülünde kullanılabilir. Aşağıda, iki çözümün düz kodu bulunmaktadır.

Yöntem 1 (CSS kullanarak animasyonlar)

function useDeprecatedMethod (element, callback) { 
    let listener; 
    return element.addEventListener(`DOMNodeInserted`, listener = (ev) => { 
     if (ev.path.length > 1 && ev.path[ev.length - 2] instanceof Document) { 
      element.removeEventListener(`DOMNodeInserted`, listener); 
      callback(); 
     } 
    }, false); 
} 

function isAppended (element) { 
    while (element.parentNode) 
     element = element.parentNode; 
    return element instanceof Document; 
} 

/** 
* Method 1. Asynchronous. Has a better performance but also has an one-frame delay after element is 
* appended (around 25ms delay) of callback triggering. 
* This method is based on CSS3 animations and animationstart event handling. 
* Fires callback once element is appended to the document. 
* @author ZitRo (https://github.com/ZitRos) 
* @see https://stackoverflow.com/questions/38588741/having-a-reference-to-an-element-how-to-detect-once-it-appended-to-the-document (StackOverflow original question) 
* @see https://github.com/ZitRos/dom-onceAppended (Home repository) 
* @see https://www.npmjs.com/package/dom-once-appended (npm package) 
* @param {HTMLElement} element - Element to be appended 
* @param {function} callback - Append event handler 
*/ 
export function onceAppended (element, callback) { 

    if (isAppended(element)) { 
     callback(); 
     return; 
    } 

    let sName = `animation`, pName = ``; 

    if (// since DOMNodeInserted event is deprecated, we will try to avoid using it 
     typeof element.style[sName] === `undefined` 
     && (sName = `webkitAnimation`) && (pName = "-webkit-") 
      && typeof element.style[sName] === `undefined` 
     && (sName = `mozAnimation`) && (pName = "-moz-") 
      && typeof element.style[sName] === `undefined` 
     && (sName = `oAnimation`) && (pName = "-o-") 
      && typeof element.style[sName] === `undefined` 
    ) { 
     return useDeprecatedMethod(element, callback); 
    } 

    if (!document.__ONCE_APPENDED) { 
     document.__ONCE_APPENDED = document.createElement('style'); 
     document.__ONCE_APPENDED.textContent = `@${ pName }keyframes ONCE_APPENDED{from{}to{}}`; 
     document.head.appendChild(document.__ONCE_APPENDED); 
    } 

    let oldAnimation = element.style[sName]; 
    element.style[sName] = `ONCE_APPENDED`; 
    element.addEventListener(`animationstart`,() => { 
     element.style[sName] = oldAnimation; 
     callback(); 
    }, true); 

} 

Yöntem 2 (MutationObserver kullanılarak) bu yöntemlerden

function useDeprecatedMethod (element, callback) { 
    let listener; 
    return element.addEventListener(`DOMNodeInserted`, listener = (ev) => { 
     if (ev.path.length > 1 && ev.path[ev.length - 2] instanceof Document) { 
      element.removeEventListener(`DOMNodeInserted`, listener); 
      callback(); 
     } 
    }, false); 
} 

function isAppended (element) { 
    while (element.parentNode) 
     element = element.parentNode; 
    return element instanceof Document; 
} 

/** 
* Method 2. Synchronous. Has a lower performance for pages with a lot of elements being inserted, 
* but triggers callback immediately after element insert. 
* This method is based on MutationObserver. 
* Fires callback once element is appended to the document. 
* @author ZitRo (https://github.com/ZitRos) 
* @see https://stackoverflow.com/questions/38588741/having-a-reference-to-an-element-how-to-detect-once-it-appended-to-the-document (StackOverflow original question) 
* @see https://github.com/ZitRos/dom-onceAppended (Home repository) 
* @see https://www.npmjs.com/package/dom-once-appended (npm package) 
* @param {HTMLElement} element - Element to be appended 
* @param {function} callback - Append event handler 
*/ 
export function onceAppendedSync (element, callback) { 

    if (isAppended(element)) { 
     callback(); 
     return; 
    } 

    const MutationObserver = 
     window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 

    if (!MutationObserver) 
     return useDeprecatedMethod(element, callback); 

    const observer = new MutationObserver((mutations) => { 
     if (mutations[0].addedNodes.length === 0) 
      return; 
     if (Array.prototype.indexOf.call(mutations[0].addedNodes, element) === -1) 
      return; 
     observer.disconnect(); 
     callback(); 
    }); 

    observer.observe(document.body, { 
     childList: true, 
     subtree: true 
    }); 

} 

ikisi de sadece fonksiyon isimleri farklıdır, aynı kullanım, var

import { onceAppended } from "dom-once-appended"; // or onceAppendedSync 

function myModule() { 
    let sampleElement = document.createElement("div"); 
    onceAppended(sampleElement,() => { // or onceAppendedSync 
     console.log(`Sample element is appended!`); 
    }); 
    return sampleElement; 
} 

// somewhere else in the sources (example) 
let element = myModule(); 
setTimeout(() => document.body.appendChild(element), 200); 
2

Maalesef DOMNodeInserted olduğu gibi bu tamamen aynı şekilde yapmak için hiçbir yolu yoktur Bir elemanın ebeveyn değiştiğinde MutationObserver olayların hiçbiri size haber çünkü. Bunun yerine, gözlemciyi document.body'a yerleştirmeniz ve eklenecek her bir düğümü işaretlemeniz gerekir. Herhangi bir düğüm eklendiğinde geri aramanızı çalıştırmak istiyorsanız, bu kolay. Belirli düğümler eklendiğinde sadece çalışmasını istiyorsanız, o noktalara bir yerde bir referans tutmak zorunda kalacaksınız.

let elements = []; 
elements[0] = document.createElement('div'); 
elements[1] = document.createElement('span'); 
elements[2] = document.createElement('p'); 
elements[3] = document.createElement('a'); 

const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 

const observer = new MutationObserver(function(mutations) { 
    // 'addedNodes' is an array of nodes that were appended to the DOM. 
    // Checking its length let's us know if we've observed a node being added 
    if (mutations[0].addedNodes.length > 0) { 

    // 'indexOf' let's us know if the added node is in our reference array 
    if (Array.prototype.indexOf.call(mutations[0].addedNodes[0], elements) > -1) { 

     // Run the callback function with a reference to the element 
     callback(mutations[0].addedNodes[0]); 
    } 
}); 

observer.observe(document.body, { 
    childList: true, 
    subtree: true 
}); 

function callback(element) { 
    console.log(element); 
} 

document.body.appendChild(elements[2]); // => '<p></p>' 
elements[2].appendChild(elements[3]); // => '<a></a>' 

Eğer geri arama document.body içinde herhangi bir yere eklenen düğümler için tetiklenir görebileceğiniz gibi. Herhangi bir eleman eklendiğinde callback()'un çalışmasını istiyorsanız, eğer elemanın referans dizisinde var ise ikinci kontrolden çıkın.

+0

Teşekkür ederiz! Bu yöntem görevi çözmek için yeterince iyidir, ancak bununla birlikte büyük eksileri performanstır. Sayfaya binlerce eleman eklendikten sonra (yeni bir tablo oluşturmak gibi) geri çağrıma bin kez denir. – ZitRo

İlgili konular