编程语言
首页 > 编程语言> > javascript – 为jQuery UI Droppable的Intersect容差构建匹配选项

javascript – 为jQuery UI Droppable的Intersect容差构建匹配选项

作者:互联网

我想将一个元素拖动到两个或更多可放置区域,但那些可放置区域需要完全包含在我的可拖动对象中.

问题是,jQuery UI’s existing functionality for droppable tolerances都没有满足这个需求.

理想情况下,我会使用“intersect”,但是代码中的可拖动和可放置对象测量结果是相反的. (通过搜索$.ui.intersect可以在jquery-ui.js中找到此逻辑.)

我已尝试在duck punching with jQuery之前覆盖该功能,并尝试将容差设置为这样的自定义函数:

tolerance: function(draggable, droppable) {
            if(!droppable.offset) return false;

            return ...logic check here...
        },
        drop: ...continues...

都没有奏效.

这是一个JSFiddle来说明我的意思:https://jsfiddle.net/myingling/kgaqb0ay/5/

同样,应该分配//由一个人//覆盖的所有项目.

解决方法:

修改$.ui.intersect似乎是最好的方法.你有不同的选择.如果您不需要那么大的灵活性,您可以简单地添加一个公差类型,例如’cover’.然后你只需要在开关中添加一个用于检查相交中的公差类型的情况,这可以恰好与“适合”相反.像这样:

  case 'fit':
    return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
    break;
  case 'cover':
    return (l >= x1 && x2 >= r && t >= y1 && y2 >= b);
    break;

见:https://jsfiddle.net/6nyqja4a/4/

或者,如果您想要更多灵活性,可以添加容差是函数的情况.然后,您可以在选项中传递一个函数,这样您就可以对不同的可放置对象进行精确容差.像这样的东西例如:
在intererct功能:

 if (toleranceMode instanceof Function) {

    return toleranceMode(draggable, droppable, x1, x2, y1, y2, l, r, t, b);

  } else {
    switch (toleranceMode) {
      case 'fit':
        return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
        break;
...

你这样称呼它:

$('.droppable').droppable({
  hoverClass: "yellow",
  tolerance: function(drag, drop, x1, x2, y1, y2, l, r, t, b) {
    return (l >= x1 && x2 >= r && t >= y1 && y2 >= b);
  },
  drop: function(event, ui) {
    $("#value_" + $(this).data("id")).val(ui.draggable.data("id"));
    console.log("Item " + $(this).data("id") + " taken by " + ui.draggable.data("id"));
  }
});

见:https://jsfiddle.net/h4wm3r09/3/

从jquery 1.12 $.ui.intersect函数作用域,以便之后不能直接修改.它在$.ui.ddmanager中作为局部变量调用,因此即使修改$.ui.intersect,也不会使用它.定制它有点复杂.你可以这样做,基本上你重新扫描相交,然后重新定义$.ui.ddmanager上的拖放方法,以便它调用修改后的交叉:

var intersect = $.ui.intersect = ( function() {
    function isOverAxis( x, reference, size ) {
        return ( x >= reference ) && ( x < ( reference + size ) );
    }

    return function( draggable, droppable, toleranceMode, event ) {

        if ( !droppable.offset ) {
            return false;
        }

        var x1 = ( draggable.positionAbs ||
                draggable.position.absolute ).left + draggable.margins.left,
            y1 = ( draggable.positionAbs ||
                draggable.position.absolute ).top + draggable.margins.top,
            x2 = x1 + draggable.helperProportions.width,
            y2 = y1 + draggable.helperProportions.height,
            l = droppable.offset.left,
            t = droppable.offset.top,
            r = l + droppable.proportions().width,
            b = t + droppable.proportions().height;
        if (toleranceMode instanceof Function) {

            return toleranceMode(draggable, droppable, x1, x2, y1, y2, l, r, t, b);

        } else {
            switch ( toleranceMode ) {
                case "fit":
                    return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
                case "intersect":
                    return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
                x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
                t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
                y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
                case "pointer":
                    return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
                isOverAxis( event.pageX, l, droppable.proportions().width );
                case "touch":
                    return (
                ( y1 >= t && y1 <= b ) || // Top edge touching
                ( y2 >= t && y2 <= b ) || // Bottom edge touching
                ( y1 < t && y2 > b ) // Surrounded vertically
            ) && (
                ( x1 >= l && x1 <= r ) || // Left edge touching
                ( x2 >= l && x2 <= r ) || // Right edge touching
                ( x1 < l && x2 > r ) // Surrounded horizontally
            );
                default:
                    return false;
            }
        }
    };
} )();

那么,在你不改变任何东西的地方,你只需要完全相同的方式重新定义它们.

$.ui.ddmanager.drag = function( draggable, event ) {

    // If you have a highly dynamic page, you might try this option. It renders positions
    // every time you move the mouse.
    if ( draggable.options.refreshPositions ) {
        $.ui.ddmanager.prepareOffsets( draggable, event );
    }

    // Run through all droppables and check their positions based on specific tolerance options
    $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {

        if ( this.options.disabled || this.greedyChild || !this.visible ) {
            return;
        }

        var parentInstance, scope, parent,
            intersects = intersect( draggable, this, this.options.tolerance, event ),
            c = !intersects && this.isover ?
                "isout" :
                ( intersects && !this.isover ? "isover" : null );
        if ( !c ) {
            return;
        }

        if ( this.options.greedy ) {

            // find droppable parents with same scope
            scope = this.options.scope;
            parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
                return $( this ).droppable( "instance" ).options.scope === scope;
            } );

            if ( parent.length ) {
                parentInstance = $( parent[ 0 ] ).droppable( "instance" );
                parentInstance.greedyChild = ( c === "isover" );
            }
        }

        // We just moved into a greedy child
        if ( parentInstance && c === "isover" ) {
            parentInstance.isover = false;
            parentInstance.isout = true;
            parentInstance._out.call( parentInstance, event );
        }

        this[ c ] = true;
        this[ c === "isout" ? "isover" : "isout" ] = false;
        this[ c === "isover" ? "_over" : "_out" ].call( this, event );

        // We just moved out of a greedy child
        if ( parentInstance && c === "isout" ) {
            parentInstance.isout = false;
            parentInstance.isover = true;
            parentInstance._over.call( parentInstance, event );
        }
    } );

}

$.ui.ddmanager.drop = function( draggable, event ) {

    var dropped = false;

    // Create a copy of the droppables in case the list changes during the drop (#9116)
    $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {

        if ( !this.options ) {
            return;
        }
        if ( !this.options.disabled && this.visible &&
                intersect( draggable, this, this.options.tolerance, event ) ) {
            dropped = this._drop.call( this, event ) || dropped;
        }

        if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
                ( draggable.currentItem || draggable.element ) ) ) {
            this.isout = true;
            this.isover = false;
            this._deactivate.call( this, event );
        }

    } );
    return dropped;

}

https://jsfiddle.net/u6wfj8mj/1/

显然,这个更容易出错,可能有更好的方法来实现这一点.通常你可以扩展小部件,例如,它会更干净.但是intersect和ddmanager在draggable和droppable中都使用,而不是直接在这些小部件中.因此,以一种干净的方式扩展起来更加困难.
您也可以直接将逻辑放在拖动事件中并删除可拖动和可放置的事件,但由于存在默认容差,因此不确定它是否更好.

标签:jquery-ui-draggable,javascript,jquery,jquery-ui,jquery-ui-droppable
来源: https://codeday.me/bug/20191008/1874792.html