我正在Chrome中开发一个扩展,我想知道:当一个元素出现时,最好的方法是什么?使用纯javascript,间隔检查,直到一个元素存在,或jQuery有一些简单的方法来做到这一点?
当前回答
对于一个使用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毫秒检查一次元素是否加载,当加载成功时,我们就可以使用它。
这对于向已动态添加到文档中的元素添加单击处理程序特别有用。
其他回答
一个返回承诺的解决方案,并允许使用超时(兼容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的更清晰的例子:
new MutationObserver( mutation => {
if (!mutation.addedNodes) return
mutation.addedNodes.forEach( node => {
// do stuff with node
})
})
更新
下面是一个更新的版本,可以使用承诺。如果达到特定的尝试次数,它也会“停止”。
function _waitForElement(selector, delay = 50, 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);
}
}
用法很简单,用await使用它只是确保你在一个 异步功能:
const start = (async () => {
const $el = await _waitForElement(`.my-selector`);
console.log($el);
})();
过时的版本
只需添加所需的选择器。一旦找到元素,就可以在回调函数中访问它。
const waitUntilElementExists = (selector, callback) => {
const el = document.querySelector(selector);
if (el){
return callback(el);
}
setTimeout(() => waitUntilElementExists(selector, callback), 500);
}
waitUntilElementExists('.wait-for-me', (el) => console.log(el));
这是写在王勇答案(最高分答案)上面的一个更好的版本。
增加的特性:您可以等待一个元素特定的时间,精确定位,以提高性能。
async function waitForElement(selector, timeout = null, location = document.body) {
return new Promise((resolve) => {
let element = document.querySelector(selector);
if (element) {
return resolve(element);
}
const observer = new MutationObserver(async () => {
let element = document.querySelector(selector);
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,
});
});
}
用法:
await waitForElement(".nav-alt", 500, ".main-body")
奖励:等待一个元素从DOM中消失。
async function waitForElementDeath(selector, location = document.body) {
return new Promise((resolve) => {
const observer = new MutationObserver(async () => {
if (!document.querySelector(selector)) {
resolve(true);
observer.disconnect();
}
});
observer.observe(location, {
childList: true,
subtree: true,
});
});
}
用法:
await waitForElementDeath(".Popup-div", "Popup-Container")
你也可以使用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)
推荐文章
- 如何为Firebase构建云函数,以便从多个文件部署多个函数?
- 如何发送推送通知到web浏览器?
- AngularJS:工厂和服务?
- js:将一个组件包装成另一个组件
- 父ng-repeat从子ng-repeat的访问索引
- JSHint和jQuery: '$'没有定义
- 模仿JavaScript中的集合?
- 用JavaScript验证电话号码
- 如何在HTML5中改变视频的播放速度?
- 谷歌地图API v3:我可以setZoom后fitBounds?
- 用jQuery检查Internet连接是否存在?
- 如何使用滑动(或显示)函数在一个表行?
- ES6/2015中的null安全属性访问(和条件赋值)
- 与push()相反;
- JS字符串“+”vs concat方法