我在使用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);
}
}
答案 0 :(得分:3)
更新回答:
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";
通常不是将内容附加到元素的好方法。以下是浏览器执行此操作时的操作:
这是一些工作,也是消除事件处理程序的可能性。如果您要添加新的子元素,请查看使用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
}
})();
在那里,我们几乎立即启动了第一次检查,如果我们找不到该元素,我们会在250ms之后再次安排检查。因为我们只安排下一次检查,如果前一个没有找到该元素,我们只需要循环多次,以找到该元素。
如果该元素没有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并且该元素不再存在,则会在测试时看到错误,并提醒您更新代码。
答案 1 :(得分:1)
编辑:既然您已经展示了代码,那么它就会出现一些问题。
例如,getElementsByClassName()
返回一个数组,因此您无法执行此操作:
var headerElement = document.getElementsByClassName("flex-module-header");
if (headerElement.innerHTML == undefined)
你必须这样做:
var headerElement = document.getElementsByClassName("flex-module-header");
if (!headerElement || headerElement.length == 0 || headerElement[0].innerHTML == undefined)
在问题中提供代码之前的原始答案:
如果你向我们展示了整个问题,我们可能会想出一些更优雅的东西,但根据你告诉我们的内容,我们现在可以建议的是钝力法:
(function() {
var item, cnt = 0;
var pollTimer = setInterval(function() {
++cnt;
if (!item) {
// cache the item if found so future checks will be faster
item = document.getElementById("testObject");
}
if (item && item.innerHTML != "") {
// the item has innerHTML now, you can process it
// with code here
clearInterval(pollTimer);
} else {
if (cnt > 100) {
// if not found after 100 checks (20 seconds)
// then stop looking so we don't keep going forever
clearInterval(pollTimer);
}
}
}, 200);
}){};