gpt4 book ai didi

javascript - 如何在循环中添加点击形状?

转载 作者:行者123 更新时间:2023-11-29 09:53:41 25 4
gpt4 key购买 nike

我将文本数组传递给我的 circleCreate 函数,该函数为每个文本创建一个楔形。我想要做的是为每个楔形添加一个点击事件,所以当用户点击一个楔形时,它会用每个楔形文本抛出一个警报。

但它不起作用。只有外圈是警告文本。它总是说相同的文字。两个内圈警报未定义。

http://jsfiddle.net/Yushell/9f7JN/

var layer = new Kinetic.Layer();

function circleCreate(vangle, vradius, vcolor, vtext) {
startAngle = 0;
endAngle = 0;
for (var i = 0; i < vangle.length; i++) {
// WEDGE
startAngle = endAngle;
endAngle = startAngle + vangle[i];
var wedge = new Kinetic.Wedge({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: vradius,
angleDeg: vangle[i],
fill: vcolor,
stroke: 'black',
strokeWidth: 1,
rotationDeg: startAngle
});
/* CLICK NOT WORKING
wedge.on('click', function() {
alert(vtext[i]);
});*/
layer.add(wedge);
}
stage.add(layer);
}

最佳答案

这是您在使用异步 JavaScript 代码(例如事件处理程序)时会遇到的典型问题。 for 函数中的 circleCreate() 循环使用一个变量 i,它为每个楔形递增。在您使用 i 创建楔子的地方,这很好:

            angleDeg: vangle[i],

但是在 click 事件处理程序中使用它时会失败:
            alert(vtext[i]);

这是为什么?

当您使用 new Kinetic.Wedge() 调用创建楔形时,这是直接在循环内完成的。此代码同步运行;它使用 i 的值,因为它存在于循环的这个特定迭代运行的那一刻。

但是 click 事件处理程序在那个时候没有运行。如果您从不单击,它可能根本无法运行。当您单击一个楔形时,它的事件处理程序会在原始循环完成运行很久之后被调用。

那么,事件处理程序运行时 i 的值是多少?它是代码最初运行时留在其中的任何值。当 for 等于 i 时,这个 vangle.length 循环退出——换句话说, i 超过了数组的末尾,因此 vangle[i]undefined

您可以使用闭包轻松解决此问题,只需为每个循环迭代调用一个函数:
var layer = new Kinetic.Layer();

function circleCreate(vangle, vradius, vcolor, vtext) {
startAngle = 0;
endAngle = 0;
for (var i = 0; i < vangle.length; i++) {
addWedge( i );
}
stage.add(layer);

function addWedge( i ) {
startAngle = endAngle;
endAngle = startAngle + vangle[i];
var wedge = new Kinetic.Wedge({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: vradius,
angleDeg: vangle[i],
fill: vcolor,
stroke: 'black',
strokeWidth: 1,
rotationDeg: startAngle
});
wedge.on('click', function() {
alert(vtext[i]);
});
layer.add(wedge);
}
}

现在发生的是,调用 addWedge() 函数会为每次循环迭代单独捕获 i 的值。如您所知,每个函数都可以有自己的局部变量/参数,并且 i 中的 addWedge() 是该函数的局部变量——特别是该函数的每个单独调用的局部变量。 (请注意,因为 addWedge() 是它自己的函数,所以该函数内部的 i 与外部 i 函数中的 circleCreate() 不同。如果这令人困惑,可以给它一个不同的名称。)

Updated fiddle

更好的方法

这就是说,我建议采用不同的方法来构建数据。当我阅读您的代码时, Angular 和文本数组引起了我的注意:
var anglesParents = [120, 120, 120];
var parentTextArray = ['Parent1', 'Parent2', 'Parent3'];

子代和孙代有类似但更长的数组对。

您可以将这些数组中的值与 vtext[i] 中的 vangle[i]circleCreate() 引用一起使用。

一般来说,除非有特殊原因使用这样的并行数组,否则如果将它们组合成单个对象数组,您的代码将变得更清晰:
[
{ angle: 120, text: 'Parent1' },
{ angle: 120, text: 'Parent2' },
{ angle: 120, text: 'Parent3' }
]

