Подтвердить что ты не робот

Сделать функцию до тех пор, пока не будет существовать элемент

Я пытаюсь добавить холст поверх другого холста - как я могу заставить эту функцию ждать, пока не будет создано первое полотно?

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;
    }
4b9b3361

Ответ 1

Если у вас есть доступ к коду, который создает холст, просто вызовите функцию прямо после создания холста.

Если у вас нет доступа к этому коду (например, если это сторонний код, такой как карты Google), то что вы можете сделать, это проверить наличие в интервале:

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

Но обратите внимание: во многих случаях сторонний код имеет возможность активировать ваш код (путем обратного вызова или запуска события), когда он заканчивает загрузку. Это может быть место, где вы можете поставить свою функцию. Решение интервалов действительно плохое решение и должно использоваться только в том случае, если ничего не работает.

Ответ 2

В зависимости от того, какой браузер вам нужно поддерживать, выберите MutationObserver.

Что-то вроде этого должно сделать трюк:

// 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. Я сам не тестировал этот код, но это общая идея.

Вы можете легко расширить это, чтобы искать только часть измененной части DOM. Для этого используйте аргумент mutations, это массив объектов MutationRecord.

Ответ 3

Это будет работать только с современными браузерами, но я считаю, что проще использовать then поэтому сначала проверьте, но:

Код

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

Или используя функции генератора

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

использование

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

Ответ 4

Более современный подход к ожиданию элементов:

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

Обратите внимание, что этот код должен быть заключен в асинхронную функцию.

Ответ 5

Здесь небольшое улучшение по сравнению с ответом Джейми Хатбер

const checkElement = async selector => {

while ( document.querySelector(selector) === null) {
    await new Promise( resolve =>  requestAnimationFrame(resolve) )
}

return document.querySelector(selector); };

Ответ 6

Лучше передать в requestAnimationFrame чем в setTimeout. Это моё решение в модулях es6 и использовании Promises.

es6, модули и обещания:

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

Ответ 7

Вы можете проверить, существует ли dom уже, установив таймаут, пока он уже не будет отображаться в dom.

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

Ответ 8

Это очень просто - просто не вызывайте эту функцию до тех пор, пока вы не создадите холст (т.е. сделайте это внутри этого обработчика click).

Ответ 9

Вот решение с использованием наблюдаемых.

waitForElementToAppear(elementId) {                                          

    return Observable.create(function(observer) {                            
            var el_ref;                                                      
            var f = () => {                                                  
                el_ref = document.getElementById(elementId);                 
                if (el_ref) {                                                
                    observer.next(el_ref);                                   
                    observer.complete();                                     
                    return;                                                  
                }                                                            
                window.requestAnimationFrame(f);                             
            };                                                               
            f();                                                             
        });                                                                  
}                                                                            

Теперь вы можете написать

waitForElementToAppear(elementId).subscribe(el_ref => doSomethingWith(el_ref);