为什么 Raphael 中的拖动会因在气泡阶段的封闭元素中停止 mousemove 的传播而被破坏?

发布于 2024-11-19 03:40:45 字数 2816 浏览 2 评论 0原文

我正在尝试调试复杂的 Web 应用程序中的事件处理错误,但我已将问题简化为一个简单的示例,该示例演示了我感到困惑的行为。

我的示例页面基于 Raphaël 的一个示例,如下所示:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Raphaël · Drag-n-drop Example</title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script src="http://github.com/DmitryBaranovskiy/raphael/raw/master/raphael-min.js"></script>
        <script>
            window.onload = function () {
                $('body').mousemove(function(e) {
                    // console.log("in body's mousemove");
                    // Uncommenting the next line stops the move
                    // function below from being called:
                    // e.stopPropagation();
                });
                var R = Raphael(0, 0, "100%", "100%");
                var r = R.circle(100, 100, 50).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5});
                var start = function () {
                    this.ox = this.attr("cx");
                    this.oy = this.attr("cy");
                    this.animate({r: 70, opacity: .25}, 500, ">");
                },
                move = function (dx, dy) {
                    // console.log("in move function for the circle", this);
                    this.attr({cx: this.ox + dx, cy: this.oy + dy});
                },
                up = function () {
                    this.animate({r: 50, opacity: .5}, 500, ">");
                };
                r.drag(move, start, up);
            };
        </script>
    </head>
    <body>
        <div id="holder"></div>
    </body>
</html>

该版本按预期工作 - 您可以拖动红色圆圈 - 但取消注释 e.stopPropagation() 换行符拖动。如果您有 Firebug 或 Chrome 并取消注释 console.log 行,您可以看到 move 函数从未被调用 - 不知怎的 mousemove 处理程序因为在事件到达圆的处理程序之前调用 body 元素。

我不明白这是怎么回事,因为 body 元素上的 mousemove 处理程序是在事件处理的冒泡阶段设置的。如果我正确理解事件处理的顺序,则 mousemove 处理程序在这里的调用大致如下:

  1. capture Phase: body 元素的 mousemove (null)
  2. capture Phase: svg 元素的 mousemove (null)
  3. capture Phase: the Circle 的 mousemove (null)
  4. bubble Phase: the Circle mousemove(在拖动开始时由 Raphaël 设置,并调用 move 函数)
  5. bubble stage:svg 元素的 mousemove (null)
  6. bubble stage:body 元素的 mousemove(如上设置,并停止传播)

如果这是正确的,我不明白在气泡阶段停止 body 的 mousemove 处理程序中的事件传播如何会中断拖动,因为它应该在圆圈处理事件之后发生。

如果有人能解释一下这个例子中发生了什么,特别是我是否误解了事件处理的工作原理,或者 Raphaël 如何实现拖动有什么特殊之处,那就太好了。

I am trying to debug an event handling bug in a complicated web application, but I've reduced the problem to a simple example that demonstrates the behaviour that I'm confused by.

My example page, based one of the Raphaël examples, is as follows:

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Raphaël · Drag-n-drop Example</title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
        <script src="http://github.com/DmitryBaranovskiy/raphael/raw/master/raphael-min.js"></script>
        <script>
            window.onload = function () {
                $('body').mousemove(function(e) {
                    // console.log("in body's mousemove");
                    // Uncommenting the next line stops the move
                    // function below from being called:
                    // e.stopPropagation();
                });
                var R = Raphael(0, 0, "100%", "100%");
                var r = R.circle(100, 100, 50).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5});
                var start = function () {
                    this.ox = this.attr("cx");
                    this.oy = this.attr("cy");
                    this.animate({r: 70, opacity: .25}, 500, ">");
                },
                move = function (dx, dy) {
                    // console.log("in move function for the circle", this);
                    this.attr({cx: this.ox + dx, cy: this.oy + dy});
                },
                up = function () {
                    this.animate({r: 50, opacity: .5}, 500, ">");
                };
                r.drag(move, start, up);
            };
        </script>
    </head>
    <body>
        <div id="holder"></div>
    </body>
</html>

That version works as expected — you can drag the red circle around — but uncommenting the e.stopPropagation() line breaks dragging. If you have Firebug or Chrome and uncomment the console.log lines, you can see that the move function is never called - somehow the mousemove handler for the body element is being called before the event gets to the circle's handler.

I don't understand how this can be, since the mousemove hander on the body element is set in the bubble phase of event handling. If I understand the order in which events are processed correctly, the order in which mousemove handlers would be called here is approximately:

  1. capture phase: the body element's mousemove (null)
  2. capture phase: the svg element's mousemove (null)
  3. capture phase: the circle's mousemove (null)
  4. bubble phase: the circle's mousemove (set by Raphaël when dragging starts, and which calls the move function)
  5. bubble phase: the svg element's mousemove (null)
  6. bubble phase: the body element's mousemove (set as above, and which stops propagation)

If that's right, I don't understand how stopping propagation of the event in the mousemove handler of body in the bubble phase could break dragging, since it should happen after the circle has dealt with the event.

It would be great if someone could explain what's going on in this example, and in particular whether I've misunderstood how the event handling works, or there's something peculiar about how Raphaël implements dragging.

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

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

发布评论

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

评论(1

沦落红尘 2024-11-26 03:40:45

我尝试在 Raphaël 邮件列表上询问这个问题,那里的回复解释说 Raphaël mousemove 处理程序实际上附加到 document 上,这解释了我所看到的行为。其中一个回复还解释了为什么需要这样实现拖动:

I tried asking about this on the Raphaël mailing list, and the replies there explain that the Raphaël mousemove handler is actually attached to document, which explains the behaviour I was seeing. One of the replies also explains why dragging needs to be implemented like that:

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