Javascript Webkit和jQuery可拖动跳跃
作为一个实验,我创建了几个div并使用CSS3旋转它们Javascript Webkit和jQuery可拖动跳跃,javascript,jquery,css,webkit,Javascript,Jquery,Css,Webkit,作为一个实验,我创建了几个div并使用CSS3旋转它们 .items { position: absolute; cursor: pointer; background: #FFC400; -moz-box-shadow: 0px 0px 2px #E39900; -webkit-box-shadow: 1px 1px 2px #E39900; box-shadow: 0px 0px 2p
.items {
position: absolute;
cursor: pointer;
background: #FFC400;
-moz-box-shadow: 0px 0px 2px #E39900;
-webkit-box-shadow: 1px 1px 2px #E39900;
box-shadow: 0px 0px 2px #E39900;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
然后,我随机对它们进行了样式设置,并通过jQuery使它们可以拖动
$('.items').each(function() {
$(this).css({
top: (80 * Math.random()) + '%',
left: (80 * Math.random()) + '%',
width: (100 + 200 * Math.random()) + 'px',
height: (10 + 10 * Math.random()) + 'px',
'-moz-transform': 'rotate(' + (180 * Math.random()) + 'deg)',
'-o-transform': 'rotate(' + (180 * Math.random()) + 'deg)',
'-webkit-transform': 'rotate(' + (180 * Math.random()) + 'deg)',
});
});
$('.items').draggable();
拖拽是有效的,但我注意到拖拽div时突然跳了起来,这只适用于webkit浏览器,而在Firefox中一切正常
如果我去掉位置:绝对风格,“跳跃”更糟糕。我认为webkit和gecko之间的转换原点可能有所不同,但默认情况下它们都位于元素的中心
我已经到处搜索过了,但只找到了关于滚动条或可排序列表的结果
这是我的问题的工作演示。尝试在Safari/Chrome和Firefox中查看它
这是webkit中的错误还是浏览器呈现webkit的方式?这是由于DragTable依赖于jquery
offset()
函数和offset()
使用本机js函数getBoundingClientRect()
。最终,这是一个jquery核心无法补偿与getBoundingClientRect()
相关的不一致性的问题。Firefox版本的getBoundingClientRect()
忽略了css3转换(旋转),而chrome/safari(webkit)则没有
这就是问题的一个例证
一个老套的解决办法:
替换中的以下内容:
与
//The element's absolute position on the page minus margins
this.offset = this.positionAbs = { top: this.element[0].offsetTop,
left: this.element[0].offsetLeft };
最后是一个修补过的版本。大卫·威克的答案非常有用。。。谢谢 在这里,我为可调整大小的编码了相同的解决方法,因为它有相同的问题: 在中搜索以下内容: 并替换为:
var o = this.options, iniPos = {top:this.element[0].offsetTop,left:this.element[0].offsetLeft}, el = this.element;
David Wick在上述总体方向上是正确的,但计算正确的坐标远比这复杂得多。这里有一个更精确的monkey补丁,它基于MIT许可的Firebug代码,应该可以在更多具有复杂DOM的情况下使用: 替换为: //The element's absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset(); //元素在页面上的绝对位置减去页边距 this.offset=this.positionAbs=this.element.offset(); 使用更少的黑客(确保获取全部内容;您需要滚动): //元素在页面上的绝对位置减去页边距 this.offset=this.positionAbs=getViewOffset(this.element[0]); 函数getViewOffset(节点){ 变量x=0,y=0,win=node.ownerDocument.defaultView | | window; if(节点)addOffset(节点); 返回{left:x,top:y}; 函数getStyle(节点){ return node.currentStyle | |//IE getComputedStyle(节点“”); } 函数addOffset(节点){ var p=node.offsetParent,style,X,Y; x+=parseInt(node.offsetLeft,10)| 0; y+=parseInt(node.offsetTop,10)| 0; 如果(p){ x-=parseInt(p.scrollLeft,10)| | 0; y-=parseInt(p.scrollTop,10)| | 0; if(p.nodeType==1){ var parentStyle=getStyle(p) ,localName=p.localName ,parent=node.parentNode; if(parentStyle.position!=“static”){ x+=parseInt(parentStyle.borderLeftWidth,10)| 0; y+=parseInt(parentStyle.borderTopWidth,10)| | 0; 如果(localName=='TABLE'){ x+=parseInt(parentStyle.paddingLeft,10)| 0; y+=parseInt(parentStyle.paddingTop,10)| | 0; } else if(localName==“BODY”){ style=getStyle(节点); x+=parseInt(style.marginLeft,10)| | 0; y+=parseInt(style.marginTop,10)| | 0; } } else if(localName==“BODY”){ x+=parseInt(parentStyle.borderLeftWidth,10)| 0; y+=parseInt(parentStyle.borderTopWidth,10)| | 0; } while(p!=父级){ x-=parseInt(parent.scrollLeft,10)| 0; y-=parseInt(parent.scrollTop,10)| 0; parent=parent.parentNode; } addOffset(p); } } 否则{ 如果(node.localName==“BODY”){ style=getStyle(节点); x+=parseInt(style.borderLeftWidth,10)| 0; y+=parseInt(style.borderTopWidth,10)| | 0; var htmlStyle=getStyle(node.parentNode); x-=parseInt(htmlStyle.paddingLeft,10)| 0; y-=parseInt(htmlStyle.paddingTop,10)| | 0; } 如果((X=node.scrollLeft))X+=parseInt(X,10)| 0; 如果((Y=node.scrollTop))Y+=parseInt(Y,10)| | 0; } } }
很遗憾,DOM没有在本机公开这些计算。@ecmanaut:很好的解决方案。谢谢你的努力。为了帮助别人,我把你的解决方案变成了猴子补丁。将下面的代码复制到一个文件中。加载jquery-ui.js后包括该文件,如下所示:
<script src="javascripts/jquery/jquery.js"></script>
<script src="javascripts/jquery/jquery-ui.js"></script>
<!-- the file containing the monkey-patch to draggable -->
<script src="javascripts/jquery/patch_draggable.js"></script>
您必须将可拖动元素的父容器设置为“position:relative”。我绘制了一个图像,以指示在不同浏览器上旋转后的偏移量,如@David Wick的回答 如果您不想修补或修改jquery.ui.draggable.js,下面是要修复的代码
$(document).ready(function () {
var recoupLeft, recoupTop;
$('#box').draggable({
start: function (event, ui) {
var left = parseInt($(this).css('left'),10);
left = isNaN(left) ? 0 : left;
var top = parseInt($(this).css('top'),10);
top = isNaN(top) ? 0 : top;
recoupLeft = left - ui.position.left;
recoupTop = top - ui.position.top;
},
drag: function (event, ui) {
ui.position.left += recoupLeft;
ui.position.top += recoupTop;
}
});
});
或者你可以看到我使用了很多解决方案来让拖动正常工作。但是,它对dropzone的反应仍然是错误的(就像它没有旋转一样)。解决方案实际上是使用相对定位的父容器 这节省了我很多时间
<div id="drawarea">
<div class="rect-container h">
<div class="rect"></div>
</div>
</div>
.rect-container {
position:relative;
}
.rect容器{
位置:相对位置;
}
这里的完整解决方案(不是我提供的):
我也做了很多研究。就像这样,jQuery没有任何计划在将来改变当前的行为。所有提交的关于该主题的票证均已关闭。因此,首先让parentcontainers相对定位。它就像一个魔咒,应该是未来的。我更喜欢这种解决方法,因为它保留了
<script src="javascripts/jquery/jquery.js"></script>
<script src="javascripts/jquery/jquery-ui.js"></script>
<!-- the file containing the monkey-patch to draggable -->
<script src="javascripts/jquery/patch_draggable.js"></script>
function monkeyPatch_mouseStart() {
// don't really need this, but in case I did, I could store it and chain
var oldFn = $.ui.draggable.prototype._mouseStart ;
$.ui.draggable.prototype._mouseStart = function(event) {
var o = this.options;
function getViewOffset(node) {
var x = 0, y = 0, win = node.ownerDocument.defaultView || window;
if (node) addOffset(node);
return { left: x, top: y };
function getStyle(node) {
return node.currentStyle || // IE
win.getComputedStyle(node, '');
}
function addOffset(node) {
var p = node.offsetParent, style, X, Y;
x += parseInt(node.offsetLeft, 10) || 0;
y += parseInt(node.offsetTop, 10) || 0;
if (p) {
x -= parseInt(p.scrollLeft, 10) || 0;
y -= parseInt(p.scrollTop, 10) || 0;
if (p.nodeType == 1) {
var parentStyle = getStyle(p)
, localName = p.localName
, parent = node.parentNode;
if (parentStyle.position != 'static') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
if (localName == 'TABLE') {
x += parseInt(parentStyle.paddingLeft, 10) || 0;
y += parseInt(parentStyle.paddingTop, 10) || 0;
}
else if (localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.marginLeft, 10) || 0;
y += parseInt(style.marginTop, 10) || 0;
}
}
else if (localName == 'BODY') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
}
while (p != parent) {
x -= parseInt(parent.scrollLeft, 10) || 0;
y -= parseInt(parent.scrollTop, 10) || 0;
parent = parent.parentNode;
}
addOffset(p);
}
}
else {
if (node.localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.borderLeftWidth, 10) || 0;
y += parseInt(style.borderTopWidth, 10) || 0;
var htmlStyle = getStyle(node.parentNode);
x -= parseInt(htmlStyle.paddingLeft, 10) || 0;
y -= parseInt(htmlStyle.paddingTop, 10) || 0;
}
if ((X = node.scrollLeft)) x += parseInt(X, 10) || 0;
if ((Y = node.scrollTop)) y += parseInt(Y, 10) || 0;
}
}
}
//Create and append the visible helper
this.helper = this._createHelper(event);
//Cache the helper size
this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable
if($.ui.ddmanager)
$.ui.ddmanager.current = this;
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Store the helper's css position
this.cssPosition = this.helper.css("position");
this.scrollParent = this.helper.scrollParent();
//The element's absolute position on the page minus margins
this.offset = this.positionAbs = getViewOffset(this.element[0]);
this.offset = {
top: this.offset.top - this.margins.top,
left: this.offset.left - this.margins.left
};
$.extend(this.offset, {
click: { //Where the click happened, relative to the element
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
},
parent: this._getParentOffset(),
relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
});
//Generate the original position
this.originalPosition = this.position = this._generatePosition(event);
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
//Set a containment if given in the options
if(o.containment)
this._setContainment();
//Trigger event + callbacks
if(this._trigger("start", event) === false) {
this._clear();
return false;
}
//Recache the helper size
this._cacheHelperProportions();
//Prepare the droppable offsets
if ($.ui.ddmanager && !o.dropBehaviour)
$.ui.ddmanager.prepareOffsets(this, event);
this.helper.addClass("ui-draggable-dragging");
//JWL: Hier vindt de jump plaats
this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
return true;
};
}
monkeyPatch_mouseStart();
$(document).ready(function () {
var recoupLeft, recoupTop;
$('#box').draggable({
start: function (event, ui) {
var left = parseInt($(this).css('left'),10);
left = isNaN(left) ? 0 : left;
var top = parseInt($(this).css('top'),10);
top = isNaN(top) ? 0 : top;
recoupLeft = left - ui.position.left;
recoupTop = top - ui.position.top;
},
drag: function (event, ui) {
ui.position.left += recoupLeft;
ui.position.top += recoupTop;
}
});
});
<div id="drawarea">
<div class="rect-container h">
<div class="rect"></div>
</div>
</div>
.rect-container {
position:relative;
}
$(document).ready(function(){
// backup original handler
var _mouseStart = $.ui.draggable.prototype._mouseStart;
$.ui.draggable.prototype._mouseStart = function(event) {
//remove the transform
var transform = this.element.css('transform');
this.element.css('transform', 'none');
// call original handler
var result = _mouseStart.call(this, event);
//restore the transform
this.element.css('transform', transform);
return result;
};
});