jQuery Droppables - 隐藏“非活动”时出现问题降落区

发布于 2024-11-11 18:33:29 字数 2906 浏览 4 评论 0原文

我有一个相当长的 div 列表,我试图将其用作 droppable,但我想隐藏所有不接受当前可拖动元素的 droppable。

我在 http://jsfiddle.net/N3uh3/ 上举了一个例子

基本上,如果我拖动 '拖动 A' 元素,它将隐藏所有“可放置 B”元素,并允许我放置到正确的元素上,这效果很好。

但是,如果我拖动“拖动 B”元素,它将隐藏所有“可放置 A”元素,但其余放置区域不接受我的可拖动项目。如果我将该项目放置在“可放置 B”元素的原始位置,那么它会正确放置(即使该元素的位置已移动)。如果我使用“可见性:隐藏;”而不是“display:none”,这也可以工作,因为元素不移动。

我希望这是有道理的 - 似乎可放置区域设置为元素的原始位置......有什么办法解决这个问题吗?

.lhs { width: 40%; float:left; }
.rhs { width: 40%; float:right; }
.lhs div { margin: 4px; }
.a { background-color: green; }
.b { background-color: red; }
.ui-state-highlight { background-color: yellow; }
.dropZones .ui-droppable { display: none; }
.dropZones .ui-state-highlight { display: block; }
.currentDropZone { display: block; }

<div class="wrapper">
    <div class="lhs">
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
    </div>
    <div class="rhs">
        <div class="a">Drag A</div>
        <br />
        <div class="b">Drag B</div>
    </div>
</div>


$(document).ready(function(){
    $('.rhs div').draggable({
        helper: function (e,ui) {
            // this sets the clone to be a child of the body - fixing overflow:auto problems on divs!
            return $(this).clone().appendTo('body').css('zIndex',5).show();
        }, 
        revert: 'invalid',
        cursor: 'move',
        start: function(){
            //$('.lhs').addClass('dropZones');    // immediately hides so doesn't get the ui-state-highlight class'

            // give a quick period of time then add the class
            setTimeout(function() { $('.lhs').addClass('dropZones'); }, 250);
        },
        stop: function(){
            $('.lhs').removeClass('dropZones');
        },
    });

    $('.lhs div').each(function(){
        $(this).droppable({
            greedy: true,
            activeClass: 'ui-state-highlight',
            accept: '.' + $(this).attr('class'),
            drop: function(event, ui) {
                $(this).append($(ui.draggable).clone());
            },
            activate: function(){
                $(this).addClass('currentDropZone');
            },
            deactivate: function(){
                $(this).removeClass('currentDropZone');
            }

        });
    });
});

提前致谢!

I've got a fairly long list of divs which I'm trying to use as droppable's - but I want to hide all of the droppables that won't accept the current draggable element.

I've put an example up at http://jsfiddle.net/N3uh3/

Basically if I drag the 'Drag A' element it will hide all 'Droppable B' elements and allow me to drop onto the correct elements and this works well.

However if I drag the 'Drag B' element it will hide all 'Droppable A' elements but the remaining drop areas do not accept my draggable item. If I drop the item at the original location of the 'Droppable B' elements then it drops correctly (even though the position of the element has moved). If I use "visibility: hidden;" instead of "display:none" this also works as the element does not move.

I hope this makes sense - seems like the droppable area is set to the original position of the element....is there any way around this?

.lhs { width: 40%; float:left; }
.rhs { width: 40%; float:right; }
.lhs div { margin: 4px; }
.a { background-color: green; }
.b { background-color: red; }
.ui-state-highlight { background-color: yellow; }
.dropZones .ui-droppable { display: none; }
.dropZones .ui-state-highlight { display: block; }
.currentDropZone { display: block; }

<div class="wrapper">
    <div class="lhs">
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="a">DROP A</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
        <div class="b">DROP B</div>
    </div>
    <div class="rhs">
        <div class="a">Drag A</div>
        <br />
        <div class="b">Drag B</div>
    </div>
