Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/457.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用javascript for循环更改svg元素属性_Javascript_Html_Web - Fatal编程技术网

使用javascript for循环更改svg元素属性

使用javascript for循环更改svg元素属性,javascript,html,web,Javascript,Html,Web,我在练习网络编程时遇到了这个问题。 问题是,当我尝试在for循环中重复增加圆的半径时,它不会显示每次迭代后的更改结果,尽管它会显示上一次迭代的结果,即当我达到40时,将显示半径为40的圆。那么这里有什么问题 <!DOCTYPE html> <html> <head> <script type="text/javascript"> function strokeincr(){ var circl = document.getElementById("

我在练习网络编程时遇到了这个问题。 问题是,当我尝试在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>

函数strokeincr(){
var circl=document.getElementById(“circ”);
var i;

对于(i=10;i嗯,首先警报停止进程,但更重要的是,
for循环
告诉程序在大括号之间运行代码,它将尽可能快速高效地运行代码。正如@YonaAppletree指出的,尽管没有在官方规范中编写,但大多数浏览器(如果不是全部的话)都是如此实现相同或细微不同的处理规则,并且不允许在for循环期间重新绘制视图。这是一种节省资源的优化,实际上从最终用户的角度看,这并没有多大区别,因为即使它不这样做,代码的处理速度通常也会比人眼快这意味着这是一个很好的优化,但也意味着您当前的代码无法按预期的方式工作

我们可以做的是设置一个间隔计时器,当
i
等于40或更大时,它会自动清除。一个间隔包含两个参数

setInterval(函数,时间单位为毫秒)

ms
为毫秒。1000毫秒等于1秒。所提供的功能将以指定的间隔反复执行,直到间隔被清除。例如:

setInterval(function(){console.log(“hi!”)},1000)

将每隔1000毫秒(相当于1秒)向您的控制台打印“hi!”。此操作不会停止,因为它永远不会清除

通过将此函数指定给一个变量,我们可以确保在
i
达到40或更大时清除它(停止函数)

这是为变量指定间隔的方式:

var myIntervalTimer=setInterval(函数,时间单位为毫秒)

要清除该间隔,请调用
clearInterval(间隔名称)
。例如:

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,它将清除间隔计时器


函数strokeincr(){
var circl=document.getElementById(“circ”);
var i=10;
var myIntervalTimer=setInterval(函数(){
循环设置属性(“r”,i);
如果(i>=40)clearInterval(myIntervalTimer);
i++;
}, 250);
}
#第1部分svg{
宽度:200px;
高度:200px;
背景颜色:粉红色;
}
点击我

单击按钮时会执行整个循环。如果要在每次单击按钮时增加圆的半径,则必须采用不同的方法

function strokeincr() {
    var circl = document.getElementById("circ");
    var r = parseInt(circl.getAttribute("r"));
    circl.setAttribute("r", r + 10);
}

这是一个非常有趣的问题,我会尽力回答

由于浏览器优化,您遇到了存在的意外行为。这与重新绘制有关。您在循环的每一步都在更改圆的半径。如果浏览器必须在每次迭代中重新绘制屏幕,这将是一个非常苛刻的操作

那么浏览器供应商做了什么呢?他们(显然)将重新绘制延迟到循环完成之后。这有意义,对吗

当您开始使用警报暂停循环时,这突然变得可见(注意DOM中的值在每次迭代时是如何变化的,但屏幕不会重新绘制)

如果您想设置此更改的动画,有几种方法。您可以使用css转换或使用JavaScripts
window.requestAnimationFrame()
。但这超出了您的问题范围;)


PS:这个答案是基于我自己的观察和我刚才读到的一些文章,所以如果你知道一些关于这种重新绘制行为的官方文档,请发表评论(我自己也有点好奇)。

这里的问题与浏览器如何更新屏幕和事件如何工作有关。浏览器有一种称为“事件循环”的东西浏览器等待某些事件发生,如用户单击按钮,然后执行相关代码。修改文档的调用,如setAttribute调用,不会直接导致屏幕更新。相反,它们正在更新DOM(文档对象模型)定义浏览器应在屏幕上显示的内容

只有在所有事件处理代码完成后,屏幕才会更新。因此,从10循环到40,更新圆的半径。但是浏览器只在循环完成后检查值。因此,您只能看到最终值

如@zfrisch的回答中所述,解决此问题的一种方法是使用浏览器的事件调度功能。这些功能允许您要求浏览器在稍后启动事件(并使用您选择的代码处理)

您可以使用三个主要的调度函数:
setTimeout(callback,delayInMs)
setInterval(callback,intervalInMs)
,以及
requestAnimationFrame(callback)
。您可以在文档中查找进一步的解释,但一般来说,对于动画,您应该使用
requestAnimationFrame

requestAnimationFrame
基本上要求浏览器在渲染完所有内容并准备好渲染新内容后执行一些代码

使用
requestAnimationFrame
,您的示例可能如下所示:


函数strokeincr(){
//注意使用const而不是var。