我正在Chrome中开发一个扩展,我想知道:当一个元素出现时,最好的方法是什么?使用纯javascript,间隔检查,直到一个元素存在,或jQuery有一些简单的方法来做到这一点?
当前回答
受杰米·胡伯的启发,我想出了一个答案。
这是一个基于承诺的函数,你可以设置:
最大尝试次数-默认为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上的任何元素。
其他回答
insertionQuery库呢?
insertionQuery使用CSS动画回调附加到指定的选择器,在创建元素时运行回调。此方法允许在创建元素时运行回调,而不仅仅是第一次。
从github:
用非dom事件的方式捕获节点。它使用选择器。 它不仅仅是为了更广泛的浏览器支持,在某些方面它可能比DOMMutationObserver更好。 为什么? 因为DOM事件会降低浏览器的速度,而insertionQuery不会 因为DOM Mutation Observer的浏览器支持比insertionQuery少 因为使用insertionQuery,您可以使用选择器过滤DOM更改,而没有性能开销! 广泛的支持! IE10+和其他设备(包括手机)
这里有一个用Javascript编写的promise返回解决方案(没有混乱的回调)。默认情况下,它每200ms检查一次。
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);
}
}
});
}
受杰米·胡伯的启发,我想出了一个答案。
这是一个基于承诺的函数,你可以设置:
最大尝试次数-默认为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上的任何元素。
我通常使用标签管理器的这个片段:
<script>
(function exists() {
if (!document.querySelector('<selector>')) {
return setTimeout(exists);
}
// code when element exists
})();
</script>
由于性能问题,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()