该项目使用CreateJS,并且构建为可以通过添加JSON数据在Canvas中创建各种游戏和练习。为了演示这个问题,我将使用“字母板”的示例,您可以点击每个字母的图片,听到它大声朗读。问题是他们都播放最后一个字母的声音。
创建练习时,将从数据库加载JSON数据。它添加了用户指定的所有内容,但在添加区域时存在问题。这些是用户定义的,包括坐标,大小以及单击时要执行的操作。它通过循环执行此操作,检查要添加的区域类型(圆形,矩形,隐藏矩形等),通过CreateJS添加它,然后分配eventListener以执行预定义操作。但是,最后,所有eventListeners都执行相同的操作,即 last 。但是,我使用.bind()并尝试在匿名函数中创建具有相同结果的闭包。
这是区域数据的样子(以字母A为例):
{"coords":"25,30,67,55","type":"rectangleHidden","actions":[{"do":"playSound","data":{"asset":{"id":"a","src":"a.mp3"}}}]}
您可以使用JSON编辑器在线更好地了解: Data for A to C
所有资产均已预加载且可访问。加载所有资源后,将构建场景并运行此功能:
p.addAreas = function (areas, event) {
var i = 0,
length = (typeof areas != 'undefined') ? areas.length : 0;
for (; i < length; i++) {
var x = i;
switch (areas[i].type) {
case 'rectangleHidden':
var rectangleHidden = new ui.Rectangle(areas[i].coords, this.STRIKE, this.FILL, this.STROKE_STYLE, false);
rectangleHidden.alpha = 0.01;
this.addChild(rectangleHidden);
rectangleHidden.addEventListener('click', this.doActions.bind(event, areas[i].actions, this));
break;
default :
break;
}
}
}
我省略了开关的不同情况,因为这个例子只使用了rectangleHidden。同样适用于下一个,我只包含playSound。所以addEventListener分配的函数就是这个:
p.doActions = function (actions, scene) {
"use strict";
var i = 0,
length = actions.length;
// cleans up scene
p.cleanUp(scene);
// adds actions in sequence order
for (; i < length; i++) {
var action = actions[i],
data = action.data;
// switch over action
switch (action.do) {
case 'playSound':
var delayTime = Number(data.delay || 0);
var looper = Number(data.loop || 0);
new createjs.Sound.play(data.asset.id, { delay: delayTime, loop: looper });
break;
default:
break;
}
}
}
即使正在使用 .bind(),在这种情况下,所有字母都会播放声音&#34; c.mp3&#34; 而不是他们各自的声音。我哪里错了? eventListener是否会在某处被覆盖?
我尝试修改将eventListener添加到以下内容的代码:
rectangleHidden.on('click', function (scene, action) {
return scene.doActions.bind(event, action, scene);
}(this, areas[i].actions));
但它仍会产生相同的结果。
我还尝试在另一个项目中创建一个经典闭包,其中eventlistener使用循环中的i值调用此函数:
function saveNumber(value) {
return function () { console.log(value); };
}
在另一个项目中,正如预期的那样,每个列表项在单击时从控制台中的数组中写入自己的编号。当我尝试将此函数添加到当前项目中的eventlistener时,它仍会每次写出循环的最后一个值,在本例中为 2 。
rectangleHidden.addEventListener('click', saveNumber(i));
它们之间有什么区别?(该函数也在循环外部和addAreas表达式之外定义。)
我可以补充说这个指的是Canvas-stage本身,我最初没有编写这段代码,我只是想解决这个问题。在我从 createjs-2013.12.12 更新到 createjs-2015.05.21 之前,相同的代码似乎一直在工作,但切换回它没有任何区别。如果您需要,请向我询问更多详情!
我已经阅读了JavaScript closure inside loops – simple practical example,虽然它看起来似乎可以帮助我乍一看,但它并没有解决我的问题。在答案中解释了如何使用闭包和.bind()来解决问题,但是,我的问题是,尽管使用了,但仍然会出现。
答案 0 :(得分:0)
问题确实存在于CreateJS并更新到最新版本。之前的类是通过使用initialize-method进行扩展的,后来改为使用SuperClass_constructor,如解释here.
由于旧代码,按钮未正确创建并导致.on()和.addEventListener()方法出现问题。循环一直在工作!