我正在尝试使用类rules
设置段落标记的值。它应该每4秒在a,b,c等之间切换并重复。出于某种原因,该功能根本没有运行,并且chrome的开发人员工具中没有错误。当我用<body onload="rulesSlideshow">
调用函数时没有任何变化。
<script type="text/javascript">
document.onload = function rulesSlideshow() {
setTimeout(setRule("a"), 4000);
setTimeout(setRule("b"), 4000);
setTimeout(setRule("c"), 4000);
setTimeout(setRule("d"), 4000);
setTimeout(setRule("e"), 4000);
rulesSlideshow();
}
function setRule(rule) {
document.querySelector("rules").innerHTML = rule;
}
</script>
<p id="rule" class="rules"></p>
编辑:通过删除document.onload =
并添加<body onload="rulesSlideshow()">
我可以得到运行的代码(由Daniel Beck提供)。尽管如此,我的代码找不到段落标记。
如果您尝试通过DOM中的onload属性调用该函数,则需要调用该函数,而不仅仅是引用它;这应该是<body onload="rulesSlideshow()">
。
如果您更喜欢在代码中定义onload处理程序,请使用匿名函数:
document.onload = function() {...};
...或者应用于document.onload的命名函数作为参考:
var rulesSlideshow = function() {...}
document.onload = rulesSlideshow; // no parens this time, since you're assigning the function to the handler here, not calling it.
从DOM属性调用处理程序,或在代码中定义它 - 不要两者都做。 (尽可能让你的javascript与DOM分开是一个好主意,因此很多人会建议不要使用像<body onload="...">
这样的内联事件属性,而是在代码中定义这些处理程序 - 但这两种技术仍然可以很好地工作。)
由于您正在寻找类名,因此您需要包含“。”:
document.querySelector(".rules").innerHTML = rule;
由于所有超时都具有相同的时间值,因此它们将同时运行(或足够接近) - 因此您只能看到最后一个的结果。如果您希望每次调用之间有4秒的间隔,则需要不同的超时值。
此外,由于rulesSlideshow在运行后立即调用自身,因此最终会出现堆栈溢出。这也需要一个setTimeout(虽然你正在做的是定期重复函数,用setInterval
调用它可能更合适。)
setTimeout期望接收一个函数,但是你通过调用函数传递结果。如果你在setRule
上不需要参数,你可以使用这个简写:
setTimeout(setRule, 4000)
但是使用param,你需要一个匿名的包装器:
setTimeout(function() {setRule("x")}, 4000)
将它们全部放在一起(我已将它从onload切换到onclick,因为onload很难在堆栈片段中演示,但其余部分是相同的):
var rulesSlideshow = function() {
console.log("Called rulesSlideshow");
setTimeout(function() {setRule("a")}, 4000);
setTimeout(function() {setRule("b")}, 8000);
setTimeout(function() {setRule("c")}, 12000);
setTimeout(function() {setRule("d")}, 16000);
setTimeout(function() {setRule("e")}, 20000);
setTimeout(rulesSlideshow, 20000); // used same timeout as above, because there's a 4s delay before this function does anything.
}
document.onclick = rulesSlideshow;
function setRule(rule) {
console.log("setRule");
document.querySelector(".rules").innerHTML = rule;
}
(Click anywhere to start)
<p id="rule" class="rules"></p>
你有一些问题,但最大的问题是
setTimeout
的调用是立即调用函数,因为你使用括号传递参数,但调用函数。 setTimeout
需要功能参考.querySelector
不会找到该类的元素因为你没有在类名前面加上.
请参阅下面的注释以获得更清晰的解决方案(我在这里使用一秒钟以便更快地查看结果):
var el = null; // prepare to hold a reference to the output element
var vals = ["a", "b", "c", "d", "e"]; // values to enumerate
var idx = 0; // counter to keep track of how many times to call a timer
var timer = null; // will hold reference to timer
// When the document is fully parsed
document.addEventListener("DOMContentLoaded", function() {
el = document.getElementById("rule"); // set up reference to output element
timer = setTimeout(setRule, 1000); // set up the timer, don't invoke the function with ()
});
// Function to be called by timer
function setRule() {
// Check the counter to see if we still have values to enumerate
if(idx < vals.length){
// We do, so set the output element to the correct array value
el.textContent = vals[idx++];
// Call the timer again
setTimeout(setRule, 1000);
}
}
<p id="rule"></p>
你有三个问题:
rulesSlideshow()
函数分配给onload
,但从未实际调用它。你可以通过在函数末尾添加括号function() { ... }()
来实现这一点,创建一个Immediately Invoked Function Expression (IIFE)。querySelector("rules")
实际上不会瞄准任何东西;你需要用.
前缀指定类为.querySelector(".rules")
。4000
。因为它们将异步运行,所以它们将同时触发。因此,您只会看到最终输出(e
)。要真正“抵消”输出,您需要将超时设置在彼此之内,或者使用chained promises以便它们按顺序运行。这一切都可以在以下内容中看到:
document.onload = function rulesSlideshow() {
setTimeout(function() {
setRule("a");
setTimeout(function() {
setRule("b");
setTimeout(function() {
setRule("c");
setTimeout(function() {
setRule("d");
setTimeout(function() {
setRule("e");
}, 4000);
}, 4000);
}, 4000);
}, 4000);
}, 4000);
}();
function setRule(rule) {
document.querySelector(".rules").innerHTML = rule;
}
<p id="rule" class="rules"></p>
另外,请注意,您不需要在rulesShowshow()
本身内实际调用rulesSlideshow()
;这已从上面的代码段中删除。