Как я могу обработать список с несколькими сотнями элементов в HTML?(Используя Javascript) - PullRequest
7 голосов
/ 18 августа 2010

Я создаю веб-страницу, предназначенную для мобильного сафари, и создаю список динамически. Список создается из текстового файла, в котором я получаю информацию, и я добавляю эту информацию в список. Он прекрасно работает, когда имеется около 200 элементов, но когда файл очень большой (я пробовал до 4000 элементов), страница становится очень медленной, прокрутка и выбор этих элементов очень сложны. Я знаю, что не должен создавать столько HTML-элементов, но я ищу способ создать более короткий список и заменить информацию об элементах списка в зависимости от того, сколько прокрутки вы сделали. Есть идеи?

Ответы [ 5 ]

3 голосов
/ 23 августа 2010

Разъяснение

Для простоты я с самого начала буду использовать возможность использования специализированной библиотеки JavaScript UI. Лично я бы не использовал такое решение, так как участие в библиотеке создает дополнительные ограничения (и, возможно, раздувание) для вашего проекта (если вы не работаете над проектом, который в значительной степени опирается на компоненты пользовательского интерфейса на стороне клиента, и в этом случае вы должны выбрать один). Библиотека пользовательского интерфейса и придерживаться ее).

Кроме того, я не буду рассматривать «прокрутку» как решение (то есть создание бесконечного списка объектов DOM и простую прокрутку по ним). ИМХО, на самом деле это не «решение» проблемы, это просто метод генерации проблемы, которая привела вас сюда.

Думай поток

Вы должны иметь в виду, что на стороне клиента язык JavaScript в некотором смысле «привязан» к объектной модели документа в браузере. Ваш код JavaScript практически «говорит» браузеру, что нужно изменить иерархию DOM множеством способов, и тогда браузер согласится. Это основная причина, по которой чистый JavaScript-код имеет тенденцию работать быстро, а затем резко замедляется, когда начинаешь манипулировать объектами DOM.

Основное правило, которому нужно следовать, на мой взгляд, состоит в том, чтобы максимально минимизировать количество манипуляций с объектами DOM, следуя этому потоку:

  1. Если возможно, сделайте это на стороне сервера : это может оказаться очень последовательным и надежным решением; если ваш проект допускает это, вы должны отправлять в браузер только сегменты данных разумного размера (например, одну страницу из всего набора), это позволит клиенту правильно отображать и обрабатывать эти данные в кратчайшие сроки. и отзывчивый способ.

  2. Если вы должны сделать это на стороне клиента, старайтесь не трогать как можно больше DOM : это важно; если вы получаете 4000 объектов в JS-скрипте, храните их в памяти , не спешите переводить все эти элементы в объекты DOM; это смертный приговор.

  3. Манипулировать DOM только в последний возможный момент и касаться наименьшего количества объектов : поскольку для модификации DOM требуется много усилий (по сравнению с другими Операции с памятью). Другая опасность здесь - утечка памяти (браузеры не идеальны), так как при создании и отбрасывании многих объектов DOM некоторые из этих отброшенных объектов могут все еще сохраняться в памяти, что приводит к утечке памяти (которая может в конечном итоге привести к зависанию браузера или даже системы). ).

Решения

Вот подходы на столе:

  1. Разбивка на стороне сервера : возможно, это очевидно, но слишком часто люди пытаются пропустить этот вариант, и я думаю, что это неправильно. Опять же, если ваши проекты позволяют это, очень трудно для такого решения подвести вас: оно может быть очень последовательным и надежным (вот почему это classic ).

  2. Разбиение на стороне клиента : Очевидно, что вы можете отправить все данные в браузер, обработать их в JS, а затем сразу отобразить в виде кусков разумного размера, не превышая определенного количества сгенерированные объекты DOM. Это может показаться привлекательным и более простым, чем Решение 1, однако, имейте в виду, что если ваши данные являются двунаправленными (то есть подразумевают вмешательство и обратную связь от пользователя, которые должны вернуться на сервер) и важными (например, более важными, чем статистические данные / данные отчетности, которые нужны только ), вам, вероятно, следует избегать этой опции.

    Причина в том, что даже если JavaScript достаточно быстрый и эффективный для манипулирования этими данными в памяти, он не настолько безопасен ;Вы никогда не знаете, что может произойти на стороне клиента: память может быть повреждена, может произойти сбой браузера и т. д. ;в основном у вас нет разумной гарантии для ваших данных.Сервер лучше подготовлен для обработки важных данных.Более того, будет очень трудно иметь историю навигации между страницами и URL-адресами, которые переходят на конкретные страницы в наборе данных (оба возможны, но в любом случае не без головной боли).

  3. Клиентская динамическая прокрутка : вместо отображения объектов из памяти JS в виде полных страниц, вы просто показываете разумное подмножество, скажем, 100 элементов, а затем прокручиваете вниз, беря один объект (или больше)сверху вниз и перемещая его в конец списка, соответственно изменяя его содержимое.Очевидно, что этот вариант представляет те же опасности, что и решение 2, но все же это очень хорошее решение.

Пример

Учитывая, что ваши проекты работают на мобильных устройствах, я считаю, чтоПоследний подход, вероятно, более выполним для вас, поэтому вот (очень) упрощенный пример того, как это можно сделать с помощью MooTools (очевидно, этот принцип может быть применен с использованием any framework):

<html>

<head>

    <title>Endless scrolling example.</title>

    <!-- Include the MooTools framework. -->
    <script type="text/javascript" src="mootools-1.2.4-core-yc.js"></script>

    <!-- Note: we'll use id's to select objects since it's faster. -->

