【问题标题】:js/jQuery Drag'n'Drop, recalculate the drop targetsjs/jQuery 拖放,重新计算放置目标
【发布时间】:2009-04-07 14:11:14
【问题描述】:

我有以下问题,我有一棵大树,它有可以按需折叠和展开的子节点(节点内的数据通过 AJAX 获取)。但是,我使用 jquery.event.drop/drag 来创建我的拖放目标。

但是,当我折叠/展开时,放置目标会改变位置,我需要重新计算。这就是我想这样做的方式:

function create_drop_targets() {
  $('li a')
    .bind('dropstart', function(event) {
    })
    .bind('drop', function(event) {
    })
    .bind('dropend', function(event) {
    });
}

create_drop_targets() 在折叠/展开时调用。

但是,这不起作用。我在 jquery.event.drop 中找到了以下内容:

var drop = $.event.special.drop = {
    setup: function(){
        drop.$elements = drop.$elements.add( this );
        drop.data[ drop.data.length ] = drop.locate( this );
        },
    locate: function( elem ){ // return { L:left, R:right, T:top, B:bottom, H:height, W:width }
        var $el = $(elem), pos = $el.offset(), h = $el.outerHeight(), w = $el.outerWidth();
        return { elem: elem, L: pos.left, R: pos.left+w, T: pos.top, B: pos.top+h, W: w, H: h };
        }

现在我需要知道如何再次调用 setup() 方法,以便它使用 droppables 的新位置重新填充 $elements。

【问题讨论】:

    标签: javascript jquery tree


    【解决方案1】:

    刚刚遇到同样的问题。我在 jQuery 的源代码中四处游荡,发现了这个(ui.droppable.js):

    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);
      ...
    

    所以,你只需要使用

    $(".cocktails").draggable({
      refreshPositions: true,
    });
    

    似乎没有太多记录......但它解决了我的问题。当然,这会使一切都变慢一些,我建议进行一些依赖于使用的调整(在更改发生之前启用它,并在用户移动鼠标并发生更改后禁用它)。

    【讨论】:

    • 我明天要试试这个,我会及时通知你的!
    【解决方案2】:

    添加 jQuery 1.3 中引入的实时事件可能会更好?

    $("li a").live("dropstart", function(){...});

    【讨论】:

    • 我已经在 1.3.2 版本的现场活动中尝试过这个,没有解决方案。
    【解决方案3】:

    当我尝试将滚动与 liteGrid 中的可拖动行结合起来时遇到了同样的问题,但我找到了解决方法。您的里程可能会有所不同,但我所做的是向我的拖动事件处理程序添加逻辑,该处理程序将检查网格是否正在滚动(这是我需要强制刷新可放置位置的时候),如果是这样,我设置在可拖动对象上将 refreshPositions 设置为 true。这不会立即刷新位置,但会导致它们在下次拖动手柄移动时刷新。由于 refreshPositions 会减慢速度,因此我会在下次触发拖动事件处理程序时重新禁用它。最终结果是 refreshPositions 仅在网格在 liteGrid 中滚动时启用,其余时间禁用。这里有一些代码来说明:

    //This will be called every time the user moves the draggable helper.
    function onDrag(event, ui) {
        //We need to re-aquire the drag handle; we don't
        //hardcode it to a selector, so this event can be
        //used by multiple draggables.
        var dragHandle = $(event.target);
    
        //If refreshOptions *was* true, jQueryUI has already refreshed the droppables,
        //so we can now switch this option back off.
        if (dragHandle.draggable('option', 'refreshPositions')) {
            dragHandle.draggable('option', 'refreshPositions', false)
        }
    
        //Your other drag handling code
    
        if (/* logic to determine if your droppables need to be refreshed */) {
                    dragHandle.draggable('option', 'refreshPositions', true);
        }
    }
    
    
    $("#mydraggable").draggable({
        //Your options here, note that refreshPositions is off.
        drag: onDrag
    });
    

    我希望这样可以避免您像我一样多次将头撞到键盘上...

    【讨论】:

    • 我应该注意到我尝试只启用 refreshPositions,但性能无法接受。使用这个解决方案,当拖动行导致网格滚动时,我的性能仍然很慢,但在其余时间它表现很好(因为 refreshPositions 被禁用)。
    【解决方案4】:

    我意识到最初的问题现在已经很老了,但是我想出的一个小技巧可以在没有太多开销的情况下刷新可拖动元素的位置 (AFAICT) 是在适当的地方禁用并立即重新启用它们。

    例如,我注意到调整浏览器窗口的大小不会刷新可拖动表格行的位置,所以我这样做了:

    $(window).resize(function () {                
        $(".draggable").draggable("option", "disabled", true);
        $(".draggable").draggable("option", "disabled", false);
    });
    

    我希望这对那里的人有所帮助!

    【讨论】:

    • 我会尽快在某个地方尝试一下 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    相关资源
    最近更新 更多