30

无论当前在哪里,警报dragend都显示为零。mouseX这在 Chrome 中运行良好,所以不确定我做错了什么。

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只是获取对象的偏移量,将其添加为属性。它在所有浏览器中都能正常工作。

4

5 回答 5

7

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

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

我受到 Jay 的评论的启发,使用了“drop”事件。但这只是一个评论,所以让我把它打造成一个答案。

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

我们将如何解决它:documentdrop事件与我们正在拖动的元素的事件同时触发dragend。And:将具有drop 的正确值。e.clientYe.clientX

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

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 绑定到element's dragend,但是由于clientYclientX缺失,我们将它绑定到文档。这正是您在调用 dragend 时想要发生的事情,除非您有 x/y 坐标。
于 2020-08-11T20:22:42.767 回答
0
document.addEventListener("dragover", function( event ) {
      event.preventDefault();
      console.log(event.pageX)
  }, false);

添加监听 console.log (event.pageX)http://jsfiddle.net/zfnj5rv4/dragover

于 2019-08-14T13:19:07.007 回答
0

前几天我在 Firefox 上遇到了同样的问题。

我设法找到了一种解决方法,尽管它依赖于使用全局变量来存储鼠标前后位置。

似乎使事情正常进行的一点是从 ondrop 事件而不是 ondragend 事件中获取 pageX 和 pageY 值。

唯一的问题是 ondrop 不存储拖动的元素或原始鼠标位置(因此需要全局变量)。

var dragDetails = {
   target: null,
   orgMouseX: 0,
   orgMouseY: 0,
   desMouseX: 0,
   desMouseY: 0
}

$("targetElement").on("dragstart", function(event) {
   dragDetails.target = this;
   dragDetails.orgMouseX = event.originalEvent.pageX;
   dragDetails.orgMouseY = event.originalEvent.pageY;
});

$("html").on("drop", function(event) {
   dragDetails.desMouseX = event.originalEvent.pageX;
   dragDetails.desMouseY = event.originalEvent.pageY;
   handleDrag();
});

这是小提琴中的一个示例:https ://jsfiddle.net/L1b6uz2d/2/

它似乎可以在最新版本的 Chrome、Firefox、Edge 和 Internet Explorer 上运行(虽然在 Internet Explorer 上的准确度没有那么好),它也可以在 Android Chrome 上运行。还没有测试任何其他人,我相信代码可以改进。

我确实设法让它在不需要全局变量的情况下工作,但我必须使用 ondrop 然后将目标、pageX 和 pageY 作为参数传递给 ondragend 事件(我没有包含小提琴,因为代码非常难看)

于 2019-02-19T15:06:57.120 回答
0

看起来这个错误可能会在一段时间内仍然是 Firefox 的核心,这里有一个 99% 的补丁:

if(/Firefox\/\d+[\d\.]*/.test(navigator.userAgent)
        && typeof window.DragEvent === 'function'
        && typeof window.addEventListener === 'function') (function(){
    // patch for Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=505521
    var cx, cy, px, py, ox, oy, sx, sy, lx, ly;
    function update(e) {
        cx = e.clientX; cy = e.clientY;
        px = e.pageX;   py = e.pageY;
        ox = e.offsetX; oy = e.offsetY;
        sx = e.screenX; sy = e.screenY;
        lx = e.layerX;  ly = e.layerY;
    }
    function assign(e) {
        e._ffix_cx = cx; e._ffix_cy = cy;
        e._ffix_px = px; e._ffix_py = py;
        e._ffix_ox = ox; e._ffix_oy = oy;
        e._ffix_sx = sx; e._ffix_sy = sy;
        e._ffix_lx = lx; e._ffix_ly = ly;
    }
    window.addEventListener('mousemove', update, true);
    window.addEventListener('dragover', update, true);
    // bug #505521 identifies these three listeners as problematic:
    // (although tests show 'dragstart' seems to work now, keep to be compatible)
    window.addEventListener('dragstart', assign, true);
    window.addEventListener('drag', assign, true);
    window.addEventListener('dragend', assign, true);

    var me = Object.getOwnPropertyDescriptors(window.MouseEvent.prototype),
        ue = Object.getOwnPropertyDescriptors(window.UIEvent.prototype);
    function getter(prop,repl) {
        return function() {return me[prop] && me[prop].get.call(this) || Number(this[repl]) || 0};
    }
    function layerGetter(prop,repl) {
        return function() {return this.type === 'dragover' && ue[prop] ? ue[prop].get.call(this) : (Number(this[repl]) || 0)};
    }
    Object.defineProperties(window.DragEvent.prototype,{
        clientX: {get: getter('clientX', '_ffix_cx')},
        clientY: {get: getter('clientY', '_ffix_cy')},
        pageX:   {get: getter('pageX', '_ffix_px')},
        pageY:   {get: getter('pageY', '_ffix_py')},
        offsetX: {get: getter('offsetX', '_ffix_ox')},
        offsetY: {get: getter('offsetY', '_ffix_oy')},
        screenX: {get: getter('screenX', '_ffix_sx')},
        screenY: {get: getter('screenY', '_ffix_sy')},
        x:       {get: getter('x', '_ffix_cx')},
        y:       {get: getter('y', '_ffix_cy')},
        layerX:  {get: layerGetter('layerX', '_ffix_lx')},
        layerY:  {get: layerGetter('layerY', '_ffix_ly')}
    });
})();

请注意,尽管 OP 的问题仅针对“dragend”,但这是对所有受影响事件的修复。

它从“mousemove”和“dragover”事件中获取鼠标的最后一个准确坐标,并将它们植入到受影响的“dragstart”、“drag”和“dragend”事件中。

请注意,这不是一个精确的修复。x / y 坐标可能略有偏差。由于 'drag' 事件发生在 'dragover' 之前,它使用前一个事件框架的坐标执行。

于 2021-09-17T20:20:05.520 回答
-1

不要使用 e.clientX 或 e.clientY

请改用 e.pageX 和 e.pageY 或 e.targetTouches[0].pageX e.targetTouches[0].pageY(用于触摸屏)。

pageX 指的是文档,clientX 指的是视口。也可以看看:

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX

于 2018-10-31T11:47:41.643 回答