AJAX Прелоадеры

Многие программисты оптимизируют JavaScript и CSS-код, чтобы страница грузилась быстрее. Но не все из них делают прелоадеры, которые дают пользователю эффект субъективно более быстрой загрузки.

Способ №1. Дешево и сердито.

Идея проста — необходимо поместить по центру картинку, которая будет показывать пользователю, что страница все еще загружается. Код довольно прост, пишем сразу после <body>:
<div id="preloaderbg" class="centerbg1">   <div class="centerbg2">     <div id="preloader"></div>   </div> </div>   <script type="text/javascript"> document.getElementById('preloaderbg').style.display = 'block'; document.body.style.overflow = 'hidden'; </script>

CSS-код:

.centerbg1 {   display: none;   width:100%;   height:100%;   position: absolute;   top: 0px;   left: 0px;   z-index: 1000;   background: url('/design/im/texture1.jpg') #3c363e; }   .centerbg2 {   position: absolute;   left: 50%;   top: 50%; }   #preloader {   top: -50%;   left: -50%;   position: relative;   width: 333px;   height: 26px;   background: url('/content/pages/articles/preloaders/bg2.gif');   border: solid #edda3d 2px; }

В результате у нас сразу после загрузки появляется блок с анимированным прогрессбаром по центру страницы. Параметр overflow нужно менять для того, чтобы не появилась полоса прокрутки и пользователь не мог прокрутить вниз и поглядеть на содержимое странички.

Потом, когда все загрузилось — нужно убрать прелоадер и установить overflow в положение visible. document.getElementById('loaderbg').style.display = 'none'; document.body.style.overflow = 'visible';

Эту часть кода я поместил в файл с JS-функциями, plreloader1.js

Если делать прогрессбар из анимированного GIF-рисунка, то он может получиться слишком тяжелым, порой даже больше самой странички, где его размещают. Поэтому лучше нарисовать полоску (например,такую), поставить ее как фон у блока с ID preloader и двигать бекграунд-позишн по таймеру.

<script type="text/javascript">   document.getElementById('loaderbg').style.display = 'block';   document.body.style.overflow = 'hidden';   pbPos = 0;   pbInt = setInterval(function() {   document.getElementById('preloader'). style.backgroundPosition = ++pbPos + 'px 0';   }, 25); </script>

И после загрузки делаем вот что:

clearInterval(pbPos); document.getElementById('loaderbg').style.display = 'none';

Результат работы можно посмотреть тут.

У этого способа есть недостатки. Если ставить скрытие прелоадера на onload, т.е. когда ждать, пока загрузятся все картинки, то пользователь может подумать, что страница просто зависла — фактически кроме анимации ничего не происходит. Если же вешать на $(document).ready() из jQuery, то после исчезновения прелоадера картинки только будут подгружаться.

Поэтому предлагается использовать…

Способ №2. Истина где-то рядом, или джедаи наносят ответный удар.
Для начала нарисуем 2 полосы загрузки — активную и не очень.




Поставим неактивную как фон, а активную сделаем фоном у дива, для которого будем менять ширину в зависимости от процента загрузки.

<div id="loaderbg" class="centerbg1">  <div class="centerbg2">   <div id="preloader">    <img alt="Загрузка..." src="/design/im/progbar_ph.gif" />    <div id="progbarfg"></div>   </div>  </div> </div>

progbar_ph.gif – это картинка высотой в 1 пиксель и шириной с нашу полосу прокрутки (данный пример глючит без нее в IE, и я пока не нашел другого способа выровнять по центру див с прогрессбаром).
Стили такие же, как и в предыдущем способе, разве что
#progbarfg {width: 0px; background: url('/design/im/progbar_fg.png')}

Теперь осталось сделать небольшой скрипт, который будет динамически подгружать содержимое сайта и картинки. Он нужен для того, чтобы прогрессбар показывался и изменялся еще до того, как скачается используемый фреймворк и другие JS-файлы.

Возьмем средний сайт, сделанный полностью на AJAX. Загрузка примерно происходит так:
грузится HTML-код начинают грузиться картинки затем некий фреймворк дополнительные JS-файлы (хотя лучше все склеить в один) запускается некая функция (или несколько), которая стягивает дополнительный контент.
Всему этому (за вычетом CSS и HTML) мы назначаем вес в байтах (или условный вес), например, единицу, и по мере загрузки каждого файла (или выполнения функции) мы двигаем наш прогрессбар.

Я реализовал 2 метода — первый простой, включается дело так:
непосредственно перед </body> пишем

<script type="text/javascript">
dLoader.start('progbarfg', 333, 'count');
</script>


Первым параметром идет идентификатор блока с активной полосой загрузки в качестве фона, вторым — ширина картинки, третий параметр — это метод, которым будем считать вес контента.

Скрипт сканирует все картинки на страницы и назначает им вес равный 1. Все JS-файлы прописываются в его теле, как я расскажу чуть ниже.
Однако хочется, чтобы вес у каждой единицы контента был не единицей, а реальным объемом в байтах. Да и для AJAX-приложений хотелось бы сразу подгрузить всю графику.

Для этого я написал скрипт на PHP, который сканирует папку с картинками оформления и заносит это все дело с размерами файлов в массив, опционально сжимая.

Так что дописав перед </body> следущее, мы получим прогрессбар, который будет показывать ход загрузки всего контента на странице, после чего плавно исчезнет.

<script type="text/javascript">   dLoader.start('mainprogbarfg', 333, 'size', function(){ $('#preloaderbg').fadeOut(250); }); </script>

Когда загрузились все JS-файлы, запускаются функции, которые есть в массиве invoke. Если мы с помощью jQuery подгружаем контент, то функция будет выглядить так:

function fn(callBack){ $.get('/', params, function(data){ someHandler(data); eval(callBack); }); }

PHP-скрипт делает следующее: он заносит в массив необходимые скрипты с их размерами, а так же картинки и дополнительные функции. Код:

$data['js'] = array(   array('path' => 'jquery-1.2.6.min.js', 'size' => filesize($jsRoot.'/jquery-1.2.6.min.js')),   array('path' => 'functions.js', 'size' => filesize($jsRoot.'/functions.js')) ); $data['im'] = GetFiles($imgRoot, true); $data['invoke'][] = array(   'action' => 'loadTemplates',   'size' => GetDirSize(dirname(__FILE__).'/design/ ajax templates/', false) ); $data['jspath'] = '/design/js/'; $data['impath'] = '/design/im';

Уже после того, как загрузились все картинки и JS-файлы, вызывается событие onLoad, которое вы указали в функции dLoader.start()

Еще есть способ кастомизации процесса загрузки:

dLoader.userProgress = function(bytesLoaded, totalBytes){ doSmth(); }

Для того, чтобы использовать это, нужно отредактировать PHP-скрипт, прописав в нем свои пути и JS-библиотеки, затем запустить его, чтобы он сгенерировал скрипт загрузчика. Ну и прописать его между <head> и </head>.

Работающий пример второго варианта лежит здесь.
Архив со скриптами можно взять отсюда