如何等待一个元素存在?

我正在做一个Chrome扩展,我想知道:什么时候发现一个元素的最佳方式是什么? 使用普通的JavaScript,间隔,检查,直到存在一个元素,或者jQuery有一些简单的方法来做到这一点?

由于性能问题, DOMNodeInserted与其他DOM突变事件一起被弃用 – 推荐的方法是使用MutationObserver观察DOM。 它只在新的浏览器中被支持,所以当MutationObserver不可用的时候,你应该回到DOMNodeInserted

 var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (!mutation.addedNodes) return for (var i = 0; i < mutation.addedNodes.length; i++) { // do things to your newly added nodes here var node = mutation.addedNodes[i] } }) }) observer.observe(document.body, { childList: true , subtree: true , attributes: false , characterData: false }) // stop watching using: observer.disconnect() 

我遇到了同样的问题,所以我继续为它写一个插件 。

$(selector).waitUntilExists(function);

码:

 ;(function ($, window) { var intervals = {}; var removeListener = function(selector) { if (intervals[selector]) { window.clearInterval(intervals[selector]); intervals[selector] = null; } }; var found = 'waitUntilExists.found'; /** * @function * @property {object} jQuery plugin which runs handler function once specified * element is inserted into the DOM * @param {function|string} handler * A function to execute at the time when the element is inserted or * string "remove" to remove the listener from the given selector * @param {bool} shouldRunHandlerOnce * Optional: if true, handler is unbound after its first invocation * @example jQuery(selector).waitUntilExists(function); */ $.fn.waitUntilExists = function(handler, shouldRunHandlerOnce, isChild) { var selector = this.selector; var $this = $(selector); var $elements = $this.not(function() { return $(this).data(found); }); if (handler === 'remove') { // Hijack and remove interval immediately if the code requests removeListener(selector); } else { // Run the handler on all found elements and mark as found $elements.each(handler).data(found, true); if (shouldRunHandlerOnce && $this.length) { // Element was found, implying the handler already ran for all // matched elements removeListener(selector); } else if (!isChild) { // If this is a recurring search or if the target has not yet been // found, create an interval to continue searching for the target intervals[selector] = window.setInterval(function () { $this.waitUntilExists(handler, shouldRunHandlerOnce, true); }, 500); } } return $this; }; }(jQuery, window)); 

这是等待显示元素的核心JavaScript函数。

参数:

  1. select器:这个function寻找元素$ {selector}
  2. time:这个函数检查每个$ {time}毫秒是否存在这个元素。

     function waitForElementToDisplay(selector, time) { if(document.querySelector(selector)!=null) { alert("The element is displayed, you can put your code instead of this alert.") return; } else { setTimeout(function() { waitForElementToDisplay(selector, time); }, time); } } 

例如,设置selector =“#div1”和time = 5000将每5000毫秒查找一次id =“div1”的HTML标签。

您可以侦听DOMNodeInsertedDOMSubtreeModified事件,只要将新元素添加到DOM,就会DOMSubtreeModified事件。

还有一个LiveQuery jQuery插件,可以检测何时创build一个新元素:

 $("#future_element").livequery(function(){ //element created }); 

你可以做

 $('#yourelement').ready(function() { }); 

请注意,这只有在从服务器请求元素出现在DOM中时才有效。 如果元素是通过JavaScriptdynamic添加的,则不起作用,您可能需要查看其他答案。

我用这种方法等待一个元素出现,所以我可以执行其他function。

比方说doTheRestOfTheStuff(parameters)函数只能在ID为the_Element_ID的元素出现或加载完成后调用,我们可以使用,

 var existCondition = setInterval(function() { if ($('#the_Element_ID').length) { console.log("Exists!"); clearInterval(existCondition); doTheRestOfTheStuff(parameters); } }, 100); // check every 100ms 

怎么样的插入查询库?

在创build元素时,使用CSSanimationcallback函数附加到指定的select器来运行callback函数。 这个方法允许在创build元素时运行callback,而不仅仅是第一次。

来自github:

非DOM事件的方式来捕捉节点出现。 它使用select器。

这不仅仅是为了更广泛的浏览器支持,它可以比DOMMutationObserver更好。

为什么?

  • 由于DOM事件减慢了浏览器,而且不插入查询
  • 因为DOM突变观察器的浏览器支持比插入查询less
  • 因为使用插入查询,您可以使用select器过滤DOM更改,而无需性能开销!

广泛的支持!

IE10 +和其他大部分(包括手机)

这里有一个作为MutationObserver的简单包装的函数。 唯一的要求是浏览器支持MutationObserver; 没有依赖JQuery。 运行下面的代码片段来查看一个工作示例。

 function waitForMutation(parentNode, isMatchFunc, handlerFunc, observeSubtree, disconnectAfterMatch) { var defaultIfUndefined = function(val, defaultVal) { return (typeof val === "undefined") ? defaultVal : val; }; observeSubtree = defaultIfUndefined(observeSubtree, false); disconnectAfterMatch = defaultIfUndefined(disconnectAfterMatch, false); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes) { for (var i = 0; i < mutation.addedNodes.length; i++) { var node = mutation.addedNodes[i]; if (isMatchFunc(node)) { handlerFunc(node); if (disconnectAfterMatch) observer.disconnect(); }; } } }); }); observer.observe(parentNode, { childList: true, attributes: false, characterData: false, subtree: observeSubtree }); } // Example waitForMutation( // parentNode: Root node to observe. If the mutation you're looking for // might not occur directly below parentNode, pass 'true' to the // observeSubtree parameter. document.getElementById("outerContent"), // isMatchFunc: Function to identify a match. If it returns true, // handlerFunc will run. // MutationObserver only fires once per mutation, not once for every node // inside the mutation. If the element we're looking for is a child of // the newly-added element, we need to use something like // node.querySelector() to find it. function(node) { return node.querySelector(".foo") !== null; }, // handlerFunc: Handler. function(node) { var elem = document.createElement("div"); elem.appendChild(document.createTextNode("Added node (" + node.innerText + ")")); document.getElementById("log").appendChild(elem); }, // observeSubtree true, // disconnectAfterMatch: If this is true the hanlerFunc will only run on // the first time that isMatchFunc returns true. If it's false, the handler // will continue to fire on matches. false); // Set up UI. Using JQuery here for convenience. $outerContent = $("#outerContent"); $innerContent = $("#innerContent"); $("#addOuter").on("click", function() { var newNode = $("<div><span class='foo'>Outer</span></div>"); $outerContent.append(newNode); }); $("#addInner").on("click", function() { var newNode = $("<div><span class='foo'>Inner</span></div>"); $innerContent.append(newNode); }); 
 .content { padding: 1em; border: solid 1px black; overflow-y: auto; } #innerContent { height: 100px; } #outerContent { height: 200px; } #log { font-family: Courier; font-size: 10pt; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <h2>Create some mutations</h2> <div id="main"> <button id="addOuter">Add outer node</button> <button id="addInner">Add inner node</button> <div class="content" id="outerContent"> <div class="content" id="innerContent"></div> </div> </div> <h2>Log</h2> <div id="log"></div> 

对于使用jQuery的一个简单的方法,我发现这个工作得很好:

  // Wait for element to exist. function elementLoaded(el, cb) { if ($(el).length) { // Element is now loaded. cb($(el)); } else { // Repeat every 500ms. setTimeout(function() { elementLoaded(el, cb) }, 500); } }; elementLoaded('.element-selector', function(el) { // Element is ready to use. el.click(function() { alert("You just clicked a dynamically inserted element"); }); }); 

这里我们简单地检查每个500ms,看看这个元素是否被加载,什么时候可以使用。

这对于将点击处理程序添加到已被dynamic添加到文档中的元素特别有用。

这里有一个纯Javascript函数,可以让你等待任何东西。 设置更长的时间间隔以占用更less的CPU资源。

 /** * @brief Wait for something to be ready before triggering a timeout * @param {callback} isready Function which returns true when the thing we're waiting for has happened * @param {callback} success Function to call when the thing is ready * @param {callback} error Function to call if we time out before the event becomes ready * @param {int} count Number of times to retry the timeout (default 300 or 6s) * @param {int} interval Number of milliseconds to wait between attempts (default 20ms) */ function waitUntil(isready, success, error, count, interval){ if (count === undefined) { count = 300; } if (interval === undefined) { interval = 20; } if (isready()) { success(); return; } // The call back isn't ready. We need to wait for it setTimeout(function(){ if (!count) { // We have run out of retries if (error !== undefined) { error(); } } else { // Try again waitUntil(isready, success, error, count -1, interval); } }, interval); } 

要调用这个,例如在jQuery中,使用如下所示:

 waitUntil(function(){ return $('#myelement').length > 0; }, function(){ alert("myelement now exists"); }, function(){ alert("I'm bored. I give up."); }); 

使用MutationObserver的更简洁的例子:

 new MutationObserver( mutation => { if (!mutation.addedNodes) return mutation.addedNodes.forEach( node => { // do stuff with node }) })