如何使用JavaScript动态更改事件处理程序?

时间:2011-01-02 10:28:33

标签: php javascript javascript-events

我对任何AJAX都很陌生并遇到了以下问题。我希望有人能够帮助我。我确定这是一个简单的修复,但我只是没有看到它:(

我要做的是动态更改元素的onmouseover和onmouseout事件,这里是相关的代码位:

HTML元素(请注意其中有多个,因此是其ID的动态部分)

<?
if (ownsgame($id, $userid)) {?>
    <a><img src="images/collection/got.gif" id="ownedimage<?=$id?>" title="<?=$itemtitle?> (<?=$platformdisplay?>) is in your collection" alt="You own this game" align="center" width="62" height="22" onclick="changeOwned('<?=$id?>')" onmouseover="changeImageSrc('ownedimage<?=$id?>', 'images/collection/del.gif')" onmouseout="changeImageSrc('ownedimage<?=$id?>', 'images/collection/got.gif')"/></a>
<? } else { ?>
    <a><img src="images/collection/add.gif" id="ownedimage<?=$id?>" title="Add <?=$itemtitle?> (<?=$platformdisplay?>) to your collection" alt="You do not own this game" align="center" width="62" height="22" onclick="changeOwned('<?=$id?>')" onmouseover="changeImageSrc('ownedimage<?=$id?>', 'images/collection/add.gif')" onmouseout="changeImageSrc('ownedimage<?=$id?>', 'images/collection/add.gif')"/></a>
<?} ?>

JavaScript函数:

function changeImageSrc(id, src) {
    document.getElementById(id).src = src;
}

(相关)AJAX代码:

var http = createRequestObject();
var jsid = "";

function changeOwned(id) {
    http.open('get', 'changeowned.php?id=' + id + '&user=<?=$userid?>');
    jsid = id;
    http.onreadystatechange = processResponse;
    http.send(null);
}

function processResponse() {
if((http.readyState == 4) && (http.status == 200)){

    var response = http.responseText;
    var elementid = 'ownedimage' + jsid;
    var element = document.getElementById(elementid);
    if (response == "1") {
        image = "images/collection/got.gif";
        alt = "you own this game";
        mouseoverstr = 'images/collection/del.gif';
        mouseoutstr = 'images/collection/got.gif';
        element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/add.gif')}, false);
        element.removeEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/add.gif')}, false);
    } else {
        image = "images/collection/add.gif";
        alt = "add this game to your collection";
        mouseoverstr = 'images/collection/add.gif';
        mouseoutstr = 'images/collection/add.gif';
        element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/got.gif')}, false);
        element.removeEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/del.gif')}, false);
    }
    element.src = image;
    element.alt = alt;
    element.addEventListener('mouseover', function(){changeImageSrc('ownedimage' + jsid, mouseoverstr)}, false);
    element.addEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, mouseoutstr)}, false);
}
}

一开始似乎工作正常,但会产生一些奇怪的行为。引用的PHP工作正常并产生正确的响应。图像的src和alt也会发生变化。事实上,它首先看起来像新的鼠标悬停/外出工作。但是,当您点击网站上的多个图像(具有不同的ID)时,它们会突然开始相互影响。当鼠标悬停在一个上时,另一个会更改其图像。为什么会这样?我真的很无能,因为jsid部分很好,我不明白为什么mouseover会突然改变两个图像。看起来好像将不同ID的多个事件处理程序分配给同一个图像元素。不知道为什么会这样。我希望有一些掌握更多AJAX知识的人可以帮助我,非常沮丧:(

2 个答案:

答案 0 :(得分:2)

那里有几件事: - )

1)addEventListenerremoveEventListener使用较新的DOM2处理程序链,它与旧的“DOM0”样式(onXYZ属性)完全分开。因此,您无法通过最初通过removeEventListener attriubte分配的onXYZ删除处理程序。为此,请为属性的反射属性指定“”。

element.onmouseover = "";

2)当您使用removeEventListener时,您必须传入您最初使用的相同的函数引用。所以这永远不会删除任何东西:

element.removeEventListener('mouseout', function(){changeImageSrc('ownedimage' + jsid, 'images/collection/got.gif')}, false);

