【问题标题】:How to wait until an element exists?如何等到元素存在?
【发布时间】:2018-10-23 13:17:57
【问题描述】:

我正在开发 Chrome 中的扩展程序,我想知道:找出元素何时存在的最佳方法是什么?使用纯 javascript,间隔检查直到元素存在,还是 jQuery 有一些简单的方法来做到这一点?

【问题讨论】:

  • 看起来今天这里的每个选项(包括来自 cmets)要么已过时,要么不完整。他们没有充分考虑@hughsk 的出色输入,即兼容性论点。同时,我认为,我建议简单地使用 Brandon 对 Ryan 的答案的更新,以获得一般的简单性和更少的开销风险。
  • MutationObserver > DOM Mutation Events > setTimeout.
  • 不是我的立场。 setTimeout 兼容,易于实现,易于维护,并且开销可以忽略不计。
  • (……我数不清)
  • 有3种人:会数的人和不会数的人。 ;P

标签: javascript jquery google-chrome google-chrome-extension


【解决方案1】:

这是一个使用MutationObserver api 的简单解决方案。

  1. 没有jQuery
  2. 没有Timer
  3. 没有第三方库
  4. Promise 基于 async/await

我已经在几个项目中使用过它。

function waitForElm(selector) {
    return new Promise(resolve => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                resolve(document.querySelector(selector));
                observer.disconnect();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
}

使用它:

waitForElm('.some-class').then((elm) => {
    console.log('Element is ready');
    console.log(elm.textContent);
});

或者使用异步/等待:

const elm = await waitForElm('.some-class');

【讨论】:

  • 这很好!它最酷的部分是您也可以将它与async / await 一起使用。您还可以通过执行mutations.addedNodes.find(node => node.matchesSelector("...")) 来获得更多性能
  • @mattsven 好点!仅检查突变中的节点比执行 document.querySelector 更高效。
  • 这太棒了,谢谢。但是 observer 常量中的 mutations 参数的目的是什么?
  • @RalphDavidAbernathy,你是对的,mutations 参数没有在代码中使用,可以安全删除。它有很多关于什么是变异的有用信息。我把它放在那里以防你需要访问它。
【解决方案2】:

简单的 Javascript。

cont elementExist = setInterval(() => {
    var elm = document.getElementById("elementId")
    if (elm!=null)
         // call your function here to do something
        clearInterval(elementExist);
    }
}, 100);

注意:这将阻止其他执行

