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


当前回答

下面是一个函数,充当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>

其他回答

受杰米·胡伯的启发,我想出了一个答案。

这是一个基于承诺的函数,你可以设置:

最大尝试次数-默认为10; 延迟(毫秒)-默认为100毫秒。

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

如果它没有出现,它将返回一个承诺。用null拒绝,这样您就可以按照您的愿望处理错误。

Code

export function _waitForElement(selector, delay = 10, tries = 100) {
  const element = document.querySelector(selector);


  if (!window[`__${selector}`]) {
    window[`__${selector}`] = 0;
    window[`__${selector}__delay`] = delay;
    window[`__${selector}__tries`] = tries;
  }

  function _search() {
    return new Promise((resolve) => {
      window[`__${selector}`]++;
      setTimeout(resolve, window[`__${selector}__delay`]);
    });
  }

  if (element === null) {
    if (window[`__${selector}`] >= window[`__${selector}__tries`]) {
      window[`__${selector}`] = 0;
      return Promise.resolve(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上的任何元素。

我采取@Yong Wong的解决方案,但它有一个可选的超时,你可以指定根节点从哪里你想等待元素。

完整的异步/等待。

const $ = (selector, opts) => {
  let timeout = undefined;
  let root = undefined;

  if (opts) {
    ({ root, timeout } = opts);
  }

  if (root === undefined) root = document.body;
  
  const nodeFound = root.querySelector(selector);
  if (nodeFound) return new Promise(resolve => resolve(nodeFound));

  return new Promise((resolve, reject) => {
    let callback = () => {
      observer.disconnect();
    };

    const _resolve = (node) => {
      callback();
      resolve(node);
    };

    const _reject = (err) => {
      callback();
      reject(err);
    };

    if (timeout && timeout > 0) {
      const handle = setTimeout(() => {
        _reject(new Error("Element not found: timeout exceeded."));
      }, timeout);
      callback = () => {
        observer.disconnect();
        clearTimeout(handle);
      };
    }

    const observer = new MutationObserver(mutations => {
      for (const mutation of mutations) {
        for (const addedNode of mutation.addedNodes) {
          if (addedNode.matches(selector)) {
            _resolve(addedNode);
            return;
          }
        }
      }
    });

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

示例调用:

// wait for 10 seconds for 'div.bla-bla-bla' to appear as a child of 'div.some-container'
await $("div.bla-bla-bla", {
  timeout: 10000,
  root: document.querySelector("div.some-container") 
});

我使用这种方法等待一个元素出现,这样我就可以在那之后执行其他函数。

让我们说doTheRestOfTheStuff(参数)函数应该只在ID为the_Element_ID的元素出现或完成加载后调用,我们可以使用,

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

你可以试试这个:

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

这个办法对我很有效

你可以这样做

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

});

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