我在让 JavaScript 函数仅在 DOM 元素完全加载时执行一次时遇到了一些困难。我尝试了无数种 setInterval
的组合s,seTimeout
s,FOR
循环,IF
声明,WHILE
循环等却一事无成。
我确实设法让它工作了一次,但它是偶然的,因为我只能通过将功能延迟 2 秒来让它工作(这不好,因为不知道到底需要多长时间)需要加载)并一遍又一遍地快速重新触发相同的功能,这也不好。
我只需要不断扫描页面来判断某个元素是否存在并包含内容( innerHTML != undefined
或其他内容),在加载后立即执行一段代码(并且仅一次),然后停止扫描页面。
有没有人找到办法做到这一点?另外,我需要 JavaScript,而不是 jQuery。
谢谢。
原始代码
function injectLink_Bridge(){
setTimeout(function(){
injectLink();
}, 2000);
}
function injectLink(){
var headerElement = document.getElementsByClassName("flex-module-header");
if (headerElement.innerHTML == undefined) {
console.log("Element doesn't exist. Restarting function");
setTimeout(function(){
injectLink_Bridge(); //I can't remember if the bridge is necessary or not
}, 2000);
} else {
console.log("Element exists. Injecting");
setTimeout(function(){
headerElement[1].innerHTML += "code" //Inject code into the second instance of the class-array
}, 2000);
}
}
完成代码
function injectLink(){
var headerElement = document.getElementsByClassName("flex-module-header")[1]; //Get the second instance
if(headerElement && headerElement.innerHTML != ""){
console.log("Element exists and has content. Injecting code...");
headerElement.innerHTML += "code"; //Currently revising, due to T.J. Crowder's side-note
} else {
console.log("Element doesn't exist or has no content. Refiring function...");
setTimeout(injectLink, 250);
}
}
最佳答案
在发布代码后更新了答案:
getElementsByClassName
返回 NodeList
,不是一个元素; NodeList
没有 innerHTML
属性。如果您想要第二个匹配元素,请使用 [1]
获取它,然后测试您是否得到了返回的内容(或者如果您愿意,可以使用 .length > 1
首先检查,但 NodeList
被记录为对于不存在的索引返回 null
)。此外,在将现有函数传递给 setTimeout
时,您不需要对现有函数进行函数包装。所以:
function injectLink(){
var headerElement = document.getElementsByClassName("flex-module-header")[1];
if (!headerElement) {
console.log("Element doesn't exist. Restarting function");
setTimeout(injectLink, 2000);
} else {
console.log("Element exists. Injecting");
// Do you really want a further two second delay?
setTimeout(function(){
headerElement.innerHTML += "code"; //Inject code into the second instance of the class-array
}, 2000);
}
}
旁注:使用 .innerHTML += "markup";
通常不是将内容附加到元素的好方法。当您执行此操作时,浏览器将执行以下操作:
- 遍历该元素及其所有后代元素,构建 HTML 字符串以提供给 JavaScript 层。
- 拆除元素中的所有内容,其副产品是删除后代元素上的所有事件处理程序。
- 解析 HTML 字符串并为其构建新的节点和元素。
这需要一些工作,而且还有可能清除事件处理程序。如果您要添加新的子元素,请查看使用 createElement
和 appendChild
。如果您要添加更多文本内容,请查看 createTextNode
和appendChild
。
原始答案:
如果您为元素指定一个id
(尽管无论您如何查找元素,相同的概念都适用),您可以执行以下操作:
(function() {
setTimeout(check, 0);
function check() {
var elm = document.getElementById('theId');
if (!elm) {
setTimeout(check, 250); // Check again in a quarter second or so
return;
}
// Use the element
}
})();
在那里,我们几乎立即启动第一次检查,如果我们没有找到该元素,我们会安排 250 毫秒后再次检查。因为如果前一次检查没有找到该元素,我们只会安排下一次检查,因此我们只根据需要循环多次以找到该元素。
如果该元素没有 id
,那么您可能会以某种方式找到它(querySelector
、querySelectorAll
等),这样就会知道您是否找到它并能够安排下一次检查。
可能值得对其进行限制,例如:
(function() {
var start = new Date();
setTimeout(check, 0);
function check() {
var elm = document.getElementById('theId');
if (!elm) {
if (new Date() - start > 5000) { // More than five seconds
throw "Couldn't find the element";
}
setTimeout(check, 250); // Check again in a quarter second or so
return;
}
// Use the element
}
})();
...因此,如果您更改了 HTML 并且该元素不再存在,您在测试时会看到错误,并会提醒您更新代码。
关于javascript - 仅当元素完全加载时执行一次的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10380678/