当容器具有隐藏项时,jQuery UI可排序拖动启动很慢

时间:2012-02-25 02:31:38

标签: jquery-ui

我有一个无序的“来源”列表,最多可包含1,000个列表项。我希望能够将源列表中的项目拖动到连接的“目标”列表中。我的一切工作都很顺利,直到我的源列表被过滤。我正在使用jquery quicksearch插件来过滤(搜索)我的源列表。过滤器通过设置'display:none;'来完成。对于与搜索不匹配的项目。

当隐藏源列表中的1..n项时,启动时拖动操作不流畅。意思是,我点击我要拖动的项目,在屏幕上移动我的鼠标,但是我拖动的项目在我开始拖动后大约一整秒才出现在我的光标下。

对于诊断,我已经将我的用例缩减到了一个我要排序的列表。我已经完全取消了对quicksearch的使用,只需将我的一半列表项硬编码为隐藏。我仍然能够重现'非流动'的行为。我的例子在这里:

http://pastebin.com/g0mVE6sc

如果我从我的示例中的列表中删除溢出样式,性能会好一点,但仍然比我希望看到的要慢。

在开始考虑其他选择之前,有没有人对我有任何建议?

提前致谢。

6 个答案:

答案 0 :(得分:12)

正如您在 jsferf 示例中所看到的,计算outerWidth()/ outerHeight()(这是插件的作用 - 见下文)隐藏元素(显示无) 比可见元素慢得多,它是由样式属性或类实现的。

我发现绕过这个并且仍能达到相同结果的唯一方法是将高度设置为隐藏为零,而不是使用display属性,无论是否使用样式atttibute或班级:

<li style="height: 0;">b</li>
<li class="hidden">b</li>

.hidden { height: 0 }

DEMO (with class) - DEMO (with style attr)


拖动元素时,sortable会发生什么?

开始拖动时,插件会刷新所有项目的列表并重新计算所有元素的位置。插件实际上得到outerWidth和outerHeight:

_mouseStart: function(event, overrideHandle, noActivation) {
    ...
    //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
    this.refreshPositions();
    ...
}

refreshPositions: function(fast) {
    ...
    for (var i = this.items.length - 1; i >= 0; i--) {
        var item = this.items[i];
        ...
        if (!fast) {
            item.width = t.outerWidth();
            item.height = t.outerHeight();
        }
        var p = t.offset();
        item.left = p.left;
        item.top = p.top;
    };
    ...
    return this;
},​

答案 1 :(得分:6)

如果您仍想使用display:none,这是对Didier答案中指定的jQuery UI源的简单修复:

if (!fast) {
    if(item.item.css('display') === 'none') {
        item.width = 0;
        item.height = 0;
    }
    else {
        item.width = t.outerWidth();
        item.height = t.outerHeight();
    }
}

这是我关于stackoverflow的第一篇文章,所以如果我搞砸了,请告诉我。

答案 2 :(得分:5)

我也有类似的问题,但使用隐藏的drop容器而不是可排序的项目。这是我的解决方案,将Jordan的答案应用于可排序项目及其容器,并简单地替换relvent方法。

$.ui.sortable.prototype.refreshPositions = function(fast) {  
    //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
    if(this.offsetParent && this.helper) {
        this.offset.parent = this._getParentOffset();
    }

    for (var i = this.items.length - 1; i >= 0; i--){
        var item = this.items[i];

        //We ignore calculating positions of all connected containers when we're not over them
        if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
            continue;

        var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;

        if (!fast) {
            /********** MODIFICATION ***********/

            if(item.item.css('display') === 'none') {
                item.width = 0;
                item.height = 0;                    
            } else {
                item.width = t.outerWidth();
                item.height = t.outerHeight();
            }

            /********** END MODIFICATION ***********/
        }

        var p = t.offset();
        item.left = p.left;
        item.top = p.top;
    };

    if(this.options.custom && this.options.custom.refreshContainers) {
        this.options.custom.refreshContainers.call(this);
    } else {
        for (var i = this.containers.length - 1; i >= 0; i--){

            /********** MODIFICATION ***********/

            if (this.containers[i].element.css('display') == 'none') {
                this.containers[i].containerCache.left = 0;
                this.containers[i].containerCache.top = 0;
                this.containers[i].containerCache.width = 0;
                this.containers[i].containerCache.height = 0;
            } else {
                var p = this.containers[i].element.offset();
                this.containers[i].containerCache.left = p.left;
                this.containers[i].containerCache.top = p.top;
                this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
                this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
            }

            /********** END MODIFICATION ***********/
        };
    }

    return this;
};

答案 3 :(得分:1)

我遇到了同样的问题...... 我已经搜索了一个解决方案,但似乎没有jquery问题的解决方案,只有一些解决方法...... 我没有找到解决方案,只是另一种解决方法。

在我的情况下,我刚刚创建了一个通用的方法来进行可排序列表中的搜索,其中在keyup上,代码进行并对列表中的每个元素进行查找,如果不匹配则通过fadeout隐藏它值。 这工作得非常好,但是当你在列表中有数百个项目时,隐藏的内容会大到足以触发对拖放的缓慢影响。 我的解决方案是重新排序列表,将匹配的项目置于顶部.. 只需删除并再次附加...

这样我对隐藏元素没有问题:)

对不起,这不是解决方案,只是另一种解决方法..

此致

答案 4 :(得分:1)

最近我再次遇到这个问题......发现我的解决方法不再是最好的解决方案了。由于问题是高度......我只是用

创建一个CSS类

.hidden {display: block; line-height:0; height: 0; overflow: hidden; padding: 0; margin: 0; }

而不是设置隐藏的元素,只需添加此类并将其删除以显示/隐藏元素..

此致 AP

答案 5 :(得分:0)

今天我遇到了与可排序 + 可拖动表格行相同的问题。 解决方案很简单:使用 visibility:collapse 而不是 display:none 并删除隐藏线的 jQuery 隐藏/显示功能。现在快了很多。 希望能帮到你。