Jquery占位符不准确

时间:2017-02-13 02:16:23

标签: jquery jquery-ui flexbox jquery-ui-sortable

所以我在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;
&#13;
&#13;

1 个答案:

答案 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 );
                }
            } );

        }
    });