Я создаю веб-страницу, которая предназначена для мобильного сафари, и я создаю список динамически. Список создается из текстового файла, в котором я получаю информацию и добавляю эту информацию в список. Он прекрасно работает, когда имеется около 200 элементов, но когда файл очень большой (я пробовал до 4000 элементов), страница становится очень медленной, прокрутка и выбор этих элементов очень сложны. Я знаю, что не должен создавать столько HTML-элементов, но я ищу способ создать более короткий список и заменить информацию об элементах списка в зависимости от того, сколько прокрутки вы сделали. Любые идеи?
Вместо того, чтобы добавлять элементы в список, как насчет одновременного отображения до 200 элементов с последующей заменой текущих элементов при прокрутке вперед-назад? Вы можете использовать для этого innerHTML или методы DOM, которые создают элементы.
Чтобы не усложнять ситуацию, я с самого начала опущу возможность использования специализированной библиотеки JavaScript UI. Лично я не стал бы использовать такое решение, поскольку работа с библиотекой создает дополнительные ограничения (и, возможно, раздувает ваш проект) (если только вы не работаете над проектом, который сильно зависит от компонентов пользовательского интерфейса на стороне клиента, в этом случае вам следует выбрать одну библиотеку пользовательского интерфейса и придерживаться ее).
Также я не буду рассматривать "прокрутку" в качестве решения (т.е. создание бесконечного списка объектов DOM и простое прокручивание их). IMHO это не совсем "решение" проблемы, это просто метод создания проблемы, который привел вас сюда.
Вы должны помнить, что на стороне клиента язык JavaScript в некотором смысле "привязан" к объектной модели документа браузера. Ваш код JavaScript практически "говорит" браузеру изменить иерархию DOM огромным количеством способов, а браузер подчиняется. Это основная причина, по которой чистый код JavaScript имеет тенденцию работать быстро, а затем все резко замедляется, когда начинаются манипуляции с объектами DOM.
Главное правило, которому нужно следовать, на мой взгляд, заключается в том, чтобы минимизировать, насколько это возможно для человека, количество манипуляций с объектами DOM, следуя следующей схеме:
Если возможно, делайте это на стороне сервера: это может оказаться очень последовательным и надежным решением; если ваш проект позволяет это, вы должны посылать браузеру только разумно большие сегменты данных в любой момент времени (например. например, одну страницу из всего набора), это позволит клиенту правильно отображать и манипулировать этими данными в быстром и отзывчивом режиме.
Если вы должны делать это на стороне клиента, избегайте касаться DOM как можно больше: это очень важно; если вы получаете 4000 объектов в JS-скрипте, держите их в памяти, не спешите переводить все эти элементы в объекты DOM; это смертный приговор.
манипулируйте DOM только в последний возможный момент и затрагивая наименьшее количество объектов: поскольку модификация DOM требует много усилий (по сравнению с другими операциями в памяти). Другой опасностью здесь является утечка памяти (браузеры не совершенны), так как при создании и удалении большого количества объектов DOM, некоторые из этих удаленных объектов могут все еще оставаться в памяти, создавая утечку памяти (которая в конечном итоге может засорить браузер или даже систему).
Вот подходы, представленные на столе:
Server-side pagination: возможно, это очевидно, но слишком часто люди пытаются упустить этот вариант, и я считаю это неправильным. Опять же, если ваши проекты это позволяют, то очень сложно, чтобы такое решение вас подвело: оно может быть очень последовательным и надежным (именно поэтому оно является классикой).
Client-side pagination: Очевидно, что вы можете отправить все данные в браузер, обработать их в JS, а затем отобразить их в разумных размерах сразу, никогда не превышая определенного количества сгенерированных DOM-объектов. Это может показаться привлекательным и более простым, чем решение 1, однако следует помнить, что если ваши данные двунаправленные (т.е. предполагают вмешательство и обратную связь с пользователем, которые должны возвращаться на сервер) и важные (например, более важные, чем статистические/отчетные данные, которые нужно только отображать), то вам, вероятно, следует избегать этого варианта.
Причина в том, что даже если JavaScript достаточно быстр и эффективен, чтобы жонглировать этими данными в памяти, это не так безопасно; вы никогда не знаете, что может произойти на стороне клиента: память может быть повреждена, браузер может упасть и т.д. ; в принципе, у вас нет разумной гарантии сохранности ваших данных. Сервер лучше подготовлен для работы с важными данными. Более того, будет очень трудно обеспечить навигацию по истории между страницами и URL-адреса, ведущие на определенные страницы в наборе данных (и то, и другое возможно, но в любом случае не без головной боли).
Динамическая прокрутка на стороне клиента: вместо того, чтобы отображать объекты из памяти JS в виде полных страниц, вы просто показываете разумное подмножество, скажем, 100 элементов, а затем прокручиваете вниз, беря один объект (или более) сверху и перемещая его в нижнюю часть списка, соответствующим образом изменяя его содержимое. Очевидно, что этот вариант представляет те же опасности, что и решение 2, но это все равно очень хорошее решение.
Учитывая, что ваши проекты работают для мобильных устройств, я считаю последний подход, вероятно, более приемлемым для вас, поэтому вот (очень) упрощенный пример того, как это можно сделать с помощью MooTools (очевидно, принцип может быть применен с помощью любого фреймворка):
<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>
Извините за довольно длинный код... надеюсь, это поможет.
Вы можете создать что-то вроде "виртуальной прокрутки" - показать только несколько элементов (которые можно просмотреть на экране) и заставить появляться полосу прокрутки, смещая их с помощью полей. Таким образом, вы заставите пользователя думать, что у него 4000 элементов на экране, а в памяти у него только 20 элементов.
Использовать таблицу данных. Два, о которых я знаю, - это 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>
Это пример изображения того, как она будет выглядеть. Единственная проблема с обработкой на стороне сервера заключается в том, что вам придется передавать информацию в формате 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>