</div>


$(document).ready(function(){
    $('.rhs div').draggable({
        helper: function (e,ui) {
            // this sets the clone to be a child of the body - fixing overflow:auto problems on divs!
            return $(this).clone().appendTo('body').css('zIndex',5).show();
        }, 
        revert: 'invalid',
        cursor: 'move',
        start: function(){
            //$('.lhs').addClass('dropZones');    // immediately hides so doesn't get the ui-state-highlight class'

            // give a quick period of time then add the class
            setTimeout(function() { $('.lhs').addClass('dropZones'); }, 250);
        },
        stop: function(){
            $('.lhs').removeClass('dropZones');
        },
    });

    $('.lhs div').each(function(){
        $(this).droppable({
            greedy: true,
            activeClass: 'ui-state-highlight',
            accept: '.' + $(this).attr('class'),
            drop: function(event, ui) {
                $(this).append($(ui.draggable).clone());
            },
            activate: function(){
                $(this).addClass('currentDropZone');
            },
            deactivate: function(){
                $(this).removeClass('currentDropZone');
            }

        });
    });
});

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一杯敬自由 2024-11-18 18:33:30

问题在于,隐藏不活动的 droppable 会改变元素流和活动 droppable 的位置。当您的延迟事件触发时,绝对可放置位置已被 jQuery UI 缓存,这就是您松开鼠标按钮时所检查的内容。在原始示例中,如果将 B 拖动到 B 放置区的旧位置(位于可见列表下方),您仍然可以放置 B

一个快速简单的解决方案是告诉 jQuery UI 通过在可拖动对象上使用 refreshPositions: true 选项来重新计算每次鼠标移动时的可放置​​位置。来自文档

刷新位置:布尔值

如果设置为 true,则所有内容均可删除
位置是在每个
鼠标移动。注意:这可以解决问题
在高度动态的页面上,但是
显着降低性能。

您更新了演示: http://jsfiddle.net/N3uh3/1/

这是一个快速修复,但我的建议是在隐藏项目时编写自己的逻辑,而不是依赖 setTimeout(),这会在隐藏您的 droppables 之前增加明显烦人的延迟。

由于只有显示的 droppables 被激活,我会在 jQuery UI 之前添加隐藏逻辑,甚至有机会构建接受 droppables 的列表,例如项目上的 mousedown 事件。然后,您可以编写自己的自定义代码来隐藏不需要的可放置项,因此当涉及到缓存位置时,它们将是正确的,并且无需在每次鼠标移动时刷新缓存,这可能是一项昂贵的操作,具体取决于可放置对象的数量你拥有的可掉落物品。

The problem is that hiding your inactive droppables changes the element flow and positions of the active ones. By the time your delayed event fires, absolute droppable positions are already cached by jQuery UI, and that is what's checked when you let the mouse button go. In your original example you can still drop B if you drag it to the old position of the B dropzones, which is just under the visible list.

A quick and easy solution would be to tell jQuery UI to recalculate droppable positions on every mousemove by using the refreshPositions: true option on the draggable. From the documentation:

refreshPositions: Boolean

If set to true, all droppable
positions are calculated on every
mousemove. Caution: This solves issues
on highly dynamic pages, but
dramatically decreases performance.

You updated demo: http://jsfiddle.net/N3uh3/1/

This is a quick fix, but my suggestion would be to make up your own logic when hiding your items rather than relying on setTimeout(), which adds a noticeable annoying lag before hiding your droppables.

As only shown droppables are activated, I would add my hiding logic before jQuery UI even has a chance of building up a list of accepting droppables, like the mousedown event on the items. Then you can do your own custom code to hide unwanted droppables, so when it comes to caching positions, they would be correct and there would be no need to refresh the cache on every mousemove, which might be an expensive operation depending on the number of droppables you have.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文