我试图在另一个画布上添加一个画布-我如何使这个函数等待开始,直到第一个画布被创建?

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

当前回答

这是为那些在Chrome控制台上运行代码而不是硬编码到html的人准备的。

上面User993683提供的代码将在您的控制台代码中工作。他/她的代码如下:

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

他/她补充说,它“需要在一个异步函数中。”如果你在Chrome的控制台中使用代码,那么实际上你不需要把它包装在一个函数中。它会像写的那样工作。您只需要将它放在代码中试图访问元素之前的位置,以确保它存在。

唯一需要注意的是,它不适用于在其他情况下偶尔出现的元素。否则,如果元素从未下载,它将无限循环,您将不得不关闭浏览器来停止等待。只对您确定会出现的元素使用它。

我的公司的表单页面为每个案例号都有十几个或更多的字段需要填写。我每天在脚本数组中有数百个案例编号。当改变iFrame SRC和“onload”不工作在Chrome控制台脚本时,元素不同时加载。所以这个方法对我来说是天赐之物,它每天为我节省了至少45分钟,而不是因为加载时间的波动而在这里等10秒或在那里等30秒。

我所做的唯一改变是“getElementById”而不是一般的“querySelector”,因为我需要的所有元素都有ID。

while(!document.getElementById("myFrame").contentWindow.document.getElementById('someDocID')) {
      await new Promise(r => setTimeout(r, 500));
    }
// After completing the wait above it is now safe to access the element
document.getElementById("myFrame").contentWindow.document.getElementById('someDocID'
).innerText = "Smith, John R";
// and now click the submit button then change the SRC to a fresh form, and use
//*emphasized text* the code again to wait for it to fully load

我向监控器道歉,但我添加了这个作为回答,因为在对控制台脚本进行了几个月的研究并等待元素加载之后,user993683关于函数的评论最终使我意识到控制台脚本不需要此代码的函数。我在这里的目标只是让其他consoler脚本用户不必像我一样经历同样的学习曲线。

其他回答

如果你有权限访问创建画布的代码,只需在画布创建后调用函数即可。

如果您无法访问该代码(例如。如果它是第三方代码,如谷歌maps),那么你可以做的是在一个区间内测试是否存在:

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

但注意-很多时候第三方代码有一个选项来激活你的代码(通过回调或事件触发)当它完成加载。你可以把函数放在这里。区间解实际上是一个糟糕的解,只有在其他方法都不起作用的情况下才应该使用。

也许我有点晚了:),但这里有一个很好的和简短的解决方案,由chrisjhoughton,它允许执行回调函数当等待结束。

https://gist.github.com/chrisjhoughton/7890303

var waitForEl = function(selector, callback) {
  if (jQuery(selector).length) {
    callback();
  } else {
    setTimeout(function() {
      waitForEl(selector, callback);
    }, 100);
  }
};

waitForEl(selector, function() {
  // work the magic
});

如果你需要将参数传递给回调函数,你可以这样使用它:

waitForEl("#" + elDomId, () => callbackFunction(param1, param2));

但是要小心!默认情况下,这个解决方案会陷入一个无限循环的陷阱。

在GitHub线程中还提供了对topicstarter建议的几个改进。

享受吧!

您可以通过设置超时来检查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);

在requestAnimationFrame中中继比在setTimeout中更好。这是我在es6模块和使用承诺的解决方案。

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
  }

纯js和承诺:

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

这是对杰米·哈伯的回答的一个小小的改进

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

使用方法:

checkElement('.myElement').then((selector) => {
  console.log(selector);
});