对于嵌套的圆环,我们可以更进一步,将所有三个环组合成一个大型对象数组,描述整个嵌套环集。你有这些数组的地方:
var anglesParents = [120, 120, 120];
var anglesChildren = [120, 60, 60, 60, 60];
var anglesGrandchildren = [
33.33, 20, 23.33, 43.33, 22.10, 25.26,
12.63, 28, 32, 33, 27, 36, 14.4, 9.6
];
var grandchildrenTextArray = [
'GrandCHild1', 'GrandCHild2', 'GrandCHild3', 'GrandCHild4',
'GrandCHild5', 'GrandCHild6', 'GrandCHild7', 'GrandCHild8',
'GrandCHild9', 'GrandCHild10', 'GrandCHild11', 'GrandCHild12',
'GrandCHild13', 'GrandCHild14', 'GrandCHild15', 'GrandCHild16'
];
var childrenTextArray = [
'Child1', 'Child2', 'Child3', 'Child4', 'Child5'
];
var parentTextArray = ['Parent1', 'Parent2', 'Parent3'];

这将是:
var rings = [
{
radius: 200,
color: 'grey',
slices: [
{ angle: 33.33, text: 'GrandChild1' },
{ angle: 20, text: 'GrandChild2' },
{ angle: 23.33, text: 'GrandChild3' },
{ angle: 43.33, text: 'GrandChild4' },
{ angle: 22.10, text: 'GrandChild5' },
{ angle: 25.26, text: 'GrandChild6' },
{ angle: 12.63, text: 'GrandChild7' },
{ angle: 28, text: 'GrandChild8' },
{ angle: 32, text: 'GrandChild9' },
{ angle: 33, text: 'GrandChild10' },
{ angle: 27, text: 'GrandChild10' },
{ angle: 36, text: 'GrandChild12' },
{ angle: 14.4, text: 'GrandChild13' },
{ angle: 9.6, text: 'GrandChild14' }
]
},
{
radius: 150,
color: 'darkgrey',
slices: [
{ angle: 120, text: 'Child1' },
{ angle: 60, text: 'Child2' },
{ angle: 60, text: 'Child3' },
{ angle: 60, text: 'Child4' },
{ angle: 60, text: 'Child5' }
]
},
{
radius: 100,
color: 'lightgrey',
slices: [
{ angle: 120, text: 'Parent1' },
{ angle: 120, text: 'Parent2' },
{ angle: 120, text: 'Parent3' }
]
}
];

现在这比原来的更长,所有的 angle:text: 属性名称,但是这些东西通过服务器和浏览器使用的 gzip 压缩非常好地压缩出来。

更重要的是,它有助于简化和阐明代码并避免错误。你有没有注意到你的 anglesGrandchildrengrandchildrenTextArray 的长度不一样? :-)

使用单个对象数组而不是并行数组可以防止出现这样的错误。

要使用此数据,请删除 circleCreate() 函数和对它的以下调用:
circleCreate(anglesGrandchildren, 200, "grey", grandchildrenTextArray);
circleCreate(anglesChildren, 150, "darkgrey", childrenTextArray);
circleCreate(anglesParents, 100, "lightgrey", parentTextArray);

并将它们替换为:
function createRings( rings ) {
var startAngle = 0, endAngle = 0,
x = stage.getWidth() / 2,
y = stage.getHeight() / 2;

rings.forEach( function( ring ) {
ring.slices.forEach( function( slice ) {
startAngle = endAngle;
endAngle = startAngle + slice.angle;
var wedge = new Kinetic.Wedge({
x: x,
y: y,
radius: ring.radius,
angleDeg: slice.angle,
fill: ring.color,
stroke: 'black',
strokeWidth: 1,
rotationDeg: startAngle
});
wedge.on('click', function() {
alert(slice.text);
});
layer.add(wedge);
});
});

stage.add(layer);
}

createRings( rings );

现在这段代码并没有比原来的更短,但一些细节更清晰: slice.angleslice.text 清楚地表明 Angular 和文本属于同一个切片对象,而原始的 vangle[i]vtext[i] 就剩下我们了希望 vanglevtext 数组是正确的匹配数组,并且彼此正确排列。

我还使用了 .forEach() 而不是 for 循环;由于您使用的是 Canvas,我们知道您使用的是现代浏览器。一件好事是 forEach() 使用函数调用,因此它会自动为您提供一个闭包。

此外,我将 xy 的计算移到循环之外,因为它们对于每个楔形都是相同的。

这是带有此更新代码和数据的 latest fiddle

关于javascript - 如何在循环中添加点击形状?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17092696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com