2013-04-22 18 views
61

我想添加一個畫布在另一個畫布上 - 我如何讓這個函數等待開始,直到第一個畫布創建?使函數等待,直到元素存在

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

當您單擊創建畫布時,運行該函數或觸發一個運行該函數的處理程序的事件。當元素變得可用時,沒有內置的跨瀏覽器事件。 – 2013-04-22 14:18:44

+0

可能重複的[如何等到一個元素存在?](http://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists) – user2284570 2014-10-12 19:59:33

回答

132

如果您有權訪問創建畫布的代碼 - 只需在創建畫布後直接調用該函數即可。

如果該代碼沒有訪問那麼你可以做的是測試中存在的區間(例如,如果它是一個第三方代碼,如谷歌地圖):

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

不過需要注意的 - 很多時候,第三方代碼有一個選項可以在完成加載時激活代碼(通過回調或事件觸發)。這可能是你可以放置你的功能的地方。間隔解決方案實際上是一個糟糕的解決方案,只有在沒有其他方法可行的情況下才能使用。

+0

我用setTimeout來運行我的腳本之後點擊感謝 – Steven 2013-04-26 00:46:58

+0

完美的解決方案,用於angularjs typeahead。感謝您指導我正確的方向! – JuanTrev 2014-10-27 00:02:01

+1

在將一些其他東西放在那裏之前,等待由Ajax創建的東西的絕佳解決方案。非常感謝。 – Countzero 2015-11-24 09:13:51

2

這很簡單 - 只是不調用這個函數,直到你已經創建畫布(即該click處理程序中做到這一點)。

1

您可以通過設置超時直到它已經在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); 
14

根據您需要支持哪些瀏覽器,還有的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 
}); 

注:我自己沒有測試過這個代碼,但這是一般的想法。

你可以很容易地擴展它,只搜索改變的DOM部分。爲此,請使用mutations參數,它是一個MutationRecord對象的數組。

2

最好在​​中繼電比在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 
    } 
+0

'未捕獲TypeError:無法讀取屬性'然後'未定義' – 2017-10-23 18:44:50

+0

我想我在新的諾言之前錯過了一個回報。 – ncubica 2017-10-23 19:22:16

+0

這是比所有周期性的基於定時器的檢查更好的解決方案。 – 2018-02-09 19:35:10

2

這隻有在現代瀏覽器的工作,但我覺得它更容易只需使用一個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) { 
    while (document.querySelector(selector) === null) { 
     await rafAsync() 
    } 
    return true; 
} 

使用

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

更先進的方法來等待元素:

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

注意,此代碼將需要包裝在async function