在滚动上删除/插入DOM元素的jQuery很挑剔

时间:2011-11-21 00:00:58

标签: jquery webview appcelerator

我正在为Appcelerator Titanium中的Web视图构建代码。由于网页上文本的大小(书本长度),我构建了一些jQuery,以便在用户滚动时自动删除/插入页面内容。这意味着在任何给定时间只加载了一小部分页面,因此操作内存的压力更小,渲染更平滑。这是代码:

$(document).ready(function() {

// assign content index and parent, add to array

    var content = new Array();
    var index = 0;
    $('section > *').each(function() {
        // set variables
        var tag = $(this).get(0).tagName;
        var id = $(this).get(0).id;
        var style = $(this).get(0).className;
        var parent = $(this).parent('section').attr('index');
        var html = $(this).html();
        // add to html
        $(this).attr('parent', parent).attr('index', index);
        // add to array
        content[index] = new Array(tag, id, style, index, parent, html);
        // next index
        index++;
    });

// find center element, remove elements

    var midW = parseInt($(window).width() / 2);
    var midH = parseInt($(window).height() / 2);
    var centerEl = document.elementFromPoint(midW, midH);
    if (!$(centerEl).attr('parent')) {
        centerEl = $(centerEl).parent();
    }
    centerEl = parseInt($(centerEl).attr('index'));
    $('section > *').remove();

// insert content

    var firstEl = centerEl - 30;
    if (firstEl < 0) {
        firstEl = 0;
    }
    var lastEl = centerEl + 30;
    if (lastEl > content.length) {
        lastEl = content.length;
    }
    for (var i = firstEl; i < lastEl; i++) {
        var tag = content[i][0];
        var id = content[i][1];
        var style = content[i][2];
        var index = content[i][3];
        var parent = content[i][4];
        var html = content[i][5];
        var el = '<' + tag + ' id="' + id + '" class="' + style + '" index="' + index + '" parent="' + parent + '">' + html + '</' + tag + '>';
        $('section[index=' + parent + ']').append(el);
    }

// on scroll

var change;
var loadContent = function() {
    // find new center element
    midW = parseInt($(window).width() / 2);
    midH = parseInt($(window).height() / 2);
    newCenterEl = document.elementFromPoint(midW, midH);
    if (!$(newCenterEl).attr('parent')) {
        newCenterEl = $(newCenterEl).parent();
    }
    newCenterEl = parseInt($(newCenterEl).attr('index'));
    // if the center element has changed
    if (newCenterEl != centerEl) {
        // set center
        if (!isNaN(newCenterEl)) {
            change = newCenterEl - centerEl;
            centerEl = newCenterEl;
        }
        $('section > *').css('background-color', 'white'); // delete
        $('section > *[index=' + centerEl + ']').css('background-color', 'aqua'); // delete
        // calculate what to display
        var firstEl = centerEl - 30;
        if (firstEl < 0) {
            firstEl = 0;
        }
        var lastEl = centerEl + 30;
        if (lastEl > content.length) {
            lastEl = content.length;
        }
        // remove elements
        $('section > *').each(function() {
            var index = $(this).attr('index');
            if (index < firstEl || index > lastEl) {
                $(this).remove();
            }
        });
        // add elements
        if (change > 0) {
            for (var i = firstEl; i <= lastEl; i++) {
                if ($('section > *[index=' + i + ']').length == 0) {
                    var tag = content[i][0];
                    var id = content[i][1];
                    var style = content[i][2];
                    var index = content[i][3];
                    var parent = content[i][4];
                    var html = content[i][5];
                    var el = '<' + tag + ' id="' + id + '" class="' + style + '" index="' + index + '" parent="' + parent + '">' + html + '</' + tag + '>';
                    $('section[index=' + parent + ']').append(el);
                }
            }
        }
        if (change < 0) {
            for (var i = lastEl; i >= firstEl; i--) {
                if ($('section > *[index=' + i + ']').length == 0) {
                    var tag = content[i][0];
                    var id = content[i][1];
                    var style = content[i][2];
                    var index = content[i][3];
                    var parent = content[i][4];
                    var html = content[i][5];
                    var el = '<' + tag + ' id="' + id + '" class="' + style + '" index="' + index + '" parent="' + parent + '">' + html + '</' + tag + '>';
                    $('section[index=' + parent + ']').prepend(el);
                }
            }
        }
    }
}
$(window).scroll(function() {
    loadContent();
});

});

