Make function wait until element exists

前端 未结 11 1846
一向
一向 2020-11-28 17:40

I\'m trying to add a canvas over another canvas – how can I make this function wait to start until the first canvas is created?

function PaintObject(brush) {         


        
相关标签:
11条回答
  • 2020-11-28 17:57

    Depending on which browser you need to support, there's the option of MutationObserver.

    EDIT: All major browsers support MutationObserver now.

    Something along the lines of this should do the trick:

    // callback executed when canvas was found
    function handleCanvas(canvas) { ... }
    
    // set up the mutation observer
    var observer = new MutationObserver(function (mutations, me) {
      // `mutations` is an array of mutations that occurred
      // `me` is the MutationObserver instance
      var canvas = document.getElementById('my-canvas');
      if (canvas) {
        handleCanvas(canvas);
        me.disconnect(); // stop observing
        return;
      }
    });
    
    // start observing
    observer.observe(document, {
      childList: true,
      subtree: true
    });
    

    N.B. I haven't tested this code myself, but that's the general idea.

    You can easily extend this to only search the part of the DOM that changed. For that, use the mutations argument, it's an array of MutationRecord objects.

    0 讨论(0)
  • 2020-11-28 18:01

    Here's a minor improvement over Jamie Hutber's answer

    const checkElement = async selector => {
      while ( document.querySelector(selector) === null) {
        await new Promise( resolve =>  requestAnimationFrame(resolve) )
      }
      return document.querySelector(selector); 
    };
    

    To use:

    checkElement('.myElement').then((selector) => {
      console.log(selector);
    });
    
    0 讨论(0)
  • 2020-11-28 18:01

    You can check if the dom already exists by setting a timeout until it is already rendered in the dom.

    var panelMainWrapper = document.getElementById('panelMainWrapper');
    setTimeout(function waitPanelMainWrapper() {
        if (document.body.contains(panelMainWrapper)) {
            $("#panelMainWrapper").html(data).fadeIn("fast");
        } else {
            setTimeout(waitPanelMainWrapper, 10);
        }
    }, 10);
    
    0 讨论(0)
  • 2020-11-28 18:03

    A more modern approach to waiting for elements:

    while(!document.querySelector(".my-selector")) {
      await new Promise(r => setTimeout(r, 500));
    }
    // now the element is loaded
    

    Note that this code would need to be wrapped in an async function.

    0 讨论(0)
  • 2020-11-28 18:06

    This will only work with modern browsers but I find it easier to just use a then so please test first but:

    Code

    function rafAsync() {
        return new Promise(resolve => {
            requestAnimationFrame(resolve); //faster than set time out
        });
    }
    
    function checkElement(selector) {
        if (document.querySelector(selector) === null) {
            return rafAsync().then(() => checkElement(selector));
        } else {
            return Promise.resolve(true);
        }
    }
    

    Or using generator functions

    async function checkElement(selector) {
        const querySelector = document.querySelector(selector);
        while (querySelector === null) {
            await rafAsync()
        }
        return querySelector;
    }  
    

    Usage

    checkElement('body') //use whichever selector you want
    .then((element) => {
         console.info(element);
         //Do whatever you want now the element is there
    });
    
    0 讨论(0)
  • 2020-11-28 18:07

    Is better to relay in requestAnimationFrame than in a setTimeout. this is my solution in es6 modules and using Promises.

    es6, modules and promises:

    // onElementReady.js
    const onElementReady = $element => (
      new Promise((resolve) => {
        const waitForElement = () => {
          if ($element) {
            resolve($element);
          } else {
            window.requestAnimationFrame(waitForElement);
          }
        };
        waitForElement();
      })
    );
    
    export default onElementReady;
    
    // in your app
    import onElementReady from './onElementReady';
    
    const $someElement = document.querySelector('.some-className');
    onElementReady($someElement)
      .then(() => {
        // your element is ready
      }
    

    plain js and promises:

    var onElementReady = function($element) {
      return new Promise((resolve) => {
        var waitForElement = function() {
          if ($element) {
            resolve($element);
          } else {
            window.requestAnimationFrame(waitForElement);
          }
        };
        waitForElement();
      })
    };
    
    var $someElement = document.querySelector('.some-className');
    onElementReady($someElement)
      .then(() => {
        // your element is ready
      });
    
    0 讨论(0)
提交回复
热议问题