【讨论】:

    【解决方案3】:

    更新

    下面有一个适用于 Promise 的更新版本。如果达到特定的尝试次数,它也会“停止”。

      function _waitForElement(selector, delay = 50, tries = 250) {
        const element = document.querySelector(selector);
    
        if (!window[`__${selector}`]) {
          window[`__${selector}`] = 0;
        }
    
        function _search() {
          return new Promise((resolve) => {
            window[`__${selector}`]++;
            console.log(window[`__${selector}`]);
            setTimeout(resolve, delay);
          });
        }
    
        if (element === null) {
          if (window[`__${selector}`] >= tries) {
            window[`__${selector}`] = 0;
            return Promise.reject(null);
          }
    
          return _search().then(() => _waitForElement(selector));
        } else {
          return Promise.resolve(element);
        }
      }
    

    使用非常简单,与await 一起使用只需确保您在 async函数:

    const start = (async () => {
      const $el = await _waitForElement(`.my-selector`);
      console.log($el);
    })();
    

    过时的版本

    只需添加您想要的选择器。找到元素后,您可以在回调函数中访问。

    const waitUntilElementExists = (selector, callback) => {
    const el = document.querySelector(selector);
    
    if (el){
        return callback(el);
    }
    
    setTimeout(() => waitUntilElementExists(selector, callback), 500);
    }
    
    waitUntilElementExists('.wait-for-me', (el) => console.log(el));
    

    【讨论】:

    • PossessWithin 同意,这是一个非常干净的解决方案,对我有用。
    • 这个答案适用于 IE8-10 以及现代浏览器。主要问题是,如果元素不存在,它将继续运行 - 所以最好什么时候确定元素会在那里。否则,您可以添加一个计数器。
    • 非常适合我
    • 像魅力一样工作!!
    • 您最有可能被否决,因为此处存在类似的答案,并且它们于 2012 年和 2015 年发布,例如stackoverflow.com/a/29754070/2103767
    【解决方案4】:

    下面的observe 函数将允许您通过选择器监听元素。

    在以下示例中,经过 2 秒后,.greeting 将插入到 .container 中。由于我们正在监听这个元素的插入,我们可以有一个在插入时触发的回调。

    const observe = (selector, callback, targetNode = document.body) =>
      new MutationObserver(mutations => [...mutations]
        .flatMap((mutation) => [...mutation.addedNodes])
        .filter((node) => node.matches && node.matches(selector))
        .forEach(callback))
      .observe(targetNode, { childList: true, subtree: true });
    
    const createGreeting = () => {
      const el = document.createElement('DIV');
      el.textContent = 'Hello World';
      el.classList.add('greeting');
      return el;
    };
    
    const container = document.querySelector('.container');
    
    observe('.greeting', el => console.log('I have arrived!', el), container);
    
    new Promise(res => setTimeout(() => res(createGreeting()), 2000))
      .then(el => container.appendChild(el));
    html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
    body { display: flex; }
    .container { display: flex; flex: 1; align-items: center; justify-content: center; }
    .greeting { font-weight: bold; font-size: 2em; }
    <div class="container"></div>

    【讨论】:

      【解决方案5】:

      我开发了一个受Jamie Hutber's启发的答案。

      这是一个基于承诺的函数,您可以在其中设置:

      • 最大尝试次数 - 默认10
      • 以毫秒为单位的延迟 - 默认100 ms

      因此,默认情况下,它会等待 1 秒,直到元素出现在 DOM 上。

      如果它没有显示出来,它将返回一个 promise.rejectnull,以便您可以根据自己的意愿处理错误。

      代码

      
      function waitForElement(selector, delay = 1000, tries = 10) {
        const element = document.querySelector(selector);
      
        // creates a local variable w/ the name of the selector to keep track of all tries
        if (!window[`__${selector}`]) {
          window[`__${selector}`] = 0;
        }
      
        function _search() {
          return new Promise((resolve) => {
            window[`__${selector}`]++;
            console.log(window[`__${selector}`]);
            setTimeout(resolve, delay);
          });
        }
      
        //element not found, retry
        if (element === null) {
          if (window[`__${selector}`] >= tries) {
            window[`__${selector}`] = 0;
            return Promise.reject(null);
          }
      
          return _search().then(() => waitForElement(selector));
        } else {
          return Promise.resolve(element);
        }
      }
      

      用法

      async function wait(){
          try{
              const $el = await waitForElement(".llama");
              console.log($el);
          } catch(err){
              console.error("Timeout - couldn't find element.")
          }
      } 
      
      wait();
      

      在上面的示例中,它将等待选择器.llama。您可以在 StackoverFlow 的控制台上添加更大的延迟并在此处进行测试。

      只需将 llama 类添加到 DOM 上的任何元素即可。

      【讨论】:

        【解决方案6】:

        你可以试试这个:

        const wait_until_element_appear = setInterval(() => {
            if ($(element).length !== 0) {
                // some code
                clearInterval(wait_until_element_appear);
            }
        }, 0);
        

        这个解决方案非常适合我

        【讨论】:

        • 简洁明了。您可能想要增加间隔,即。到 500 毫秒,并可能添加一个重试计数器以避免无限循环。
        【解决方案7】:

        这是一个等待元素显示的核心 JavaScript 函数(嗯,它插入到 DOM 中更准确)。

        // Call the below function
        waitForElementToDisplay("#div1",function(){alert("Hi");},1000,9000);
        
        function waitForElementToDisplay(selector, callback, checkFrequencyInMs, timeoutInMs) {
          var startTimeInMs = Date.now();
          (function loopSearch() {
            if (document.querySelector(selector) != null) {
              callback();
              return;
            }
            else {
              setTimeout(function () {
                if (timeoutInMs && Date.now() - startTimeInMs > timeoutInMs)
                  return;
                loopSearch();
              }, checkFrequencyInMs);
            }
          })();
        }
        

        此调用将每 1000 毫秒查找其 id="div1" 的 HTML 标记。如果找到该元素,它将显示警告消息 Hi。如果在 9000 毫秒后没有找到任何元素,此函数将停止执行。

        参数:

        1. selector: String : 这个函数寻找元素 ${selector}。
        2. callback: Function : 这是一个在找到元素时调用的函数。
        3. checkFrequencyInMs: Number : 此函数每 ${checkFrequencyInMs} 毫秒检查一次该元素是否存在。
        4. timeoutInMs:号码:可选。此函数在 ${timeoutInMs} 毫秒后停止查找元素。

        注意: 选择器在https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

        【讨论】:

        【解决方案8】:

        DOMNodeInserted 与其他 DOM 突变事件一起被弃用,因为性能问题 - 推荐的方法是使用 MutationObserver 来观察 DOM。不过,它仅在较新的浏览器中受支持,因此当 MutationObserver 不可用时,您应该回退到 DOMNodeInserted

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

        【讨论】:

        • 我一直觉得 MutationObserver api 有点复杂,所以我构建了一个库 arrive.js,以提供一个更简单的 api 来监听元素的创建/删除。
        • 我推荐使用@UzairFarooq优秀库github.com/uzairfarooq/arrive
        • 需要注意两点:(1) 最好使用if (mutation.addedNodes.length),因为if (mutation.addedNodes) 即使它是一个空数组,仍然会返回true。 (2) 你不能做mutation.addedNodes.forEach(),因为 addedNodes 是一个 nodeList,你不能用 forEach 遍历 nodeList。有关此问题的解决方案,请参阅toddmotto.com/ditch-the-array-foreach-call-nodelist-hack
        • 你能举例说明如何使用它吗?当 DOM 元素存在时,不知道在哪里放置我想要执行的 jquery 选择器或代码。
        • @Superdooperhero 我用简单的例子做了一个回答。检查。 stackoverflow.com/a/57395241/6542186
        【解决方案9】:

        如果您有异步 dom 更改,此函数会检查 DOM 元素(时间限制以秒为单位),对于 DOM 及其基于 Promise 的内容不会很繁重:)

        function getElement(selector, i = 5) {
          return new Promise(async (resolve, reject) => {
            if(i <= 0) return reject(`${selector} not found`);
            const elements = document.querySelectorAll(selector);
            if(elements.length) return resolve(elements);
            return setTimeout(async () => await getElement(selector, i-1), 1000);
          })
        }
        
        // Now call it with your selector
        
        try {
          element = await getElement('.woohoo');
        } catch(e) { // catch the e }
        
        //OR
        
        getElement('.woohoo', 5)
        .then(element => { // do somthing with the elements })
        .catch(e => { // catch the error });
        

        【讨论】:

        • 我测试你的解决方案,如果 i = 5 并且找到元素,它会返回元素;如果 i
        • Never pass an async function as the executor to new Promise!同样,您传递给setTimeout 的函数表达式没有理由是async。尽管您应该只将setTimeout 包装在new Promise 中,但无论如何都没有。
        • 事实上,这甚至都行不通,因为如果第一次尝试没有找到该元素,您永远不会解决返回承诺。
        【解决方案10】:

        我通常将这个 sn-p 用于跟踪代码管理器:

        <script>
        (function exists() {
          if (!document.querySelector('<selector>')) {
            return setTimeout(exists);
          }
          // code when element exists
        })();  
        </script>
        

        【讨论】:

          【解决方案11】:

          返回 Promise 并允许使用超时的解决方案(兼容 IE 11+)。

          对于单个元素(元素类型):

          "use strict";
          
          function waitUntilElementLoaded(selector) {
              var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
          
              var start = performance.now();
              var now = 0;
          
              return new Promise(function (resolve, reject) {
                  var interval = setInterval(function () {
                      var element = document.querySelector(selector);
          
                      if (element instanceof Element) {
                          clearInterval(interval);
          
                          resolve();
                      }
          
                      now = performance.now();
          
                      if (now - start >= timeout) {
                          reject("Could not find the element " + selector + " within " + timeout + " ms");
                      }
                  }, 100);
              });
          }
          

          对于多个元素(类型 NodeList):

          "use strict";
          
          function waitUntilElementsLoaded(selector) {
              var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
          
              var start = performance.now();
              var now = 0;
          
              return new Promise(function (resolve, reject) {
                  var interval = setInterval(function () {
                      var elements = document.querySelectorAll(selector);
          
                      if (elements instanceof NodeList) {
                          clearInterval(interval);
          
                          resolve(elements);
                      }
          
                      now = performance.now();
          
                      if (now - start >= timeout) {
                          reject("Could not find elements " + selector + " within " + timeout + " ms");
                      }
                  }, 100);
              });
          }
          

          例子:

          waitUntilElementLoaded('#message', 800).then(function(element) {
              // element found and available
          
              element.innerHTML = '...';
          }).catch(function() {
              // element not found within 800 milliseconds
          });
          
          waitUntilElementsLoaded('.message', 10000).then(function(elements) {
              for(const element of elements) {
                  // ....
              }
          }).catch(function(error) {
              // elements not found withing 10 seconds
          });
          

          适用于元素列表和单个元素。

          【讨论】:

          • 我最喜欢的解决方案!为什么要查看element instanceof HTMLElement?除了nullHTMLElement 之外,它还能是什么?
          • 你提出了一个有趣的观点。我应该改用Element 来扩大范围(固定)。我只是进行检查,因为我想确保变量element 具有属性innerHTML 作为Element MDN documentation states。如果您不关心它,请随意删除它!
          【解决方案12】:

          如果您希望它在一段时间后停止查看(超时),那么以下 jQuery 将起作用。它将在 10 秒后超时。我需要使用此代码而不是纯 JS,因为我需要通过名称选择输入并且在实现其他一些解决方案时遇到了麻烦。

           // Wait for element to exist.
          
              function imageLoaded(el, cb,time) {
          
                  if ($(el).length) {
                      // Element is now loaded.
          
                      cb($(el));
          
                      var imageInput =  $('input[name=product\\[image_location\\]]');
                      console.log(imageInput);
          
                  } else if(time < 10000) {
                      // Repeat every 500ms.
                      setTimeout(function() {
                         time = time+500;
          
                          imageLoaded(el, cb, time)
                      }, 500);
                  }
              };
          
              var time = 500;
          
              imageLoaded('input[name=product\\[image_location\\]]', function(el) {
          
               //do stuff here 
          
               },time);
          

          【讨论】:

            【解决方案13】:

            我认为这里仍然没有任何简单易读的工作示例的答案。使用MutationObserverinterface来检测DOM变化,像这样:

            var observer = new MutationObserver(function(mutations) {
                if ($("p").length) {
                    console.log("Exist, lets do something");
                    observer.disconnect(); 
                    //We can disconnect observer once the element exist if we dont want observe more changes in the DOM
                }
            });
            
            // Start observing
            observer.observe(document.body, { //document.body is node target to observe
                childList: true, //This is a must have for the observer with subtree
                subtree: true //Set to true if changes must also be observed in descendants.
            });
                        
            $(document).ready(function() {
                $("button").on("click", function() {
                    $("p").remove();
                    setTimeout(function() {
                        $("#newContent").append("<p>New element</p>");
                    }, 2000);
                });
            });
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
            
            <button>New content</button>
            <div id="newContent"></div>

            注意: 关于MutationObserverSpanish Mozilla 文档更多 如果您想了解更多信息,请详细说明。

            【讨论】:

            • 考虑发表评论解释拒绝投票的原因,以便我改进我的答案。谢谢。
            【解决方案14】:

            这是一个使用原生 Javascript 的 Promise-returning 解决方案(没有混乱的回调)。默认情况下,它每 200 毫秒检查一次。

            function waitFor(selector) {
                return new Promise(function (res, rej) {
                    waitForElementToDisplay(selector, 200);
                    function waitForElementToDisplay(selector, time) {
                        if (document.querySelector(selector) != null) {
                            res(document.querySelector(selector));
                        }
                        else {
                            setTimeout(function () {
                                waitForElementToDisplay(selector, time);
                            }, time);
                        }
                    }
                });
            }
            

            【讨论】:

              【解决方案15】:

              对于使用 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检查一下元素是否被加载,什么时候加载,我们就可以使用了。

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

              【讨论】:

                【解决方案16】:

                使用 MutationObserver 的更简洁的示例:

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

                【讨论】:

                  【解决方案17】:

                  insertionQuery 库怎么样?

                  insertionQuery 使用附加到指定选择器的 CSS 动画回调,以便在创建元素时运行回调。此方法允许在创建元素时运行回调,而不仅仅是第一次。

                  来自github:

                  捕捉节点出现的非 dom-event 方式。它使用选择器。

                  不仅仅是为了更广泛的浏览器支持,在某些方面它可以比 DOMMutationObserver 更好。

                  为什么?

                  • 因为 DOM 事件会减慢浏览器的速度,而 insertQuery 不会
                  • 因为 DOM Mutation Observer 的浏览器支持少于 insertQuery
                  • 由于使用 insertQuery,您可以使用选择器过滤 DOM 更改,而不会产生性能开销!

                  广泛支持!

                  IE10+ 和其他大部分(包括移动设备)

                  【讨论】:

                    【解决方案18】:

                    我也遇到了同样的问题,所以我继续为它写了一个plugin

                    $(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));
                    

                    【讨论】:

                    • 感谢您的插件。我分叉并改进了一点。随意从我的更新中获取任何你想要的东西。我还计划进行一些改进:updated plugin
                    • 如果没有 jquery dep 也会很好... ;)
                    • 也许你应该提到它是如何工作的:它通过每 500 毫秒询问元素是否存在(使用window.setInterval)来工作。我不知道MutationObserver 答案是否也可以通过轮询来工作......
                    • 如果元素已经在页面上,它就不能正常工作。这是此函数的正确版本:gist.github.com/PizzaBrandon/5709010
                    • 你能解释一下函数开头的;有什么用吗(;(function ($, window) {)?
                    【解决方案19】:

                    这是一个纯 Javascript 函数,可让您等待任何事情。设置更长的时间间隔以减少 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.");
                    });
                    

                    【讨论】:

                      【解决方案20】:

                      我使用这种方法等待一个元素出现,然后我可以执行其他功能。

                      假设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
                      

                      【讨论】:

                      • 简单易行。
                      【解决方案21】:

                      这是一个作为 MutationObserver 的瘦包装器的函数。唯一的要求是浏览器支持 MutationObserver;没有对 JQuery 的依赖。运行下面的 sn-p 以查看工作示例。

                      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>

                      【讨论】:

                        【解决方案22】:

                        你可以的

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

                        请注意,这仅在从服务器请求时元素存在于 DOM 中时才有效。如果元素是通过 JavaScript 动态添加的,它将不起作用,您可能需要查看其他答案。

                        【讨论】:

                        • .ready() 函数适用于大多数任何东西(如果不是任何东西),而不仅仅是document。它只是不适用于动态创建的元素,即使在 .live() 上也是如此。
                        • @Bery,正如 Richard 指出的那样,这仅适用于 HTML 中首次请求服务器时已经存在的元素。如果使用 Javascript 将元素动态添加到 DOM 中,则不起作用。
                        • @Sam,您能否说明如何将其附加到内存中元素的引用?
                        • 这个答案不正确。您实际上在这里检查的是一个常规的$(document).ready(),而不是您认为它也会适用的元素。这就是这个 special 监听器的工作原理。 Example
                        • 根据api.jquery.com/ready不推荐这种用法
                        【解决方案23】:

                        您可以监听DOMNodeInsertedDOMSubtreeModified 事件,这些事件会在新元素添加到 DOM 时触发。

                        还有LiveQuery jQuery 插件可以检测新元素的创建时间:

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

                        【讨论】:

                        • 非常不错的插件!直接在jquery中有类似的功能吗?我想知道没有现有的功能可以做到这一点。如果这是插件,请为这个答案投票;)对我来说,它完美无缺。非常感谢。
                        • 注意 IE 9 实现了 DOMNodeInserted 但有一个重大错误,即当您添加元素时它不会触发,这是您想要使用它的大部分时间。详情在:help.dottoro.com/ljmcxjla.php
                        • DOMSubtreeModified 已弃用,取而代之的是 Mutation Observer API
                        猜你喜欢
                        • 2019-12-14
                        • 2014-01-21
                        • 2015-05-18
                        • 1970-01-01
                        • 2013-04-15
                        • 1970-01-01
                        • 2020-12-05
                        相关资源
                        最近更新 更多