使用David Flanagan的普通JS脚本使我的书签可拖动。
我注意到我可以在按键期间将指针从拖动条上移开,弹出窗口可能会或可能不会跟随指针或突然对齐指针。
Firefox 8和9的总体体验并不令人印象深刻。 XP上的IE8按设计工作
它适用于书签,所以我可以使用像jQuery或YUI这样的框架。
问题:如何改善mousedown / drag的粘性,以便窗口保持连接鼠标onMousedown和onmousemove使用普通JS?
另外请帮助我让getLeft和getTop在IE / Chrome和Fx中工作,这样弹出窗口就只限于视口。
NEW AND FIXED DEMO HERE(谢谢techfoobar)
function getTop(top) {
// if (console) console.log('y:'+top+':'+document.body.clientHeight);
if (top<0) return 0;
if (top>=(document.body.clientHeight-40)) return document.body.clientHeight-40;
return top;
}
function getLeft(left) {
// if (console) console.log('x:'+left+':'+document.body.clientWidth);
if (left<0) return 0;
if (left>=(document.body.clientWidth-500)) return document.body.clientWidth-500;
return left;
}
// This code is from the book JavaScript: The Definitive Guide, 6th Edition (ISBN #978-0596805524). Copyright 2011 by David Flanagan.
function getScrollOffsets(w) {
w = w || window;
if (w.pageXOffset != null) return {x: w.pageXOffset, y:w.pageYOffset};
var d = w.document;
if (document.compatMode == "CSS1Compat")
return {x:d.documentElement.scrollLeft, y:d.documentElement.scrollTop};
return { x: d.body.scrollLeft, y: d.body.scrollTop };
}
function zDrag(elementToDrag, event) { var scroll = getScrollOffsets();
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);
}
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) {
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();
}
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
};
}
// end drag code
答案 0 :(得分:3)
这应该解决粘性问题。
我可以从您的演示网站上看到,当鼠标位于内部iframe上方时,我们遇到了粘性问题。这是因为内部iframe不会将事件冒泡到处理zDrag的mousemove事件的根文档元素。
我通过附加一个覆盖div(不可见但在那里)来解决这个问题,该div占用根文档的整个区域,从而有效地防止内部iframe获取mousemove。因为这个overlay div是我们的根文档元素的直接后代,所以它正确地冒充了mousemove事件。
更改包括获取文档高度的其他方法(来自http://james.padolsey.com/javascript/get-document-height-cross-browser/),以及更改为添加/显示/隐藏叠加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)额外的跨浏览器函数以获取窗口内部宽度和高度(从http://www.javascripter.net/faq/browserw.htm)和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 ...
}
答案 1 :(得分:0)
主要问题是iframe。当鼠标指针进入时,您告别所有已注册的事件。用div替换iframe,Firefox中的内容应该有所改进。 IE似乎只是更快地更新显示;鼠标指针永远不会有机会在IE中输入iframe。