如何等到元素存在?

IT技术 javascript jquery google-chrome google-chrome-extension
2021-01-27 00:45:07

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

6个回答

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

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 有点复杂,所以我构建了一个库到达.js,以提供一个更简单的 api 来监听元素的创建/删除。
2021-03-14 00:45:07
@Superdooperhero 我用简单的例子做了一个答案。核实。stackoverflow.com/a/57395241/6542186
2021-03-17 00:45:07
你能举一个例子来说明如何使用它吗?不确定在 DOM 元素存在时将我的 jquery 选择器或代码放在哪里。
2021-03-31 00:45:07
需要注意的两件事:(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
2021-04-05 00:45:07
我推荐使用@UzairFarooq 优秀库github.com/uzairfarooq/arrive
2021-04-10 00:45:07

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

$(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));
如果该元素已在页面上,则它无法正常工作。这是此功能的正确版本:gist.github.com/PizzaBrandon/5709010
2021-03-15 00:45:07
也许你应该提到它是如何工作的:它通过每 500 毫秒询问元素是否存在来工作(使用 a window.setInterval)。我不知道MutationObserver答案是否也适用于投票...
2021-03-19 00:45:07
如果没有 jquery dep 也会很好...;)
2021-04-04 00:45:07
你能解释一下;函数 ( ;(function ($, window) {)开头的用法吗?
2021-04-05 00:45:07
谢谢你的插件。我分叉并改进了一点。请随意从我的更新中获取您想要的任何内容。我还有一些改进计划,但仍然是:更新的插件
2021-04-10 00:45:07

这是一个核心 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);
    }
  })();
}

此调用将查找id="div1"1000毫秒一次的 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 中有解释

你能写它来使用变异观察器吗?
2021-03-18 00:45:07
或者你可以重写这个以使用Promise吗?
2021-03-21 00:45:07
2021-03-31 00:45:07
好的!你能写这个以便接受任何选择器吗?
2021-04-05 00:45:07
我怀疑我能做到……但是请查看这篇文章以获取 getElementByXpath:stackoverflow.com/questions/10596417/...
2021-04-10 00:45:07

这是一个使用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');
@RalphDavidAbernathy,您说得对,mutations代码中未使用参数,可以安全删除。它有很多关于变异的有用信息。我把它放在那里以防万一你需要访问它。
2021-03-13 00:45:07
这太棒了,谢谢。但是常量中的那个mutations参数的目的是什么observer
2021-03-19 00:45:07
这很整洁!它很酷的部分是你也可以将它与async/一起使用await你也可以通过这样做来榨取更多的性能mutations.addedNodes.find(node => node.matchesSelector("..."))
2021-03-25 00:45:07
@mattsven 好点!仅检查突变中的节点比执行 document.querySelector 更高效。
2021-03-25 00:45:07
请更正拼写错误,将 watiForElm 改为 waitForElm
2021-03-28 00:45:07

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

假设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
简单易行。
2021-03-29 00:45:07