当我遇到这个问题时,我正在练习网络编程。 问题是当我尝试在for循环中重复增加圆的半径时,它不会在每次迭代后显示变化的结果,尽管它在最后一次迭代时显示结果,即当我达到40时,圆圈与显示半径40。那么这里的问题是什么?
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function strokeincr(){
var circl = document.getElementById("circ");
var i;
for(i=10;i<=40;i++)
{
alert("for i="+i);//this was just to see the value of i changing.
circl.setAttribute("r",i);
}
}
</script>
<style>
#div1 svg{
width:200px;
height: 200px;
background-color:pink;
}
</style>
</head>
<body>
<div id="div1">
<svg>
<circle id="circ" cx="100" cy="100" r="10" fill="green"></circle>
</svg>
</div>
<button onclick="strokeincr()"> click me</button>
</body>
</html>
答案 0 :(得分:1)
此处的问题与浏览器如何更新屏幕以及事件的工作方式有关。浏览器有一个叫做“事件循环”的东西。浏览器等待某些事件发生,例如用户单击按钮,然后执行相关代码。修改文档的调用(如setAttribute调用)不会直接导致屏幕更新。相反,他们正在更新DOM(文档对象模型),它定义了浏览器应该在屏幕上显示的内容。
只有在所有事件处理代码完成后,屏幕才会更新。因此,您从10循环到40,更新圆的半径。但浏览器只是在循环结束后才会检查值。所以你只能看到最终的价值。
如@ zfrisch的回答所述,解决此问题的一种方法是使用浏览器的事件调度功能。这些功能允许您在稍后的时间要求浏览器触发事件(并使用您选择的代码处理它)。
您可以使用三种主要的日程安排功能:setTimeout(callback, delayInMs)
,setInterval(callback, intervalInMs)
和requestAnimationFrame(callback)
。您可以查看文档以获取进一步说明,但一般来说,对于动画,您应该使用requestAnimationFrame
。
requestAnimationFrame
基本上要求浏览器稍后执行某些代码,之后它已呈现所有内容并准备呈现新内容。
使用requestAnimationFrame
,您的示例可能如下所示:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function strokeincr() {
// Note the use of const instead of var. It indicates a variable that we won't change, and ensures that we don't change it.
const circl = document.getElementById("circ");
// We need to know how long our animation should last, so we can compute where we are.
// Note that since the varaible contains milliseconds, we label it as such for clarity.
const animationDurationMs = 1000;
// The starting time of the animation (in milliseconds since the epoch), so we can compute where we are in the animation later.
const startTimeMs = Date.now();
// Define the starting and ending values for the animation for later computation
const startRadius = 10;
const endRadius = 40;
function incrementAnimation() {
// Get the now-current time so we can compute the animation progress
const currentTimeMs = Date.now();
// Compute where we are in the animation as a fraction, ensuring we don't go over 1, using Math.min
const animationFraction = Math.min(
1,
(currentTimeMs - startTimeMs) / animationDurationMs
);
// Compute what the current radius should be, given where we are in the animation, using liner interpolation
const currentRadius = startRadius + (endRadius - startRadius) * animationFraction;
// Update the circle with the new radius
circl.setAttribute("r", currentRadius);
// Check if there is more animating to do, and if so, request that this function is run again after the screen is updated.
if (animationFraction < 1)
requestAnimationFrame(incrementAnimation);
}
// Start the animation by calling the animation function directly.
incrementAnimation();
}
</script>
<style>
#div1 svg {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div id="div1">
<svg>
<circle id="circ" cx="100" cy="100" r="10" fill="green"></circle>
</svg>
</div>
<button onclick="strokeincr()">click me</button>
</body>
</html>
答案 1 :(得分:0)
好吧,首先警报会停止进程,但更重要的是for loop
告诉程序在它的大括号之间运行代码,它会尽可能快速有效地执行。正如@YonaAppletree指出的那样,尽管没有在官方规范中编写,但大多数浏览器(如果不是全部)都实现了相同或平凡不同的处理规则,并且在for循环期间不允许重新绘制视图。这是一种节省资源的优化,实际上它与最终用户的观点没有多大区别,因为即使它没有做到这一点,代码通常会比人眼更快地处理能辨别出来。这意味着它是一个很好的优化,但它也意味着您当前的代码无法按预期工作。
我们可以做的是设置一个间隔计时器,它会在i
等于或大于40之后自行清除。间隔需要两个参数
setInterval( function , time in ms )
ms
是毫秒。 1000毫秒等于1秒。提供的功能将以指定的间隔反复重复,直到间隔被清除。例如:
setInterval( function() { console.log("hi!") }, 1000)
将打印&#34; hi!&#34;每1000毫秒到你的控制台,相当于1秒。这永远不会停止,因为它永远不会清除。
通过将此函数分配给变量,我们确保在i
达到40或更高时我们可以清除它(停止函数)。
这是为变量分配间隔的方法:
var myIntervalTimer = setInterval(function, time in ms)
清除您拨打clearInterval( name of interval )
的间隔。例如:
clearInterval(myIntervalTimer)
然后我们将其插入您已经建立的代码中,瞧!
var i = 10;
var myIntervalTimer = setInterval(function() {
console.log("i is" + i);
circl.setAttribute("r",i);
if(i >= 40) clearInterval(myIntervalTimer);
i++;
}, 250);
我们现在有一个定时器,每隔四分之一秒(250ms)会增加圆的半径,如果i
等于或大于40,则会清除间隔定时器。
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function strokeincr(){
var circl = document.getElementById("circ");
var i = 10;
var myIntervalTimer = setInterval(function() {
circl.setAttribute("r",i);
if(i >= 40) clearInterval(myIntervalTimer);
i++;
}, 250);
}
</script>
<style>
#div1 svg{
width:200px;
height: 200px;
background-color:pink;
}
</style>
</head>
<body>
<div id="div1">
<svg>
<circle id="circ" cx="100" cy="100" r="10" fill="green"></circle>
</svg>
</div>
<button onclick="strokeincr()"> click me</button>
</body>
</html>
&#13;
答案 2 :(得分:0)
单击按钮时将执行整个循环。如果您想在每次单击按钮时增加圆的半径,则必须采用不同的方法。
let publickey : SecKey =
"# -----BEGIN PUBLIC KEY----- some key ----END PUBLIC KEY----- #" as! SecKey
答案 3 :(得分:0)
这是一个非常有趣的问题。我会尽力回答它。
由于浏览器优化,您遇到了存在的意外行为。它与重新绘制有关。您正在循环的每一步更改圆的半径。如果浏览器必须在每次迭代时重新绘制屏幕,那将是一项非常苛刻的操作。
那么浏览器供应商做了什么?他们(显然)推迟了重复,直到循环结束。有道理吗?
当您开始使用警报暂停循环时,这突然变得明显(请注意DOM中的值在每次迭代时的确如何变化,但屏幕不会重新绘制)。
如果您想要为此更改制作动画,则有几种方法。您可以使用css转换或使用JavaScripts window.requestAnimationFrame()
。但这超出了你的问题的范围;)。