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


当前回答

你也可以使用getElementById代替querySelector

这个函数和 https://stackoverflow.com/a/61511955/10798137

  async function waitForElementById(id, timeout = null, location = document.body) {
    return new Promise((resolve) => {
        let element = document.getElementById(id);
        if (element) {
            return resolve(element);
        }

        const observer = new MutationObserver(async () => {
            let element = document.getElementById(id);
            if (element) {
                resolve(element);
                observer.disconnect();
            } else {
                if (timeout) {
                    async function timeOver() {
                        return new Promise((resolve) => {
                            setTimeout(() => {
                                observer.disconnect();
                                resolve(false);
                            }, timeout);
                        });
                    }
                    resolve(await timeOver());
                }
            }
        });

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

使用它


    waitForElement("tag_id", 500).then((elm) => {
      console.log(elm)
    })

Or


    var elm = async waitForElement("tag_id", 500)

其他回答

对于一个使用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");
    });
  });

在这里,我们只需每500毫秒检查一次元素是否加载,当加载成功时,我们就可以使用它。

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

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

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

最大尝试次数-默认为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上的任何元素。

下面的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>


更新

下面是一个实验性的async/await示例。

const sleep = (ms) => new Promise((res) => setTimeout(res, ms)); const observe = (selector, targetNode = document.body) => new Promise(res => { new MutationObserver(mutations => res([...mutations] .flatMap((mutation) => [...mutation.addedNodes]) .find((node) => node.matches && node.matches(selector)))) .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', container) .then(el => console.log('I have arrived!', el)); (async () => { await sleep(2000); container.appendChild(createGreeting()); })(); 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>

我采取@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") 
});

你可以试试这个:

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

这个办法对我很有效