JavaScript 无限循环幻灯片有延迟?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5835126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript Infinitely Looping slideshow with delays?
提问by JacobTheDev
How do I make an infinite loop in JavaScript? I'm trying to make a slideshow, which I have working, but I can't get it to loop. I can't even get it to loop twice.
如何在 JavaScript 中进行无限循环?我正在尝试制作幻灯片,我正在使用它,但无法循环播放。我什至无法让它循环两次。
The code I'm using right now is
我现在使用的代码是
window.onload = function start() {
slide();
}
function slide() {
var num = 0;
for (num=0;num<=10;num++) {
setTimeout("document.getElementById('container').style.marginLeft='-600px'",3000);
setTimeout("document.getElementById('container').style.marginLeft='-1200px'",6000);
setTimeout("document.getElementById('container').style.marginLeft='-1800px'",9000);
setTimeout("document.getElementById('container').style.marginLeft='0px'",12000);
}
}
Without the for thing in there, it does go through once. When I put in a for, it either makes Firefox lock up, or just loops once. I'm sure this is a really simple thing to do, and even if it has to be loop 1,000,000 times or something instead of infinite, that'd work fine for me.
如果没有 for 东西,它确实会通过一次。当我输入 for 时,它要么使 Firefox 锁定,要么只循环一次。我确信这是一件非常简单的事情,即使它必须循环 1,000,000 次或其他什么而不是无限,这对我来说也很好用。
Also, I don't want to use jQuery or something that someone else created. I'm learning JavaScript, and this is partially to help me learn, and partially because I'm trying to make as many HTML5-based systems as I can.
另外,我不想使用 jQuery 或其他人创建的东西。我正在学习 JavaScript,这部分是为了帮助我学习,部分是因为我正在尝试制作尽可能多的基于 HTML5 的系统。
EDIT: I think the reason it's freezing is because it executes the code all at once, and then just stores it in a cache or something. What I want it to do is go through this once, then start at the top again, which is what I've always thought loops where for. In "batch" (command prompt) scripting, this could be done with a "GOTO
" command. I don't know if there's an equivalent in JS or not, but that's really my goal.
编辑:我认为它冻结的原因是因为它一次执行所有代码,然后将其存储在缓存或其他东西中。我想要它做的是经历一次,然后再次从顶部开始,这就是我一直认为循环的目的。在“批处理”(命令提示符)脚本中,这可以通过“ GOTO
”命令来完成。我不知道 JS 中是否有等价物,但这确实是我的目标。
回答by Andy E
The correct approach is to use a single timer. Using setInterval
, you can achieve what you want as follows:
正确的方法是使用单个计时器。使用setInterval
,您可以按如下方式实现您想要的:
window.onload = function start() {
slide();
}
function slide() {
var num = 0, style = document.getElementById('container').style;
window.setInterval(function () {
// increase by num 1, reset to 0 at 4
num = (num + 1) % 4;
// -600 * 1 = -600, -600 * 2 = -1200, etc
style.marginLeft = (-600 * num) + "px";
}, 3000); // repeat forever, polling every 3 seconds
}
回答by Blindy
You don't want while(true)
, that will lock up your system.
你不想要while(true)
,那会锁定你的系统。
What you want instead is a timeout that sets a timeout on itself, something like this:
你想要的是一个超时设置自己的超时,是这样的:
function start() {
// your code here
setTimeout(start, 3000);
}
// boot up the first call
start();
回答by Ender
Here's a nice, tidy solution for you: (also see the live demo ->)
这是一个不错的,整洁的解决方案:(另请参阅现场演示 ->)
window.onload = function start() {
slide();
}
function slide() {
var currMarg = 0,
contStyle = document.getElementById('container').style;
setInterval(function() {
currMarg = currMarg == 1800 ? 0 : currMarg + 600;
contStyle.marginLeft = '-' + currMarg + 'px';
}, 3000);
}
Since you are trying to learn, allow me to explain how this works.
既然您正在尝试学习,请允许我解释一下这是如何工作的。
First we declare two variables: currMarg
and contStyle
. currMarg
is an integer that we will use to track/update what left margin the container should have. We declare it outside the actual update function (in a closure), so that it can be continuously updated/access without losing its value. contStyle
is simply a convenience variable that gives us access to the containers styles without having to locate the element on each interval.
首先我们声明两个变量:currMarg
和contStyle
。 currMarg
是一个整数,我们将使用它来跟踪/更新容器应具有的左边距。我们在实际更新函数之外(在闭包中)声明它,以便它可以不断更新/访问而不会丢失其值。 contStyle
只是一个方便的变量,它使我们可以访问容器样式,而无需在每个间隔上定位元素。
Next, we will use setInterval
to establish a function which should be called every 3 seconds, until we tell it to stop (there's your infinite loop, without freezing the browser). It works exactly like setTimeout
, except it happens infinitely until cancelled, instead of just happening once.
接下来,我们将使用setInterval
建立一个应每 3 秒调用一次的函数,直到我们告诉它停止(这是您的无限循环,不会冻结浏览器)。它的工作原理与 完全一样setTimeout
,除了它无限发生直到被取消,而不是只发生一次。
We pass an anonymous functionto setInterval
, which will do our work for us. The first line is:
我们将匿名函数传递给setInterval
,它将为我们完成我们的工作。第一行是:
currMarg = currMarg == 1800 ? 0 : currMarg + 600;
This is a ternary operator. It will assign currMarg
the value of 0
if currMarg
is equal to 1800
, otherwise it will increment currMarg
by 600
.
这是一个三元运算符。它将分配currMarg
的值0
,如果currMarg
等于1800
,否则会增加currMarg
的600
。
With the second line, we simply assign our chosen value to container
s marginLeft, and we're done!
对于第二行,我们只需将我们选择的值分配给container
s marginLeft,我们就完成了!
Note: For the demo, I changed the negative values to positive, so the effect would be visible.
注意:对于演示,我将负值更改为正值,因此效果是可见的。
回答by josh.trow
Perhps this is what you are looking for.
Perhps 这就是你要找的。
var pos = 0;
window.onload = function start() {
setTimeout(slide, 3000);
}
function slide() {
pos -= 600;
if (pos === -2400)
pos = 0;
document.getElementById('container').style.marginLeft= pos + "px";
setTimeout(slide, 3000);
}
回答by Piskvor left the building
You are calling setTimeout()
ten times in a row, so they all expire almost at the same time. What you actually want is this:
您setTimeout()
连续调用十次,因此它们几乎同时到期。你真正想要的是这样的:
window.onload = function start() {
slide(10);
}
function slide(repeats) {
if (repeats > 0) {
document.getElementById('container').style.marginLeft='-600px';
document.getElementById('container').style.marginLeft='-1200px';
document.getElementById('container').style.marginLeft='-1800px';
document.getElementById('container').style.marginLeft='0px';
window.setTimeout(
function(){
slide(repeats - 1)
},
3000
);
}
}
This will call slide(10), which will then set the 3-second timeout to call slide(9), which will set timeout to call slide(8), etc. When slide(0) is called, no more timeouts will be set up.
这将调用 slide(10),然后将设置 3 秒超时以调用 slide(9),这将设置超时以调用 slide(8) 等。当调用 slide(0) 时,将不再有超时设置。
回答by michaeltomer
You can infinitely loop easily enough via recursion.
您可以通过递归轻松地无限循环。
function it_keeps_going_and_going_and_going() {
it_keeps_going_and_going_and_going();
}
it_keeps_going_and_going_and_going()
回答by Amadan
The key is not to schedule all pics at once, but to schedule a next pic each time you have a pic shown.
关键不是一次安排所有图片,而是每次显示图片时安排下一张图片。
var current = 0;
var num_slides = 10;
function slide() {
// here display the current slide, then:
current = (current + 1) % num_slides;
setTimeout(slide, 3000);
}
The alternative is to use setInterval
, which sets the function to repeat regularly (as opposed to setTimeout
, which schedules the next appearance only.
另一种方法是使用setInterval
,它将函数设置为有规律地重复(而不是setTimeout
,它只安排下一次出现。
回答by Braden Best
Expanding on Ender's answer, let's explore our options with the improvements from ES2015.
扩展Ender 的回答,让我们通过 ES2015 的改进来探索我们的选项。
First off, the problem in the asker's code is the fact that setTimeout
is asynchronous while loopsare synchronous. So the logical flaw is that they wrote multiple calls to an asynchronous function from a synchronous loop, expecting them to execute synchronously.
首先,提问者代码中的问题setTimeout
是异步而循环是同步的。所以逻辑缺陷是他们从同步循环中编写了对异步函数的多个调用,期望它们同步执行。
function slide() {
var num = 0;
for (num=0;num<=10;num++) {
setTimeout("document.getElementById('container').style.marginLeft='-600px'",3000);
setTimeout("document.getElementById('container').style.marginLeft='-1200px'",6000);
setTimeout("document.getElementById('container').style.marginLeft='-1800px'",9000);
setTimeout("document.getElementById('container').style.marginLeft='0px'",12000);
}
}
What happens in reality, though, is that...
然而,现实中发生的事情是……
- The loop "simultaneously" creates 44 async timeouts set to execute 3, 6, 9 and 12 seconds in the future. Asker expected the 44 calls to execute one-after-the-other, but instead, they all execute simultaneously.
- 3 seconds after the loop finishes,
container
's marginLeft is set to"-600px"
11 times. - 3 seconds after that, marginLeft is set to
"-1200px"
11 times. - 3 seconds later,
"-1800px"
, 11 times.
- 循环“同时”创建 44 个异步超时,设置为在未来 3、6、9 和 12 秒执行。Asker 期望 44 个调用一个接一个执行,但相反,它们都是同时执行的。
- 循环结束 3 秒后,
container
的 marginLeft 设置为"-600px"
11 次。 - 3 秒后,marginLeft 设置为
"-1200px"
11 次。 - 3 秒后,
"-1800px"
, 11 次。
And so on.
等等。
You could solve this by changing it to:
您可以通过将其更改为:
function setMargin(margin){
return function(){
document.querySelector("#container").style.marginLeft = margin;
};
}
function slide() {
for (let num = 0; num <= 10; ++num) {
setTimeout(setMargin("-600px"), + (3000 * (num + 1)));
setTimeout(setMargin("-1200px"), + (6000 * (num + 1)));
setTimeout(setMargin("-1800px"), + (9000 * (num + 1)));
setTimeout(setMargin("0px"), + (12000 * (num + 1)));
}
}
But that is just a lazy solution that doesn't address the other issues with this implementation. There's a lot of hardcoding and general sloppiness here that ought to be fixed.
但这只是一个懒惰的解决方案,无法解决此实现的其他问题。这里有很多硬编码和一般的草率应该修复。
Lessons learnt from a decade of experience
从十年经验中吸取的教训
As mentioned at the top of this answer, Ender already proposed a solution, but I would like to add on to it, to factor in good practice and modern innovations in the ECMAScript specification.
正如在这个答案的顶部提到的,Ender 已经提出了一个解决方案,但我想补充一下,以考虑 ECMAScript 规范中的良好实践和现代创新。
function format(str, ...args){
return str.split(/(%)/).map(part => (part == "%") ? (args.shift()) : (part)).join("");
}
function slideLoop(margin, selector){
const multiplier = -600;
let contStyle = document.querySelector(selector).style;
return function(){
margin = ++margin % 4;
contStyle.marginLeft = format("%px", margin * multiplier);
}
}
function slide() {
return setInterval(slideLoop(0, "#container"), 3000);
}
Let's go over how this works for the total beginners (note that not all of this is directly related to the question):
让我们来看看这对初学者来说是如何工作的(请注意,并非所有这些都与问题直接相关):
format
格式
function format
It's immensely useful to have a printf-like string formatter function in anylanguage. I don't understand why JavaScript doesn't seem to have one.
在任何语言中都有一个类似 printf 的字符串格式化函数是非常有用的。我不明白为什么 JavaScript 似乎没有。
format(str, ...args)
...
is a snazzy feature added in ES6 that lets you do lots of stuff. I believe it's called the spread operator. Syntax: ...identifier
or ...array
. In a function header, you can use it to specify variable arguments, and it will take every argument at and past the position of said variable argument, and stuff them into an array. You can also call a function with an array like so: args = [1, 2, 3]; i_take_3_args(...args)
, or you can take an array-like object and transform it into an array: ...document.querySelectorAll("div.someclass").forEach(...)
. This would not be possible without the spread operator, because querySelectorAll
returns an "element list", which isn't a true array.
...
是 ES6 中添加的一项时髦功能,可让您做很多事情。我相信它被称为传播运算符。语法:...identifier
或...array
。在函数头中,您可以使用它来指定可变参数,它将获取位于和经过所述可变参数位置的每个参数,并将它们填充到数组中。您也可以调用一个函数,象这样的数组:args = [1, 2, 3]; i_take_3_args(...args)
,也可以采取类似阵列的对象,并将其转换成一个阵列...document.querySelectorAll("div.someclass").forEach(...)
。如果没有扩展运算符querySelectorAll
,这是不可能的,因为返回一个“元素列表”,它不是一个真正的数组。
str.split(/(%)/)
I'm not good at explaining how regex works. JavaScript has two syntaxes for regex. There's the OO way (new RegExp("regex", "gi")
) and there's the literal way (/insert regex here/gi
). I have a profound hatred for regex because the terse syntax it encourages often does more harm than good (and also because they're extremely non-portable), but there are some instances where regex is helpful, like this one. Normally, if you called split with "%"
or /%/
, the resulting array would exclude the "%" delimiters from the array. But for the algorithm used here, we need them included. /(%)/
was the first thing I tried and it worked. Lucky guess, I suppose.
我不擅长解释正则表达式的工作原理。JavaScript 有两种正则表达式语法。有面向对象的方式 ( new RegExp("regex", "gi")
) 和字面的方式 ( /insert regex here/gi
)。我对正则表达式深恶痛绝,因为它鼓励的简洁语法往往弊大于利(也因为它们非常不可移植),但在某些情况下正则表达式很有用,比如这个。通常,如果您使用"%"
或调用 split /%/
,则生成的数组将从数组中排除“%”分隔符。但是对于这里使用的算法,我们需要将它们包括在内。/(%)/
是我尝试的第一件事,它奏效了。幸运的猜测,我想。
.map(...)
map
is a functional idiom. You use map to apply a function to a list. Syntax: array.map(function)
. Function: must return a value and take 1-2 arguments. The first argument will be used to hold each value in the array, while the second will be used to hold the current index in the array. Example: [1,2,3,4,5].map(x => x * x); // returns [1,4,9,16,25]
. See also: filter, find, reduce, forEach.
map
是一个功能习语。您可以使用 map 将函数应用于列表。语法:array.map(function)
. 功能:必须返回一个值并接受 1-2 个参数。第一个参数将用于保存数组中的每个值,而第二个参数将用于保存数组中的当前索引。例子:[1,2,3,4,5].map(x => x * x); // returns [1,4,9,16,25]
。另请参阅:过滤、查找、减少、forEach。
part => ...
This is an alternative form of function. Syntax: argument-list => return-value
, e.g. (x, y) => (y * width + x)
, which is equivalent to function(x, y){return (y * width + x);}
.
这是函数的另一种形式。语法:argument-list => return-value
, eg (x, y) => (y * width + x)
, 等价于function(x, y){return (y * width + x);}
.
(part == "%") ? (args.shift()) : (part)
The ?:
operator pair is a 3-operand operator called the ternary conditional operator. Syntax: condition ? if-true : if-false
, although most people call it the "ternary" operator, since in every language it appears in, it's the only 3-operand operator, every other operator is binary (+, &&, |, =) or unary (++, ..., &, *). Fun fact: some languages (and vendor extensions of languages, like GNU C) implement a two-operand version of the ?:
operator with syntax value ?: fallback
, which is equivalent to value ? value : fallback
, and will use fallback
if value
evaluates to false. They call it the Elvis Operator.
在?:
操作者对是称为三元条件操作者3的操作数操作。语法:condition ? if-true : if-false
,虽然大多数人称它为“三元”运算符,因为在它出现的每种语言中,它是唯一的 3 操作数运算符,其他所有运算符都是二元(+、&&、|、=)或一元(++、 ..., &, *)。有趣的事实:某些语言(以及语言的供应商扩展,如 GNU C)?:
使用语法实现了运算符的两个操作数版本value ?: fallback
,它等效于value ? value : fallback
,并且将使用fallback
ifvalue
评估为 false。他们称之为猫王接线员。
I should also mention the difference between an expression
and an expression-statement
, as I realize this may not be intuitive to all programmers. An expression
represents a value, and can be assigned to an l-value
. An expression can be stuffed inside parentheses and not be considered a syntax error. An expression can itself be an l-value
, although most statements are r-values
, as the only l-value expressions are those formed from an identifier or (e.g. in C) from a reference/pointer. Functions can return l-values, but don't count on it. Expressions can also be compounded from other, smaller expressions. (1, 2, 3)
is an expression formed from three r-value expressions joined by two comma operators. The value of the expression is 3. expression-statements
, on the other hand, are statements formed from a single expression. ++somevar
is an expression, as it can be used as the r-value in the assignment expression-statement newvar = ++somevar;
(the value of the expression newvar = ++somevar
, for example, is the value that gets assigned to newvar
). ++somevar;
is also an expression-statement.
我还应该提到 anexpression
和 an之间的区别expression-statement
,因为我意识到这对所有程序员来说可能并不直观。Anexpression
代表一个值,可以分配给一个l-value
。表达式可以塞在括号内,不会被视为语法错误。表达式本身可以是l-value
,尽管大多数语句是r-values
,因为唯一的左值表达式是由标识符或(例如在 C 中)从引用/指针形成的表达式。函数可以返回左值,但不要指望它。表达式也可以由其他较小的表达式组合而成。(1, 2, 3)
是由三个 r 值表达式由两个逗号运算符连接而成的表达式。表达式的值为 3。expression-statements
另一方面,是由单个表达式形成的语句。++somevar
是一个表达式,因为它可以用作赋值表达式语句中的 r 值newvar = ++somevar;
(newvar = ++somevar
例如,表达式的值是分配给 的值newvar
)。++somevar;
也是一个表达式语句。
If ternary operators confuse you at all, apply what I just said to the ternary operator: expression ? expression : expression
. Ternary operator can form an expression or an expression-statement, so both of these things:
如果三元运算符让您感到困惑,请将我刚才所说的应用于三元运算符:expression ? expression : expression
。三元运算符可以形成一个表达式或一个表达式语句,所以这两个东西:
smallest = (a < b) ? (a) : (b);
(valueA < valueB) ? (backup_database()) : (nuke_atlantic_ocean());
are valid uses of the operator. Please don't do the latter, though. That's what if
is for. There are cases for this sort of thing in e.g. C preprocessor macros, but we're talking about JavaScript here.
是运算符的有效用途。不过,请不要做后者。这if
就是为了。在例如 C 预处理器宏中存在这种情况,但我们在这里讨论的是 JavaScript。
args.shift()
Array.prototype.shift
. It's the mirror version of pop
, ostensibly inherited from shell languages where you can call shift
to move onto the next argument. shift
"pops" the first argument out of the array and returns it, mutating the array in the process. The inverse is unshift
. Full list:
Array.prototype.shift
. 它是 的镜像版本pop
,表面上是从 shell 语言继承的,您可以在其中调用shift
以移至下一个参数。shift
从数组中“弹出”第一个参数并返回它,在此过程中改变数组。反之为unshift
。完整名单:
array.shift()
[1,2,3] -> [2,3], returns 1
array.unshift(new-element)
[element, ...] -> [new-element, element, ...]
array.pop()
[1,2,3] -> [1,2], returns 3
array.push(new-element)
[..., element] -> [..., element, new-element]
See also: slice, splice
参见:切片、拼接
.join("")
Array.prototype.join(string)
. This function turns an array into a string. Example: [1,2,3].join(", ") -> "1, 2, 3"
Array.prototype.join(string)
. 此函数将数组转换为字符串。例子:[1,2,3].join(", ") -> "1, 2, 3"
slide
滑动
return setInterval(slideLoop(0, "#container"), 3000);
First off, we return setInterval
's return value so that it may be used later in a call to clearInterval
. This is important, because JavaScript won't clean that up by itself. I strongly advise against using setTimeout
to make a loop. That is not what setTimeout
is designed for, and by doing that, you're reverting to GOTO. Read Dijkstra's 1968 paper, Go To Statement Considered Harmful,to understand why GOTO loops are bad practice.
首先,我们返回setInterval
的返回值,以便稍后可以在对 的调用中使用它clearInterval
。这很重要,因为 JavaScript 不会自行清理它。我强烈建议不要使用setTimeout
来进行循环。这不是setTimeout
设计的目的,通过这样做,您将恢复到 GOTO。阅读 Dijkstra 1968 年发表的论文,Go To Statement 被认为有害,以了解为什么 GOTO 循环是不好的做法。
Second off, you'll notice I did some things differently. The repeating interval is the obvious one. This will run forever until the interval is cleared, and at a delay of 3000ms. The value for the callbackis the return value of another function, which I have fed the arguments 0
and "#container"
. This creates a closure, and you will understand how this works shortly.
其次,你会注意到我做了一些不同的事情。重复间隔是显而易见的。这将永远运行,直到间隔被清除,并延迟 3000 毫秒。对于价值回调是另一种功能,这是我喂的参数的返回值0
和"#container"
。这将创建一个闭包,您很快就会了解它是如何工作的。
slideLoop
滑环
function slideLoop(margin, selector)
We take margin (0) and selector ("#container") as arguments. The margin is the initial margin value and the selector is the CSS selector used to find the element we're modifying. Pretty straightforward.
我们将边距 (0) 和选择器 ("#container") 作为参数。边距是初始边距值,选择器是用于查找我们正在修改的元素的 CSS 选择器。很简单。
const multiplier = -600;
let contStyle = document.querySelector(selector).style;
I've moved some of the hard coded elements up. Since the margins are in multiples of -600, we have a clearly labeled constant multiplier with that base value.
我已经将一些硬编码元素上移了。由于边距是 -600 的倍数,因此我们有一个带有该基值的明确标记的常数乘数。
I've also created a reference to the element's styleproperty via the CSS selector. Since style
is an object, this is safe to do, as it will be treated as a referencerather than a copy(read up on Pass By Sharingto understand these semantics).
我还通过 CSS 选择器创建了对元素样式属性的引用。因为style
是一个对象,所以这样做是安全的,因为它将被视为引用而不是副本(阅读传递共享以了解这些语义)。
return function(){
margin = ++margin % 4;
contStyle.marginLeft = format("%px", margin * multiplier);
}
Now that we have the scope defined, we return a function that uses said scope. This is called a closure. You should read up on those, too. Understanding JavaScript's admittedly bizarre scoping rules will make the language a lot less painful in the long run.
现在我们已经定义了范围,我们返回一个使用该范围的函数。这称为闭包。你也应该仔细阅读这些内容。从长远来看,理解 JavaScript 公认的奇怪的范围规则将使该语言的痛苦减少很多。
margin = ++margin % 4;
contStyle.marginLeft = format("%px", margin * multiplier);
Here, we simply increment margin and modulus it by 4. The sequence of values this will produce is 1->2->3->0->1->...
, which mimics exactly the behavior from the question without any complicated or hard-coded logic.
在这里,我们简单地增加 margin 并将其模数为 4。这将产生的值序列是1->2->3->0->1->...
,它完全模仿了问题的行为,没有任何复杂或硬编码的逻辑。
Afterwards, we use the format
function defined earlier to painlessly set the marginLeft CSS property of the container. It's set to the currnent margin value multiplied by the multiplier, which as you recall was set to -600. -600 -> -1200 -> -1800 -> 0 -> -600 -> ...
之后,我们使用format
之前定义的函数轻松设置容器的 marginLeft CSS 属性。它被设置为当前边际值乘以乘数,你记得它被设置为 -600。-600 -> -1200 -> -1800 -> 0 -> -600 -> ...
There are some important differences between my version and Ender's, which I mentioned in a commenton their answer. I'm gonna go over the reasoning now:
我的版本和 Ender 的版本之间存在一些重要差异,我在对他们的回答的评论中提到了这一点。我现在要回顾一下推理:
Use
document.querySelector(css_selector)
instead ofdocument.getElementById(id)
使用
document.querySelector(css_selector)
代替document.getElementById(id)
querySelector was added in ES6, if I'm not mistaken. querySelector (returns first found element) and querySelectorAll (returns a list of all found elements) are part of the prototype chain of allDOM elements (not just document
), and take a CSS selector, so there are other ways to find an element than just by its ID. You can search by ID (#idname
), class (.classname
), relationships (div.container div div span
, p:nth-child(even)
), and attributes (div[name]
, a[href=https://google.com]
), among other things.
如果我没记错的话,在 ES6 中添加了 querySelector。querySelector(返回第一个找到的元素)和 querySelectorAll(返回所有找到的元素的列表)是所有DOM 元素(不仅仅是document
)的原型链的一部分,并带有一个 CSS 选择器,所以除了找到元素还有其他方法通过它的 ID。您可以按 ID ( #idname
)、类 ( .classname
)、关系 ( div.container div div span
, p:nth-child(even)
) 和属性 ( div[name]
, a[href=https://google.com]
) 等进行搜索。
Always track
setInterval(fn, interval)
's return value so it can later be closed withclearInterval(interval_id)
始终跟踪
setInterval(fn, interval)
的返回值,以便以后可以关闭clearInterval(interval_id)
It's not good design to leave an interval running forever. It's also not good design to write a function that calls itself via setTimeout
. That is no different from a GOTO loop. The return value of setInterval
should be stored and used to clear the interval when it's no longer needed. Think of it as a form of memory management.
让间隔永远运行并不是一个好的设计。编写一个通过setTimeout
. 这与 GOTO 循环没有什么不同。的返回值setInterval
应该被存储起来,用于在不再需要的时候清除间隔。将其视为内存管理的一种形式。
Put the interval's callback into its own formal function for readability and maintainability
为了可读性和可维护性,将区间的回调放入自己的正式函数中
Constructs like this
像这样构造
setInterval(function(){
...
}, 1000);
Can get clunky pretty easily, especially if you are storing the return value of setInterval. I strongly recommend putting the function outside of the call and giving it a name so that it's clear and self-documenting. This also makes it possible to call a function that returns an anonymous function, in case you're doing stuff with closures (a special type of object that contains the local state surrounding a function).
很容易变得笨拙,尤其是当您存储 setInterval 的返回值时。我强烈建议将该函数放在调用之外并为其命名,以便它清晰且自我记录。这也使得调用返回匿名函数的函数成为可能,以防您使用闭包(一种特殊类型的对象,包含函数周围的局部状态)。
Array.prototype.forEach
is fine.
Array.prototype.forEach
很好。
If state is kept with the callback, the callback should be returned from another function (e.g.
slideLoop
) to form a closure
如果状态与回调保持一致,则回调应从另一个函数(例如
slideLoop
)返回以形成闭包
You don't want to mush state and callbacks together the way Ender did. This is mess-prone and can become hard to maintain. The state should be in the same function that the anonymous function comes from, so as to clearly separate it from the rest of the world. A better name for slideLoop
could be makeSlideLoop
, just to make it extra clear.
您不想像 Ender 那样将状态和回调混在一起。这很容易造成混乱并且难以维护。状态应该在匿名函数来自的同一个函数中,以便将它与世界的其他部分清楚地分开。一个更好的名字slideLoop
可能是makeSlideLoop
,只是为了让它更加清晰。
Use proper whitespace. Logical blocks that do different things should be separated by one empty line
使用适当的空格。做不同事情的逻辑块应该用一个空行隔开
This:
这个:
print(some_string);
if(foo && bar)
baz();
while((some_number = some_fn()) !== SOME_SENTINEL && ++counter < limit)
;
quux();
is much easier to read than this:
比这更容易阅读:
print(some_string);
if(foo&&bar)baz();
while((some_number=some_fn())!==SOME_SENTINEL&&++counter<limit);
quux();
A lot of beginners do this. Including little 14-year-old me from 2009, and I didn't unlearn that bad habit until probably 2013. Stop trying to crush your code down so small.
很多初学者都是这样做的。包括 2009 年的 14 岁小我,大概直到 2013 年我才改掉那个坏习惯。别再试图把你的代码压缩得这么小了。
Avoid
"string" + value + "string" + ...
. Make a format function or useString.prototype.replace(string/regex, new_string)
避免
"string" + value + "string" + ...
。制作格式功能或使用String.prototype.replace(string/regex, new_string)
Again, this is a matter of readability. This:
同样,这是一个可读性问题。这个:
format("Hello %! You've visited % times today. Your score is %/% (%%).",
name, visits, score, maxScore, score/maxScore * 100, "%"
);
is much easier to read than this horrific monstrosity:
比这个可怕的怪物更容易阅读:
"Hello " + name + "! You've visited " + visits + "% times today. " +
"Your score is " + score + "/" + maxScore + " (" + (score/maxScore * 100) +
"%).",
edit: I'm pleased to point out that I made in error in the above snippet, which in my opinion is a great demonstration of how error-prone this method of string building is.
编辑:我很高兴地指出我在上面的代码片段中犯了错误,在我看来,这很好地证明了这种字符串构建方法是多么容易出错。
visits + "% times today"
^ whoops
It's a good demonstration because the entire reason I made that error, and didn't notice it for as long as I did(n't), is because the code is bloody hard to read.
这是一个很好的演示,因为我犯那个错误的全部原因是因为代码很难阅读,而且我没有注意到它(不是)。
Always surround the arguments of your ternary expressions with parens. It aids readability and prevents bugs.
始终用括号将三元表达式的参数括起来。它有助于提高可读性并防止错误。
I borrow this rule from the best practices surrounding C preprocessor macros. But I don't really need to explain this one; see for yourself:
我从围绕 C 预处理器宏的最佳实践中借用了这条规则。但我真的不需要解释这个;你自己看:
let myValue = someValue < maxValue ? someValue * 2 : 0;
let myValue = (someValue < maxValue) ? (someValue * 2) : (0);
I don't care how well you think you understand your language's syntax, the latter will ALWAYS be easier to read than the former, and readability is the the only argument that is necessary. You read thousands of times more code than you write. Don't be a jerk to your future self long-term just so you can pat yourself on the back for being clever in the short term.
我不在乎你认为你对你的语言的语法有多了解,后者总是比前者更容易阅读,可读性是唯一必要的论点。您阅读的代码比编写的代码多数千倍。从长远来看,不要对未来的自己当个混蛋,这样你就可以为自己在短期内的聪明而感到欣慰。
回答by Naftali aka Neal
try this:
尝试这个:
window.onload = function start() {
slide();
}
function slide() {
setInterval("document.getElementById('container').style.marginLeft='-600px'",3000);
setInterval("document.getElementById('container').style.marginLeft='-1200px'",6000);
setInterval("document.getElementById('container').style.marginLeft='-1800px'",9000);
setInterval("document.getElementById('container').style.marginLeft='0px'",12000);
}
setInterval
is basically an 'infinite loop' and it wont black up the browser. it waits the required time, then goes again
setInterval
基本上是一个“无限循环”,它不会使浏览器变黑。它等待所需的时间,然后再去
回答by Arian saputra
you can use requestAnimationFrame() function like in the below,
您可以使用如下所示的 requestAnimationFrame() 函数,
function unlimited () {
requestAnimationFrame(unlimited);
console.log("arian")
}
unlimited();