所以我在flex布局上使用jquery-ui sortable来创建一个可以通过拖放重新排序的网格。
大多数情况下,当光标向下移动时,右边的占位符出现,当光标向上移动时,占位符显示在左侧。
我想要的是占位符位于距离光标最近的间隙中。
这是我所拥有的简化版本。
$('#sortable').sortable({
placeholder: 'placeholder',
helper: 'clone',
tolerance: 'pointer',
start: function(event, ui) {
ui.item.show();
$('.block-totara-featured-links-layout').sortable('option', 'cursorAt', {
left: ui.item.width() / 2,
top: ui.item.height() / 2
});
}
});

#sortable{
width: 500px;
display: flex;
flex-wrap: wrap;
}
#sortable div {
margin: 10px;
background-color: #f00;
flex-basis: 100px;
height: 100px;
}
#sortable div.placeholder {
max-width: 4px;
margin-left: -2px;
margin-right: -2px;
background-color: #00F;
}

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<div id="sortable">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
</div>
&#13;
答案 0 :(得分:0)
所以我通过扩展可排序的小部件并修改了一些方法来识别指针是否位于项目的左侧或右侧来修复它。
我会在这里发布代码,以便人们可以了解我做了什么
$.widget('custom.sortableGrid', $.ui.sortable, { // A Hack of the base code so it puts the place holder in the right place
_onRightSide: function(item, event){
return this._isOverAxis(
event.pageX,
item.left + ( item.width / 2 ),
item.width / 2
);
},
_intersectsWithPointer: function( item ) {
var verticalDirection, horizontalDirection,
isOverElementHeight = ( this.options.axis === "x" ) ||
this._isOverAxis(
this.positionAbs.top + this.offset.click.top, item.top, item.height ),
isOverElementWidth = ( this.options.axis === "y" ) ||
this._isOverAxis(
this.positionAbs.left + this.offset.click.left, item.left, item.width ),
isOverElement = isOverElementHeight && isOverElementWidth;
if ( !isOverElement ) {
return false;
}
verticalDirection = this._getDragVerticalDirection();
horizontalDirection = this._getDragHorizontalDirection();
return (horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1;
},
_mouseDrag: function(event) {
var i, item, itemElement, intersection,
o = this.options,
scrolled = false;
//Compute the helpers position
this.position = this._generatePosition( event );
this.positionAbs = this._convertPositionTo( "absolute" );
if ( !this.lastPositionAbs ) {
this.lastPositionAbs = this.positionAbs;
}
//Do scrolling
if ( this.options.scroll ) {
if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ].tagName !== "HTML" ) {
if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
event.pageY < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
}
if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
event.pageX < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
}
} else {
if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
}
if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() - o.scrollSpeed
);
} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() + o.scrollSpeed
);
}
}
if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
}
//Regenerate the absolute position used for position checks
this.positionAbs = this._convertPositionTo( "absolute" );
//Set the helper position
if ( !this.options.axis || this.options.axis !== "y" ) {
this.helper[ 0 ].style.left = this.position.left + "px";
}
if ( !this.options.axis || this.options.axis !== "x" ) {
this.helper[ 0 ].style.top = this.position.top + "px";
}
//Rearrange
for ( i = this.items.length - 1; i >= 0; i-- ) {
//Cache variables and intersection, continue if no intersection
item = this.items[ i ];
itemElement = item.item[ 0 ];
intersection = this._intersectsWithPointer( item );
if ( !intersection ) {
continue;
}
this.direction = this._onRightSide(item, event) === true ? "right" : "left";
this._rearrange( event, item );
if (!this._intersectsWithSides(item)) {
break;
}
this._trigger( "change", event, this._uiHash() );
break;
}
//Post events to containers
this._contactContainers( event );
//Interconnect with droppables
if ( $.ui.ddmanager ) {
$.ui.ddmanager.drag( this, event );
}
//Call callbacks
this._trigger( "sort", event, this._uiHash() );
this.lastPositionAbs = this.positionAbs;
return false;
},
_rearrange: function( event, i, a, hardRefresh ) {
a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
i.item[ 0 ].parentNode.insertBefore(
this.placeholder[ 0 ],
( this.direction === "left" ? i.item[ 0 ] : i.item[ 0 ].nextSibling )
);
//Various things done here to improve the performance:
// 1. we create a setTimeout, that calls refreshPositions
// 2. on the instance, we have a counter variable, that get's higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout,
// if it's still the same
// 4. this lets only the last addition to the timeout stack through
this.counter = this.counter ? ++this.counter : 1;
var counter = this.counter;
this._delay( function() {
if ( counter === this.counter ) {
//Precompute after each DOM insertion, NOT on mousemove
this.refreshPositions( !hardRefresh );
}
} );
}
});