总体而言,它运行良好,尤其是当用户向下滚动时。向上滚动也有效,但由于某种原因,它更加挑剔,有时会卡住。向上滚动和向下滚动之间唯一的主要区别是我在预先添加内容而不是附加内容。

那么,我的问题是,为什么向上滚动可能不如向下滚动?有什么想法/猜测/建议吗?

2 个答案:

答案 0 :(得分:1)

这是我最终得到的代码。它工作得很好,大约是原始代码的四分之一。

$(document).ready(function() {

// assign section IDs
    var sectionID = 0;
    $('section').each(function() {
        $(this).attr('id', 's' + sectionID);
        sectionID++;
    });

// assign element IDs, add to array
    var content = new Array();
    var contentID = 0;
    $('section > *').each(function() {
        $(this).attr('id', contentID);
        content[contentID] = new Array($(this).parent('section').attr('id'), $(this));
        contentID++;
    });

// display elements
    var display = function() {
        // determine center
        var center = parseInt($(document.elementFromPoint(parseInt($(window).width() / 2), parseInt($(window).height() / 2))).closest('section > *').attr('id'));
        // determine first/last
        var first, last;
        if (!isNaN(center)) {
            first = ((center - 20) < 0) ? 0 : (center - 20);
            last = ((center + 20) > content.length) ? content.length : (center + 20);
        }
        // hide
        $('section > *').each(function() {
            var id = $(this).attr('id');
            if (id < first || id > last) {
                $(this).remove();
            }
        });
        // show
        var start = $('section > *').first().attr('id') - 1;
        for (var i = start; i >= first; i--) {
            $('section#' + content[i][0]).prepend(content[i][1]);
        }
        var end = parseInt($('section > *').last().attr('id')) + 1;
        for (var i = end; i <= last; i++) {
            $('section#' + content[i][0]).append(content[i][1]);
        }
    }

// listeners
    $(window).load(function() {
        display();
    });
    $(window).scroll(function() {
        display();
    });

});

答案 1 :(得分:0)

我的猜测如下:

prepend需要更多的渲染工作然后追加,因为插入元素之后的所有dom都应该被重建。在追加时,插入一个

后没有元素

无论如何,如果你只添加/追加一次而不是50次,那么jquery可以更快地工作

for (var i = lastEl; i >= firstEl; i--) {
            if ($('section > *[index=' + i + ']').length == 0) {
                var tag = content[i][0];
                var id = content[i][1];
                var style = content[i][2];
                var index = content[i][3];
                var parent = content[i][4];
                var html = content[i][5];
                var el = '<' + tag + ' id="' + id + '" class="' + style + '" index="' + index + '" parent="' + parent + '">' + html + '</' + tag + '>';
                $('section[index=' + parent + ']').prepend(el);
            }
        }

你应该重写这个块,以便最小化前缀的数量

我想你没有很多部分,所以你可以做这样的事情

var sections={};
{ //your loop starts here

    if (typeof sections[parent]=='undefined'){
        sections[parent]=[];
    }
    var el=all+your+stuff;
    sections[parent].push(el);

}//ends here
$(sections).each(function(parent,section){
    $('section[index=' + parent + ']').prepend(section);    
});

我想你会改变一些东西,以适应你的代码,但这是个主意 - &gt;最小化dom更改操作的数量,准备一堆元素并将它们全部插入