</head>

<body>

    <!-- Scroll up. -->
    <a href="javascript:void(0);" id="list_up_button">Up!</a>

    <!-- The list (i.e. container). -->
    <ul id="list_container">
    </ul>

    <!-- Scroll down. -->
    <a href="javascript:void(0);" id="list_down_button">Down!</a>

</body>

<!-- Our script. -->
<script type="text/javascript">

    window.addEvent('domready', function() {

        // database
        var list = {};

        // options
        var list_size = 5000;   // total list size
        var list_offset = 0;    // initial list position
        var list_subset = 40;   // the smount of displayed items
        var scroll_step = 10;    // items to scroll in one step
        var time_delay = 50;    // time delay between scroll steps

        // make dummy items
        for (var i = 0; i < list_size; i++) {
            var red = Math.floor(i * 2) % 256;
            var green = Math.floor(i * 3) % 256;
            var blue = Math.floor(i * 4) % 256;

            list[i] = "<span style=\"color:rgb(" + red + ", " + green + ", " + blue + ");\">" +
                      "My name is 'Object no." + (i + 1) + "'." +
                      "</span>";
        }

        // get container
        var list_container = $('list_container')

        // generate DOM objects
        for (var i = 0; i < list_subset; i++) {
            list_container.grab(new Element('li', { html: list[i] }));
        }

        // Up scroller.
        function up() {

            // check end
            if (list_offset <= 0) {
                return false;
            }

            // get element
            var element = list_container.getLast();

            // devance offset
            list_offset--;

            // re-write element
            element.set('html', list[list_offset]);

            // move top element to top
            list_container.grab(element, 'top');

            // success
            return true;
        }

        // Down scroller.
        function down() {

            // check end
            if (list_offset >= list_size - list_subset) {
                return false;
            }

            // get element
            var element = list_container.getFirst();

            // advance offset
            list_offset++;

            // re-write element
            element.set('html', list[list_offset + list_subset - 1]);

            // move top element to bottom
            list_container.grab(element, 'bottom');

            // success
            return true;
        }

        // Repeater function.
        function repeater(direction) {

            for (var i = 0; i < scroll_step; i++) {

                // scroll
                if (direction() == false) {

                    // deactivate repeater
                    $clear(list.scroll_period);
                }
            }

        }

        // configure up scroll
        $('list_up_button').addEvents({

            // activate scroll
            'mouseenter': function() {
                list.scroll_period = repeater.periodical(time_delay, null, up);
            },

            // deactivate scroll
            'mouseleave': function() {
                $clear(list.scroll_period);
            }
        });

        // configure up scroll
        $('list_down_button').addEvents({

            // activate scroll
            'mouseenter': function() {
                list.scroll_period = repeater.periodical(time_delay, null, down);
            },

            // deactivate scroll
            'mouseleave': function() {
                $clear(list.scroll_period);
            }
        });

    });

</script>

Извините за довольно длинный код ... надеюсь, это поможет.

0 голосов
/ 23 августа 2010

Даже если вы хотите отобразить весь большой список за один раз, используйте фрагмент документа

0 голосов
/ 18 августа 2010

Вы можете создать что-то вроде «виртуальной прокрутки» - показать только несколько элементов (которые можно просмотреть на экране) и заставить полосу прокрутки появляться, смещая их с полями.Таким образом, пользователь будет думать, что у него 4000 элементов на экране и только 20 элементов в памяти.

0 голосов
/ 18 августа 2010

Использовать таблицу данных.Два из которых я знаю, это YUI2 dataTable и www.dataTables.net.Я использую www.dataTables.net, потому что это действительно хорошо, и я до сих пор к этому привык (хотя и не эксперт).Вы можете использовать обработку на стороне сервера, которую вы можете использовать для вызова php-файла или метода или другого javascript, но он соберет x количество записей для вас и знает, с чего начать, когда вы разбиваете на страницы (нумерация страниц уже предоставляется с dataTable.

Вы бы создали таблицу следующим образом:

<script type="text/javascript" char="utf-8>
  $(document).ready(function() {
    $('#tableName').dataTable({
      "bProcessing": true,
      "bServerSide": true,
      "sAjaxSource": "php_filename.php",
      "sPaginationType": "full_numbers"
    });
  });
</script>

from dataTables.net

Это пример изображения того, как он будет выглядеть. Единственная проблема с работой сервераобработка на стороне означает, что вам придется передавать информацию в формате JSON.

 "aaData": [
  "info1",
  "info2",
  etc...
]

Элементы управления могут быть добавлены в записи aaData. Здесь является хорошим примером. Надеюсь, этопомогает.

Обновление 2: Вам нужно будет загрузить файл jQuery (1.4.1 - это версия, которую я использовал), и вам нужно будет сослаться на файл jQuery , dataTable.jsфайл и css. Имя класса таблицы должно быть «display». Имя css: demo_table.css.

<script type="text/javascript" language="javascript" src="../Scripts/jquery-1.4.1.js"></script>
<script type="text/javascript" language="javascript" src="../Scripts/jquery.dataTables.js"></script>

<style type="text/css" title="currentStyle">
  @import "../../Content/stylesheets/demo_table.css"
</style>
0 голосов
/ 18 августа 2010

Вместо добавления элементов в список, как насчет отображения до 200 одновременно, а затем замены текущих элементов при прокрутке вперед - прокрутке назад? Для этого вы можете использовать innerHTML или методы DOM, которые создают элементы.

...