Javascript 为什么在此脚本中可以将鼠标从拖动区域中拉出?

Javascript 为什么在此脚本中可以将鼠标从拖动区域中拉出?,javascript,mouseevent,drag,gecko,Javascript,Mouseevent,Drag,Gecko,使用David Flanagan提供的简单JS脚本使我的bookmarklet可拖动 我注意到,我可以在“向下键”期间将指针从拖动条上移开,弹出窗口可能会也可能不会跟随指针,或者突然捕捉到指针 Firefox8和Firefox9的总体体验并不令人印象深刻。XP上的IE8按设计工作 它是为bookmarklet设计的,所以我不能使用jQuery或YUI这样的框架 问题:如何提高鼠标向下/拖动的粘性,以便使用普通JS在mousedown和mousemove上保持窗口与鼠标的连接 另外,请帮助我使ge

使用David Flanagan提供的简单JS脚本使我的bookmarklet可拖动

我注意到,我可以在“向下键”期间将指针从拖动条上移开,弹出窗口可能会也可能不会跟随指针,或者突然捕捉到指针

Firefox8和Firefox9的总体体验并不令人印象深刻。XP上的IE8按设计工作

它是为bookmarklet设计的,所以我不能使用jQuery或YUI这样的框架

问题:如何提高鼠标向下/拖动的粘性,以便使用普通JS在mousedown和mousemove上保持窗口与鼠标的连接

另外,请帮助我使getLeft和getTop在IE/Chrome和Fx中工作,以便弹出窗口仅限于视口

(谢谢techfoobar)

函数getTop(顶部){
//if(console)console.log('y:'+top+':'+document.body.clientHeight);
if(top=(document.body.clientHeight-40))返回document.body.clientHeight-40;
返回顶部;
}
函数getLeft(左){
//if(console)console.log('x:'+left+':'+document.body.clientWidth);
if(left=(document.body.clientWidth-500))返回document.body.clientWidth-500;
左转;
}
//这段代码来自《JavaScript:权威指南》第6版(ISBN#978-0596805524)。David Flanagan版权所有2011。
函数getScrollOffsets(w){
w=w | |窗;
if(w.pageXOffset!=null)返回{x:w.pageXOffset,y:w.pageYOffset};
var d=w.文件;
如果(document.compatMode==“CSS1Compat”)
返回{x:d.documentElement.scrollLeft,y:d.documentElement.scrollTop};
返回{x:d.body.scrollLeft,y:d.body.scrollTop};
}
函数zDrag(elementToDrag,event){var scroll=getScrollOffsets();
var startX=event.clientX+scroll.x;
var startY=event.clientY+scroll.y;
var origX=elementToDrag.offsetLeft;
变量origY=元素todrag.offsetTop;
var deltaX=startX-origX;
var deltaY=恒星-恒星;
如果(document.addEventListener){
document.addEventListener(“mousemove”,moveHandler,true);
document.addEventListener(“mouseup”,upHandler,true);
} 
如果(文件附件){
elementToDrag.setCapture();
elementToDrag.attachEvent(“onmousemove”,moveHandler);
elementToDrag.attachEvent(“onmouseup”,upHandler);
elementToDrag.attachEvent(“onlosecapture”,upHandler);
} 
if(event.stopPropagation)event.stopPropagation();
else event.cancelBubble=true;
if(event.preventDefault)event.preventDefault();
else event.returnValue=false;
函数moveHandler(e){
如果(!e)e=window.event;
var scroll=getScrollOffsets();
elementToDrag.style.left=getLeft(e.clientX+scroll.x-deltaX,true)+“px”;
elementToDrag.style.top=getTop(e.clientY+scroll.y-deltaY,true)+“px”;
如果(e.stopPropagation)e.stopPropagation();
否则e.cancelBubble=true;
};
函数upHandler(e){
如果(!e)e=window.event;
如果(document.removeEventListener){
document.removeEventListener(“mouseup”,upHandler,true);
removeEventListener(“mousemove”,moveHandler,true);
} 
如果(document.detachEvent){
elementToDrag.detachEvent(“onlosecapture”,upHandler);
elementToDrag.detachEvent(“onmouseup”,upHandler);
elementToDrag.detachEvent(“onmousemove”,moveHandler);
elementToDrag.releaseCapture();
} 
如果(e.stopPropagation)e.stopPropagation();
否则e.cancelBubble=true;
};
} 
//端阻力代码

主要问题是iframe。当鼠标指针进入时,表示您对所有已注册事件说再见。用div替换iframe,Firefox中的情况应该会有所改进。IE似乎只是更新显示速度更快;鼠标指针永远没有机会进入IE中的iframe。

这应该考虑粘性问题

我可以从您的演示站点上看到,当鼠标位于内部iframe上时,我们会遇到粘性问题。这是因为内部iframe不会将事件冒泡到处理zDrag的mousemove事件的根文档元素

我通过附加一个覆盖div(不可见但在那里)解决了这个问题,该div占据了根文档的整个区域,从而有效地防止内部iframe获得mousemove。由于这个overlay div是我们的根文档元素的直接后代,所以它正确地弹出mousemove事件

更改包括用于获取文档高度(从)的附加方法,以及用于添加/显示/隐藏覆盖div的zDrag方法的更改

function getDocHeight() {
  var D = document;
  return Math.max(
    Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
    Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
    Math.max(D.body.clientHeight, D.documentElement.clientHeight)
  );
}

