我正在Chrome中开发一个扩展,我想知道:当一个元素出现时,最好的方法是什么?使用纯javascript,间隔检查,直到一个元素存在,或jQuery有一些简单的方法来做到这一点?
当前回答
如果你想让它在一段时间后停止查看(超时),那么下面的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);
其他回答
一个返回承诺的解决方案,并允许使用超时(兼容IE 11+)。
对于单个元素(element类型):
"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
});
既适用于元素列表,也适用于单个元素。
下面是一个使用MutationObserver api的简单解决方案。
没有jQuery 没有计时器 没有第三方库 基于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);
});
或者使用async/await:
const elm = await waitForElm('.some-class');
我使用这种方法等待一个元素出现,这样我就可以在那之后执行其他函数。
让我们说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
我采取@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")
});
由于性能问题,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()
推荐文章
- 截断字符串直接JavaScript
- 我如何使用可选的链接与数组和函数?
- EINVRES请求https://bower.herokuapp.com/packages/失败,提示502
- 使用fetch进行基本身份验证?
- 如何从子组件内部更新React上下文?
- 如何将一个普通对象转换为ES6映射?
- scrollIntoView卷轴太远了
- Angular ng-repeat反过来
- 如何获得请求路径与表达请求对象
- 使用Handlebars 'each'循环访问父对象的属性
- 盎格鲁- ngcloak / ngg展示blink元素
- 禁用表单自动提交按钮单击
- 节点和错误:EMFILE,打开的文件太多
- JavaScript函数中的默认参数值
- 使用RegExp.exec从字符串中提取所有匹配项