使用 Mootools 添加事件处理程序.addEvent() 在某个地方神秘地失败

发布于 2024-12-07 03:15:18 字数 1655 浏览 0 评论 0原文

我正在为一个网络应用程序开发一些 JS,但遇到了一个相当令人难以置信的问题。不幸的是,我无法发布完整的代码,因为它是尚未发布的项目的一部分。这个问题让我和我问过的一些同事都感到困惑——据我所知,它应该有效。

现在,解决实际问题:用户在某些表单字段中输入一些信息并单击“确认”图像,然后 AJAX 请求被发送回服务器。服务器进行一些处理,然后发回带有状态和一些附加数据的响应。用户正在使用的模式对话窗口中会显示一条状态消息,并会显示一个带有链接的图标。下面是 Mootools Request.JSON 对象的“onComplete”处理程序,删除了一些错误条件处理:

  onComplete: function(response) {
    if (response) {
      if (response.status == 0) {
        // this means the request was successful
        licenses = response.licenses;
        updateControls();
        licenseList();
        // here I add the status message...
        $("createform_result").innerHTML = "<img src=\'/media/com_supportarea/images/db_success.png\' /> License created. Download:<br /><br />";
        // ...and the download "link"
        if (response.tlsid) {
          $("createform_result").innerHTML += "<a href=\"#\" id=\"newtlslic-"+response.tlsid+"\"><img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>";
          // this line is here for debugging only, to make sure this
          // block of code is run (it is) and the element is found (it is)
          $("newtlslic-"+response.tlsid).style.border = "1px solid red";
          $("newtlslic-"+response.tlsid).addEvent("click", function(e) {
            // I've stripped out all other code, also for debugging
            e.stop();
          });
        }
      }
    }
  }

出现带有链接的消息和图标,应用样式(出现红色边框),并且在 Firefox 或 Chrome 中不会出现错误消息。但是,单击该图标会导致 URL 附加一个 #(e.stop()) 不执行任何操作)。根据EventBug插件,链接没有附加点击事件。看起来 .addEvent() 在这里什么也没做。

现在,这是他们最关心的问题:这是为什么?我该如何解决它?帮助!

I'm having a rather mind-boggling problem with some JS I'm working on for a web app. Unfortunately, I can't post the full code for this, as it's part of a not-yet-released project. This issue has both me and some colleagues I asked stumped - from what I can tell, it should work.

Now, to the actual problem: a user enters some info into some form fields and clicks a "confirm" image, whereupon an AJAX request is sent back to the server. The server does some processing, then sends back a response with a status and some attached data. A status message is displayed in the modal dialogue window the user was using, and an icon with a link is displayed. Here's the "onComplete" Handler for the Mootools Request.JSON object, with some error condition handling removed:

  onComplete: function(response) {
    if (response) {
      if (response.status == 0) {
        // this means the request was successful
        licenses = response.licenses;
        updateControls();
        licenseList();
        // here I add the status message...
        $("createform_result").innerHTML = "<img src=\'/media/com_supportarea/images/db_success.png\' /> License created. Download:<br /><br />";
        // ...and the download "link"
        if (response.tlsid) {
          $("createform_result").innerHTML += "<a href=\"#\" id=\"newtlslic-"+response.tlsid+"\"><img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>";
          // this line is here for debugging only, to make sure this
          // block of code is run (it is) and the element is found (it is)
          $("newtlslic-"+response.tlsid).style.border = "1px solid red";
          $("newtlslic-"+response.tlsid).addEvent("click", function(e) {
            // I've stripped out all other code, also for debugging
            e.stop();
          });
        }
      }
    }
  }

The message and icon with link appears, the style is applied (red border appears) and no error message appears in either Firefox or Chrome. However, clicking the icon results in a # being appended to the URL (the e.stop()) does nothing). According to the EventBug plugin, no click event is attached to the link. It seems like .addEvent() simply does nothing here.

Now, and here's they prize question: why is this and how can I fix it? Help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空名 2024-12-14 03:15:18

JavaScript 中的字符串是不可变的。当您执行以下操作时:

$("createform_result").innerHTML += "<a href=\"#\" id=\"newtlslic-"+response.tlsid+"\"><img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>";

您将innerHTML 作为字符串引用。它的作用是,它将属性提取到一个字符串中,将其与您传递的其他字符串连接起来,然后最后返回一个新字符串,该字符串被设置为innerHTML。

这样做时,您每次迭代都会覆盖元素的内容。

附加到元素的事件不是由通用 ID 处理程序完成的 - 它们依赖于 DOM 中的元素,然后读取元素 UID(mootools 分配给所有传递元素的内部属性)并将事件回调添加到元素中该 UID 后面的存储。

你可以通过执行 console.log(element.retrieve("events")); 来查看这项工作,

如果你重写了innerHTML,内部元素将被重新创建并获得一个新的UID,这意味着回调现在指向一个空指针,因为 UID 是元素存储中的键。

我对你在这里所做的事情可能是错误的,因为我实际上没有看到你再次重写它的地方,但你剥离的代码中可能有一个,特别是如果你正在运行一个循环。

处理这个问题的最好方法是使用其他方法 - 使用事件委托。

它可以允许您通过某些选择器将单击事件添加到父元素。这适用于在任何时间以任何方式添加的任何匹配元素。

例如。

// add this once, outside the loop 
$("createform_result").addEvent("click:relay(a.editLink)", function(event, element) {
    console.log(this === element); 
    console.log(this === event.target);
    console.log(this.get("data-id"));
}); 

// then as you loop the results, just inject the els or use innerHTML or whatever...
new Element("a.editLink", {
    html: '<img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>',
    "data-id": response.tlsid
}).inject($("createform_result"));

事件委托现在是 1.4.0 中 mootools 核心的一部分,或者是之前版本中 mootools-more 的一部分。

玩得开心!

strings in javascript are immutable. when you do stuff like:

$("createform_result").innerHTML += "<a href=\"#\" id=\"newtlslic-"+response.tlsid+"\"><img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>";

you are referencing the innerHTML as a string. what this does is, it fetches the property into a string, concatenates it to the other strings you pass on and then returns a new string in the end, which gets set as the innerHTML.

in doing so, you are OVERWRITING the contents of the element every time, for every iteration.

events attached to elements are not done by a generic ID handler - they rely on the element being in the DOM, then the element UID (an internal property mootools assigns to all passed elements) is being read and the event callback is added into the element storage behind that UID.

you can see this work by doing console.log(element.retrieve("events"));

if you rewrite the innerHTML, the inner element is re-created and gets a NEW UID, which means the callback now points to an empty pointer as the UID is the key in element storage.

I may be wrong about what you are doing here as I don't actually see the bit where you rewrite it again, but there probably is one in the code you stripped, especially if you are running a loop.

the best way to deal with this is something else - use Event Delegation.

it can allow you to add the click event to the parent element instead via some selector. this will work for ANY element added in any way at any time that matches.

eg.

// add this once, outside the loop 
$("createform_result").addEvent("click:relay(a.editLink)", function(event, element) {
    console.log(this === element); 
    console.log(this === event.target);
    console.log(this.get("data-id"));
}); 

// then as you loop the results, just inject the els or use innerHTML or whatever...
new Element("a.editLink", {
    html: '<img src=\'/media/com_supportarea/images/download_small.png\' /></a> <em>TLS</em>',
    "data-id": response.tlsid
}).inject($("createform_result"));

Event delegation is now a part of mootools core in 1.4.0 or is in mootools-more in previous versions.

have fun!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文