function zDrag(elementToDrag, event) { 
  var scroll = getScrollOffsets();

  // create/show overlay - over the inner iframe and everything else
  var div = document.getElementById('overlay');
  if(div==null) {
    div = document.createElement('div');
    div.id = 'overlay';
    div.style.position = 'absolute';
    div.style.left = '0px';
    div.style.top = '0px';
    div.style.width = '100%';
    div.style.height = getDocHeight()+'px';
    div.style.zIndex = 99999;
    div.style.cursor = 'move';
    var bodyTag = document.getElementsByTagName("body")[0];
    bodyTag.appendChild(div);
  }
  else {
    div.style.display = 'block';
  }

  var startX = event.clientX + scroll.x;
  var startY = event.clientY + scroll.y;
  var origX = elementToDrag.offsetLeft;
  var origY = elementToDrag.offsetTop;
  var deltaX = startX - origX;
  var deltaY = startY - origY;
  if (document.addEventListener) { 
    document.addEventListener("mousemove", moveHandler, true);
    document.addEventListener("mouseup", upHandler, true);
  } 
  else if (document.attachEvent) { 
    /*elementToDrag.setCapture();
    elementToDrag.attachEvent("onmousemove", moveHandler);
    elementToDrag.attachEvent("onmouseup", upHandler);
    elementToDrag.attachEvent("onlosecapture", upHandler);*/

    // attach the events to the document element, to ensure we dont 'miss' any move events.
    document.setCapture();
    document.attachEvent("onmousemove", moveHandler);
    document.attachEvent("onmouseup", upHandler);
    document.attachEvent("onlosecapture", upHandler);
  } 

  if (event.stopPropagation) event.stopPropagation();
  else event.cancelBubble = true;
  if (event.preventDefault) event.preventDefault();
  else event.returnValue = false;

  function moveHandler(e) { 
    if (!e) e = window.event;
    var scroll = getScrollOffsets();
    elementToDrag.style.left = getLeft(e.clientX + scroll.x - deltaX,true) + "px";
    elementToDrag.style.top = getTop(e.clientY + scroll.y - deltaY,true) + "px";
    if (e.stopPropagation) e.stopPropagation();
    else e.cancelBubble = true;
  };

  function upHandler(e) { 

    // dragging is over. hide the overlay.
    document.getElementById('overlay').style.display = 'none';

    if (!e) e = window.event;
    if (document.removeEventListener) { 
      document.removeEventListener("mouseup", upHandler, true);
      document.removeEventListener("mousemove", moveHandler, true);
    } 
    else if (document.detachEvent) { 
      /*elementToDrag.detachEvent("onlosecapture", upHandler);
      elementToDrag.detachEvent("onmouseup", upHandler);
      elementToDrag.detachEvent("onmousemove", moveHandler);
      elementToDrag.releaseCapture();*/
      document.detachEvent("onlosecapture", upHandler);
      document.detachEvent("onmouseup", upHandler);
      document.detachEvent("onmousemove", moveHandler);
      document.releaseCapture();

    } 
    if (e.stopPropagation) e.stopPropagation();
    else e.cancelBubble = true;
  };
}
编辑-用于限制视口内的拖动

现在,它将限制拖动到视口内部(即浏览器窗口内部宽度和高度)。更改包括a)一个额外的跨浏览器函数,用于获取窗口内部宽度和高度(from);b)更改moveHandler()方法(在zDrag方法内部),以检查和强制执行限制

function getWindowSize() {
  var winW = 630, winH = 460;
  if (document.body && document.body.offsetWidth) {
    winW = document.body.offsetWidth;
    winH = document.body.offsetHeight;
  }
  if (document.compatMode=='CSS1Compat' && document.documentElement && document.documentElement.offsetWidth ) {
    winW = document.documentElement.offsetWidth;
    winH = document.documentElement.offsetHeight;
  }
  if (window.innerWidth && window.innerHeight) {
    winW = window.innerWidth;
    winH = window.innerHeight;
  }
  return {width: winW, height: winH};
}
在zDrag()中,将当前的moveHandler替换为:

function moveHandler(e) { 
  if (!e) e = window.event;
  var scroll = getScrollOffsets();

  var newLeft = getLeft(e.clientX + scroll.x - deltaX,true);
  if(newLeft + elementToDrag.offsetWidth > winDim.width) {
    newLeft = winDim.width - elementToDrag.offsetWidth;
  }
  elementToDrag.style.left = newLeft + "px";

  var newTop = getTop(e.clientY + scroll.y - deltaY,true);
  if(newTop + elementToDrag.offsetHeight > winDim.height) {
    newTop = winDim.height - elementToDrag.offsetHeight;
  }
  elementToDrag.style.top = newTop + "px";

  if (e.stopPropagation) e.stopPropagation();
  else e.cancelBubble = true;
};
编辑-winDim变量

winDim是存储视口尺寸的变量。它在移动处理程序中用于检查移动对象是否在视口中。我将其保留在外部,以避免在每次移动事件中重新计算窗口尺寸,从而降低性能

var winDim = null;

function zDrag(...) {

  if(winDim == null) winDim = getWindowSize

  // ... rest of the code in zDrag ...

}

因此,您的问题仅适用于Firefox,或者..?可能是IE以外的其他浏览器。IE8工作良好。请使您的代码更具可读性。但鼠标指针不应该有机会进入iframe,因为我在div上执行鼠标向下操作,这应该会将鼠标向下的点粘到指针上。我必须用一个iframe来解释zindex的理由,嗯?我们把iframe放在里面,但是用div覆盖它。非常有趣。谢谢你,我来测试一下。当我看到“overlay”时,我想-哦,不,这将停止与iframe的交互,但是如果在拖动停止时隐藏/删除它,它当然会起作用
var winDim = null;

function zDrag(...) {

  if(winDim == null) winDim = getWindowSize

  // ... rest of the code in zDrag ...

}