Pregunta Hacer que la función espere hasta que el elemento exista


Intento agregar un lienzo sobre otro lienzo. ¿Cómo puedo hacer que esta función espere hasta que se cree el primer lienzo?

function PaintObject(brush) {

    this.started = false;

    // get handle of the main canvas, as a DOM object, not as a jQuery Object. Context is unfortunately not yet
    // available in jquery canvas wrapper object.
    var mainCanvas = $("#" + brush).get(0);

    // Check if everything is ok
    if (!mainCanvas) {alert("canvas undefined, does not seem to be supported by your browser");}
    if (!mainCanvas.getContext) {alert('Error: canvas.getContext() undefined !');}

    // Get the context for drawing in the canvas
    var mainContext = mainCanvas.getContext('2d');
    if (!mainContext) {alert("could not get the context for the main canvas");}

    this.getMainCanvas = function () {
        return mainCanvas;
    }
    this.getMainContext = function () {
        return mainContext;
    }

    // Prepare a second canvas on top of the previous one, kind of second "layer" that we will use
    // in order to draw elastic objects like a line, a rectangle or an ellipse we adjust using the mouse
    // and that follows mouse movements
    var frontCanvas = document.createElement('canvas');
    frontCanvas.id = 'canvasFront';
    // Add the temporary canvas as a second child of the mainCanvas parent.
    mainCanvas.parentNode.appendChild(frontCanvas);

    if (!frontCanvas) {
        alert("frontCanvas null");
    }
    if (!frontCanvas.getContext) {
        alert('Error: no frontCanvas.getContext!');
    }
    var frontContext = frontCanvas.getContext('2d');
    if (!frontContext) {
        alert("no TempContext null");
    }

    this.getFrontCanvas = function () {
        return frontCanvas;
    }
    this.getFrontContext = function () {
        return frontContext;
    }

74
2018-04-22 14:17


origen


Respuestas:


Si tiene acceso al código que crea el lienzo, simplemente llame a la función inmediatamente después de crear el lienzo.

Si no tiene acceso a ese código (por ejemplo, si se trata de un código de terceros, como google maps), entonces lo que podría hacer es probar la existencia en un intervalo:

var checkExist = setInterval(function() {
   if ($('#the-canvas').length) {
      console.log("Exists!");
      clearInterval(checkExist);
   }
}, 100); // check every 100ms

Pero tenga en cuenta que muchas veces el código de terceros tiene una opción para activar su código (por devolución de llamada o activación de evento) cuando termina de cargarse. Ese puede ser el lugar donde puedes poner tu función. La solución de intervalo es realmente una mala solución y debe usarse solo si no funciona nada más.


164
2018-04-22 14:30



Dependiendo de qué navegador necesite admitir, existe la opción de MutationObserver.

Algo en la línea de esto debería hacer el truco:

// 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ótese bien No he probado este código yo mismo, pero esa es la idea general.

Puede extender esto fácilmente para buscar solo la parte del DOM que cambió. Para eso, usa el mutations argumento, es una variedad de MutationRecord objetos.


21
2018-02-04 20:45



Esto solo funcionará con los navegadores modernos, pero me resulta más fácil simplemente usar un then así que por favor prueba primero pero:

Código

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

O usando funciones de generador

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

Uso

checkElement('body') //use whichever selector you want
.then((element) => {
     console.info(element);
     //Do whatever you want now the element is there
});

9
2017-12-12 15:42



Puede verificar si el dom ya existe estableciendo un tiempo de espera hasta que ya se represente en el dom.

var panelMainWrapper = document.getElementById('panelMainWrapper');
setTimeout(function waitPanelMainWrapper() {
    if (document.body.contains(panelMainWrapper)) {
        $("#panelMainWrapper").html(data).fadeIn("fast");
    } else {
        setTimeout(waitPanelMainWrapper, 10);
    }
}, 10);

2
2017-09-26 07:10



Es mejor retransmitir en requestAnimationFrame que en un setTimeout. esta es mi solución en módulos es6 y el uso Promises.

es6, módulos y promesas:

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

2
2017-07-07 20:19



Es muy simple: simplemente no llame a esta función hasta que haya creado el lienzo (es decir, hágalo dentro de ese click entrenador de animales).


1
2018-04-22 14:19



Un enfoque más moderno para esperar elementos:

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

Tenga en cuenta que este código debería estar envuelto en un función asíncrona.


0
2018-02-03 22:48