...因为它创建了一个全新的函数来传递给removeEventListener,并且因为该函数不在事件处理程序链上,所以忽略了调用。

我可能通过使用单个事件处理程序来解决问题,但随后更改它使用的数据。您可以使用data-xyz属性(例如data-oversrcdata-stdsrc或其他类似内容)将备用图片网址存储在实际元素本身上。然后你的两个函数(一个用于mouseover,一个用于mouseout)根据图像更改URL:

function handleMouseOver() {
    this.src = this.getAttribute('data-oversrc');
}

function handleMouseOut() {
    this.src = this.getAttribute('data-stdsrc');
}

我会完全从元素中删除onXYZ个处理程序,并将它们替换为一次性addEventListener(IE上为attachEvent),并分配这两个。

与所有自定义属性一样,

data-xyz属性在HTML4及更早版本中无效。从HTML5开始,他们会进行验证,因为无论如何主要浏览器都无法解决无效属性问题,您可以立即开始使用它们。


偏离主题#1 :现在,我通常建议您使用JavaScript库来平滑浏览器差异并为您实现有用的功能。例如,使用addEventListenerremoveEventListener的代码在IE9之前的IE上会失败,因为它根本就没有这些方法。如果您使用的是jQueryPrototypeYUIClosureany of several others等库,他们会为您处理这些内容,以便您可以专注在你自己的增值上。

偏离主题#2 :当鼠标经过元素时,mouseover事件会重复发生,并且mouseout和/ mouseenter都会在DOM中冒泡。这意味着对于像你这样的悬停效果,如果你不能使用CSS(你不能在IE6上),你最好使用mouseleavemouseenter事件,大部分时间。但这些是大多数其他浏览器不支持的IE特定事件。输入任何体面的JavaScript库。 :-)他们会在不直接支持它们的浏览器上模仿mouseleave和{{1}}。在上面的列表中,我确信jQuery和Prototype可以做到这一点;如果其他人没有类似的功能,我会感到惊讶。

答案 1 :(得分:2)

问题是removeEventListener,它不像您认为的那样工作。当你这样做时发生了什么:

element.removeEventListener('mouseout',function(){/* handlers */},false);

function() { }是您刚刚创建的匿名函数,而不是作为侦听器的元素上的现有函数...所以当它去除时 em> listener,它只是不存在,因为那是一个不同的匿名函数(即使它具有完全相同的代码,它是一个不同的引用),您通过addEventListener分配。

有一些解决办法,因为你正在制作AJAX请求我假设你没有在这里制作数百/数千,所以你可以存储你指定的处理程序以便以后删除它们,比如这样:

var http = createRequestObject();
var jsid = "";
var handlers = {};

function changeOwned(id) {
    http.open('get', 'changeowned.php?id=' + id + '&user=<?=$userid?>');
    jsid = id;
    http.onreadystatechange = processResponse;
    http.send(null);
}

function processResponse() {
  if((http.readyState == 4) && (http.status == 200)){
    var response = http.responseText,
        elementid = 'ownedimage' + jsid,
        element = document.getElementById(elementid),
        image, alt, mouseoverstr, mouseoutstr;
    if (response == "1") {
        element.src = "images/collection/got.gif";
        element.alt = "you own this game";
        mouseoverstr = 'images/collection/del.gif';
        mouseoutstr = 'images/collection/got.gif';
    } else {
        element.src = "images/collection/add.gif";
        element.alt = "add this game to your collection";
        mouseoverstr = 'images/collection/add.gif';
        mouseoutstr = 'images/collection/add.gif';
    }
    //Create a holder if this is the first time for this elementid
    if(!handlers[elementid]) handlers[elementid] = {};
    //Remove old handlers
    element.removeEventListener('mouseover', handers[elementid].mouseover, false);
    element.removeEventListener('mouseout', handers[elementid].mouseout, false);
    //Store new handlers
    handlers[elementid].mouseover = function(){changeImageSrc('ownedimage' + jsid, mouseoverstr)};
    handlers[elementid].mouseout = function(){changeImageSrc('ownedimage' + jsid, mouseoutstr)};
    //Add hew handlers as listeners
    element.addEventListener('mouseover', handers[elementid].mouseover, false);
    element.addEventListener('mouseout', handers[elementid].mouseout, false);
  }
}