【问题标题】:Creating multiple droppable siblings that at positioned on top of eachother创建多个放置在彼此之上的可放置同级
【发布时间】:2012-09-25 07:39:47
【问题描述】:

我正在尝试创建多个彼此相邻的 jquery 可放置对象,其中某些部分可能会重叠,在这些情况下,我希望顶部(z-index 明智)的那个是贪婪的。

我已经尝试在 droppable 中设置 greedy: true 选项,但这似乎没有帮助。我还尝试在 drop 事件中使用return false 并使用event.stopPropagation();

这是一个基于 jquery 的demo pagejsfiddle

如果有另一个 droppable 触发它,是否有任何方法阻止 drop 事件传播,最好是具有最高 z-index 的那个?

【问题讨论】:

    标签: javascript jquery jquery-ui jquery-droppable


    【解决方案1】:

    使用document.elementFromPoint 来检查光标正下方的元素。如果它不是你的 droppable,请不要做任何事情。 将以下内容添加到 drop: 处理程序的顶部:

    var droppable = $(this);
    ui.helper.css({pointerEvents: 'none'});
    var onto = document.elementFromPoint(event.clientX, event.clientY);
    ui.helper.css({pointerEvents: ''});
    if(!droppable.is(onto) && droppable.has(onto).length === 0) {
        return;
    }
    

    在帮助器上禁用指针事件对于document.elementFromPoint 忽略您拖动的内容并仅在下方检查是必要的。我已经 updated 你的 jsFiddle 进行快速演示。请注意,突出显示仍然会影响这两个元素。您应该能够通过不让 jQuery UI 进行突出显示来改变这一点,而是自己在可拖动的 drag: 事件上编写它。然而,我发现这在实践中是不可用的,因为这个检查(和禁用指针事件)非常慢并且还可能导致闪烁。

    【讨论】:

    • 不错的解决方案!用 z-indexes 等寻找了大约 3 个小时的不同方法,但这只是简单而有效!
    【解决方案2】:

    你需要一个函数来检查元素是否是最高可见元素。当

    1. 该项目位于 dom 列表的后面
    2. 它具有更高的 z-index 集

    下面的函数可以用来查看当前元素(无论是在over方法中还是在droppable设置中的drop方法中)是否实际上是最高可见元素。

    function isHighestVisible(cEl) {
        cEl = $(this); //use this if you want to use it in the over method for draggable, else just pass it to the method
    
        //get all active droppable elements, based on the classes you provided
        var $list = $('.ui-widget-header.ui-state-active');
        var listCount = $list.length;
        var HighestEl = null;
        var HighestZI = -1;
    
    
        //one element is always highest.
        if (listCount<=1) {
            console.log(cEl.attr('id'));
            return true;
        }
    
        //check each element
        $list.each(function(i) {
            var $el = $(this);
    
            var id = $el.attr('id');
    
            //try to parse the z-index. If its 'auto', return 0.
    
            var zi = isNaN(parseInt($el.css('z-index'))) ? 0 : parseInt($el.css('z-index'));
    
            if (zi>0) {
                //z-index is set, use it.
                //I add the listCount to prevent errors when a low z-index is used (eg z-index=1) and there are multiple elements.
                //Adding the listCount assures that elements with a z-index are always later in the list then elements without it.
                zi = zi + listCount;
            } else {
                //z-index is not set, check for z-index on parents
                $el.parents().each(function() {
                    $par = $(this);
                    var ziParent = isNaN(parseInt($par.css('z-index'))) ? 0 : parseInt($par.css('z-index'));
                    if (ziParent>0) {
                        zi = ziParent;
                        return false;
                    }
                });
            }
    
            //add the current index of the element to the zi
            zi += i;
    
            //if the calculated z-index is highest, change the highest element.
            if (HighestEl==null || HighestZI<zi) {
                HighestEl=$el;
                HighestZI = zi;
            }
        });
    
        //if the highest found active element, return true;
        if (HighestEl.attr('id')==cEl.attr('id')) {
            console.log(cEl.attr('id'));
            return true;
        }
    
        //if all else fails, return false
        return false;
    }
    

    【讨论】:

    • 这看起来很有希望。我还没有机会尝试它,但原理是合理的。但是,请注意,有效的 z 索引也可以是负数,并且每个定位元素(static 以外的任何值)都会打开自己的堆叠上下文,这意味着即使有效的 z 索引也必须遍历父元素找到了。
    • 感谢您的支持和评论。我确实忘记了负 z-index 选项。我什至不知道你提到的第二部分。我很少在一个页面上多次使用 z-index,我猜我从来没有遇到过。
    【解决方案3】:

    如果我有这个问题,我会使用 jQuery 的 .addclass

    .droppablewidgetforce {
    z-index: 1000 !important; 
    }
    

    这样创建一个类,这样层无论如何都保持在顶部。这应该可以解决问题。

    【讨论】:

    • 也许我误解了你的答案,但问题不在于 z-index。问题是该事件在#droppable3 元素和droppable3-inner 元素上都被触发,而它只能在droppable3-inner 上触发,同时在两个元素上拖动它。我不确定将 droppables z-index 设置为 1000 对我有什么帮助。
    • 从选择器列表中取出 droppable3 并使用该参数和所需参数创建新函数
    • 这只将droppable放在draggable之上,这根本不是我想做的,也许你可以在jsfiddle中告诉我你的意思?
    【解决方案4】:

    贪婪选项仅适用于具有可放置父级的嵌套元素。

    在您的代码中,2 个可放置元素是同级元素,因此贪婪选项将不起作用:

    <div id="droppable3" class="ui-widget-header">
        <p>Outer droppable</p>
    </div>
    <div id="droppable3-inner" class="ui-widget-header">
        <p>Inner droppable (greedy)</p>
    </div>
    

    如果您仍想使用兄弟姐妹而不是父母和孩子,这是一个混乱的解决方法。

    直播代码example.

    function normalDraggedOver() {
        $( this ).addClass( "ui-state-highlight" )
                 .find( "> p" )
                 .html( "Droppeeeed!" );
    }
    
    var options = {
        activeClass: "ui-state-hover",
        hoverClass: "ui-state-active",
        greedy: true,
        drop: normalDraggedOver
    };
    
    var options2 = {
        activeClass: "ui-state-hover",
        hoverClass: "ui-state-active",
        disabledClass: "ui-state-disabled",
        hoverStateClass: "ui-state-hover",
        greedy: true,
        greedyWithSibligs: true,
        drop: normalDraggedOver,
        over: function () {
        /* if we have previous siblings of the inner element we handle them as parents */
            if(options2.greedyWithSibligs && $(this).prev().length > 0) {       
                $(this).siblings().slice(0, $(this).index())
                .removeClass(options2.hoverClass)
                .droppable('disable')
                .removeClass(options2.disabledClass)
                .removeClass(options2.hoverStateClass);
            }
        },
        out: function () {
        /* all the siblings of the inner element that were handled as parents act as one*/
            if(options2.greedyWithSibligs && $(this).prev().length > 0) {
                $(this).siblings().slice(0, $(this).index())
                .droppable('enable')
                .addClass(options2.hoverClass);
                console.log($(this).attr('id'));
            }
        }
    };
    

    【讨论】:

    • 好吧,我仍在寻找更通用的解决方案:droppables 不应该是兄弟姐妹。我只希望绝对定位的 droppables 尊重z-index,因此当拖放到视觉上位于另一个元素前面的元素上时(这也是可拖放的),drop 应该只注册在前面的元素上。
    • z-index 的问题在于,如果你自己没有设置它,它的值总是'auto'。
    【解决方案5】:

    如果只是想让它看起来一样,您可以将 #droppable3 设置为 position: relative 并将子 #droppable3-inner 设置为 position: absolute。

    HTML:

    <div id="droppable3" class="ui-widget-header">
        <p>Outer droppable</p>
    </div>
    <div id="droppable3-inner" class="ui-widget-header">
        <p>Inner droppable (greedy)</p>
    </div>
    

    这里是直播example

    【讨论】:

    • 这个例子需要我将 droppable3-inner 元素实际移动到 droppable3 元素中,我想避免这种情况。
    猜你喜欢
    • 2022-10-12
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多