为什么 event.clientX 在 firefox 中为 dragend 事件错误地显示为 0?

来自 dragend 的警报将​​ mouseX 显示为零,无论它当前在哪里.这在 Chrome 中运行良好,所以不确定我做错了什么.

The alert from dragend is showing mouseX as zero no matter where it is currently. This works fine in Chrome so not sure what I'm doing wrong.

function move(e,obj,but){
    if(typeof(obj) === 'string'){
        obj = document.getElementById(obj) ;
    }
    
    if(typeof(but) === 'string'){
        but = document.getElementById(but) ;
    }

    //elementCoord(but) ;//get the current coords of the button &
    elementCoord(obj) ;//the container
    
    e = e || window.event ;
    var mouseX = e.clientX ;
    var mouseY = e.clientY ;
            
    //alert('mouseX='+mouseX+', but.XCoord '+but.XCoord) ;
    var diffX = Math.abs(obj.XCoord - mouseX) ;
    var diffY = Math.abs(obj.YCoord - mouseY) ;
    
    but.addEventListener("dragend",function(evt){
        evt = evt || window.event ;
        mouseX = evt.clientX ;
        mouseY = evt.clientY ;
        obj.style.left = mouseX - diffX + 'px';
        obj.style.top = mouseY - diffY + 'px';
        alert('mouseX='+mouseX+' diffX='+diffX) ;
        }
    ,false) ;
    
}

忘了说,elementCoord 只是获取对象的偏移量,将其添加为属性.它适用于所有浏览器.

Forgot to mention, elementCoord just gets the offset of an object adding it as a property. It works fine in all browsers.

推荐答案

这是 Firefox 的官方问题 -- Bugzilla:错误 #505521,在 HTML5 拖动事件期间设置屏幕坐标.我会引用 jbmj 来总结一下,我会加粗他们引用的原始开发人员...

This is officially an issue with Firefox -- Bugzilla: Bug #505521, Set screen coordinates during HTML5 drag event. I'll quote jbmj to summarize, and I will bold the original developer they are quoting...

我不敢相信这个评论
"请注意,虽然它没有指定属性应该设置为什么,只是应该设置它们,而我们目前将它们设置为 0."
从 11 年前开始,它仍然是最先进的.

I can't believe that this comment
"Note though that it doesn't specify what the properties should be set to, just that they should be set and we currently set them to 0."
from 11years ago is still state of the art.

Jay 的评论启发了我,我使用了drop";事件.但这只是一个评论,所以让我把它打造成一个答案.

I was inspired by Jay's comment, to use the "drop" event. But that was only a comment, so let me thresh it out into an answer.

我们的问题:dragend 事件将 e.clientYe.clientX 设置为 0.

Our problem: dragend event has e.clientY and e.clientX set to 0.

我们将如何解决它:documentdrop 事件 也触发 与我们拖动的元素的 dragend 事件.并且:drop 将具有正确的 e.clientYe.clientX 值.

How we will solve it: document's drop event also fires at the same exact time as the element we are dragging's dragend event. And: drop will have the correct values for e.clientY and e.clientX.

两个工作演示,100% 仅 JavaScript 的解决方案:SO 代码片段和 JSBin.SO Code Snippet 控制台有时会吞噬控制台中拖动的元素,而 JSBin 给了我更一致的结果.

Two working demos, 100% JavaScript-Only Solution: SO Code Snippet and JSBin. The SO Code Snippet console sometimes gobbles up the dragged element in the console, and JSBin gave me more consistent results.

var startx = 0;
var starty = 0;
dragStartHandler = function(e) {
  startx = e.clientX;
  starty = e.clientY;
}

dragOverHandler = function(e) {
  e.preventDefault();
  return false;
}

dragEndHandler = function(e) {
  if(!startx || !starty) {
    return false;
  }
  
  var diffx = e.clientX - startx;
  var diffy = e.clientY - starty;
  
  var rect = e.target.getBoundingClientRect();

var offset = { 
                top: rect.top + window.scrollY, 
                left: rect.left + window.scrollX, 
            };
  
  var newleft = offset.left + diffx;
  var newtop = offset.top + diffy;
  
  e.target.style.position = 'absolute';
  e.target.style.left = newleft + 'px';
  e.target.style.top = newtop + 'px';
  
  startx = 0;
  starty = 0;
}

document.getElementsByClassName("draggable")[0].addEventListener('dragstart', dragStartHandler);

document.addEventListener('dragover', dragOverHandler);
document.addEventListener('drop', dragEndHandler);

.draggable {
  border: 1px solid black;
  cursor: move;
  width:250px;
};

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <BR><BR><BR>

  <div id="draggable1" class="draggable" draggable="true">
    Hey, try to drag this element!
  </div>
  
</body>
</html>

说明:

  • dragStartHandler() :绑定到可拖动元素.在这里,我们所做的只是在开始时记录当前的 x/y 坐标.
  • dragOverHandler() :这是绑定到文档的,这样我们就可以覆盖默认的拖动行为.这是进行任何类型的拖动和下降.
  • dragEndHandler() :绑定到 documentdrop.通常,我们希望 this 绑定到 elementdragend,但由于缺少 clientYclientX,我们将它绑定到文档.这正是您在调用 dragend 时想要发生的事情,除非您有 x/y 坐标.
  • dragStartHandler() : This is bound to the draggable element. Here, all we do is record the current x/y coordinates at start.
  • dragOverHandler() : This is bound to the document, so that we can override the default dragover behavior. This is needed to do any type of drag & dropping.
  • dragEndHandler() : This is bound to the document's drop. Normally, we would want this to bind to the element's dragend, but since clientY and clientX are missing, we bind it to the document. This just does exactly what you'd want to happen when dragend is called, except you have x/y coordinates.

相关文章