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

发布于 2024-12-17 04:22:52 字数 4817 浏览 2 评论 0原文

我正在 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();
});

});

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

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

I'm building code for a web view in Appcelerator Titanium. Because of the massive (book length) size of the text on the webpage, I've built some jQuery to automatically remove/insert the page's content as the user scrolls. This means that only a small portion of the page is loaded at any given time, so there is a lot less stress on operating memory and much smoother rendering. Here's the code:

$(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();
});

});

Overall, it's working well, especially when the user scrolls down. Scrolling up also works, but for some reason it's much more finicky, and sometimes it gets stuck. The only major difference between scrolling up and scrolling down is that I'm prepending the content instead of appending it.

My question, then, is why might the upward scrolling be less reliable than the downward? Any thoughts/guesses/suggestions?

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

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

发布评论

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

评论(2

祁梦 2024-12-24 04:22:52

这是我最终得到的代码。它运行完美,并且其大小约为原始代码的四分之一。

$(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();
    });

});

This is the code I ended up with. It's working perfectly, and it's about a quarter of the size of the original code.

$(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();
    });

});
信愁 2024-12-24 04:22:52

我的猜测如下:

前置需要比附加更多的渲染工作,因为插入元素之后的所有 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);    
});

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

My guess is following:

prepending requires much more rendering efforts then appending, since all dom that goes after inserted element should be rebuilded. while appending there are no elements after inserted one

Anyway, jquery works MUCH faster if you prepend/append only once and not 50 times

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

you should rewrite this block, in order to minimize number of prepends

I suppose you dont have many sections, so you can do something like this

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

i suppose you will change something, to adjust to your code, but this is idea -> minimize number of dom change operations, prepare bunch of elements and insert them alltogether

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