стрілка вверх

preloading articles

Дозавантаження статей із БД засобами AJAX

січень 2016

Автор: Анатолій

Займаючись навчанням основ програмування на власному сайті та залишаючи нотатки у вигляді навчальних статей склалась така ситуація, що маю досить значну кількість статей і головна сторінка, де представлений короткий анонс статей перевантажена. В мережі Інтернет є варіант проектування головної сторінки, коли завантажуються лиш, скажімо, перші десять статей, а інші підвантажуються засобами асинхронного javascript - AJAX,- за умови, що відвідувач сайту дійшов до останнього/нижнього анонсу статті.

Що ж, давайте розглянемо як реалізувати цей задум...

Зміст

  1. Алгоритм дозавантаження веб-сторінки
  2. Клієнтська частина скрипту
    1. Частина javascript-скрипту визначення висоти HTML-документу, висоти прокрутки веб-сторінки та визначення висоти екрану відвідувача
    2. Метод append() бібліотеки jQuery
    3. Відправлення AJAX-запиту
    4. Час виконання AJAX-запиту
    5. Зупинка AJAX-запиту
  3. Серверна частина
  4. Демо сторінка динамічного завантаження контенту
  5. Використані інтернет джерела

1. Алгоритм дозавантаження веб-сторінки

Думаю, зрозуміло, що можливості сучасних мов програмування досить широкі. Щоб реалізувати задум автоматичного дозавантаження контенту з Бази Даних нам необхідно виконати логіку, як на стороні клієнту (тобто на стороні користувача веб-сайту), так і виконати логіку на серверній стороні.

Структурна схема основних функціональних блоків динамічного дозавантаження контенту веб-сторінки може бути як на рисунку 1.

preloading articles

Рис.1. Структурна схема динамічного дозавантаження контенту.


Розглянемо, які ресурси нам необхідні для реалізації задумки:

1. javascript - а саме бібліотека javascript, jQuery, для контролю за тілом HTML-документу. Скрипт буде контролювати чи користувач веб-сайту прокрутив повністю веб-сторінку і чи необхідно дозавантажувати слідуючий контент. Якщо виконується умова виконання AJAX-запиту -> формується тіло HTML-документу з отриманих від серверу даних.

2. На сервері реалізуємо php-обробник. Він виконує декілька функцій:
- Обробляє AJAX-запит, обробник отримує запит від клієнта щодо номеру контенту з якого буде формуватись запит до вибору даних з таблиці БД,
- Формує SQL-запит до таблиці Article_List на вибір даних,
- Формує частину HTML-документу, що буде дозавантажуватись на клієнтській стороні.


info label

AJAX (Asynchronous JavaScript And XML) — підхід до побудови користувацьких інтерфейсів веб-застосунків, за яких веб-сторінка, не перезавантажуючись, у фоновому режимі надсилає запити на сервер і сама звідти довантажує потрібні користувачу дані.

Документація jQuery API docs...


Давайте розглянемо приклад, коли в нас є певна кількість статей, що знаходяться в таблиці Article_List:

IdArticle categoryArticle themeArticle linkArticle previewArticle picture link
11Що таке Інтернет?лінк до статтіСтаття знайомить з технікою реалізації мережі мереж - Інтернету... лінк на картинку
22Авторизаціялінк до статтіВелика кількість веб-сайтів вимагають авторизації користувачів, -Яким чином виконується авторизація? На це питання дає відповідь...лінк на картинку
31Як реалізувати quiz?лінк до статтіСтворити Опитування користувачів досить легко, для цього необхідно...лінк на картинку
..................
N2Знайомство з БДлінк до статтіВелика кількість веб-сайтів втратить свою функціональність, якщо не застосовувати можливості Бази Даних...лінк на картинку

Дані (атрибути таблиці), що описують статтю:
Id - номер статті в таблиці Article_List,
Article category - категорія статті, наприклад, стаття відноситься до тематики 1 - PHP, 2 - MySQL, 3 - загальна тематика, основи, та таке інше...,
Article theme - тема статті,
Article link - посилання на статтю, щось на зразок, http://bestwebit.biz.ua/pages_04/preloading_articles.php,
Article preview - короткий анонс статті,
Article picture link - посилання на картинку статті.



2. Клієнтська частина скрипту

Скрипт javascript, що на стороні клієнту, повинен виконувати AJAX-запит до PHP-обробника, як лиш користувач прокрутив веб-сторінку до кінця html-сторінки, та розмістити результати AJAX-запиту у відведену область веб-сторінки.

2.1. Частина javascript-скрипту визначення висоти HTML-документу, висоти прокрутки веб-сторінки та визначення висоти екрану відвідувача.

Для того, щоб динамічно оперувати контентом веб-сторінки нам необхідно знати:
- висоту HTML-документу,
- висоту прокрутки веб-сторінки,
- висоту вікна веб-сторінки відвідувача.

Тобто, яка умова довантаження контенту? - Як лиш висота прокрутки веб-сторінки плюс висота вікна веб-сторінки буде рівною висоті HTML-документу, то необхідно виконати AJAX-запит на дозавантаження контенту.

if(height_scroll+height_win >= height_doc){
   /* виконати AJAX-запит */
  };

Застосуємо слідуючий скрипт:

/* підключаємо бібліотеку jquery */
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>

/* сам скрипт визначення даних висоти*/
<script>
$(document).ready(function(){
  $(document).mousemove(function(event){
   /* висота документу */
   var height_doc = $(document).height();
   /* висота вікна */
   var height_win = $(window).height()
   /* висота прокрутки вікна */
   var height_scroll = $(window).scrollTop();
   
   $( "#height_doc_info").text("Висота HTML-документу:"+height_doc);
   $( "#height_window_info").text("Висота вікна:"+height_win);
   $( "#height_scroll_info").text("Прокрутка:"+height_scroll);
 }); 
});
</script>

Як приклад, маємо слідуючі актуальні дані:

2.2. Методу append() бібліотеки jQuery.

Результат виконання AJAX-запиту добавляється у встановлений блок за допомогою jQuery методу append() jQuery API docs...

Приклад застосування методу append():

<script>
$( "#demo_append" ).append( "Hello" );
</script>

<p id="demo_append">I would like to say: </p>

Результат виконання:

I would like to say:

В нашому випадку результуючі дані із сервера Бази Даних, що виконав AJAX-запит, будемо добавляти в область <div id="articles"></div>

2.3. Відправлення AJAX-запиту.

Дещо особлива частина скрипту, як на мене варто бути уважним із створенням коду.

Ще раз лінк, щоб пригадати синтаксис AJAX-запиту jQuery API docs...

<script>

/* Номер id контенту, з якого будемо виводити слідуючі статті */
 var startFrom = 10;

/* висота документу */
var height_doc = $(document).height();
/* висота вікна */
var height_win = $(window).height()
/* висота прокрутки вікна */
var height_scroll = $(window).scrollTop();

/* Умова, якщо кінець HTML-документу, виконуємо AJAX-запит*/
if( height_scroll+height_win>= height_doc ){
  $.ajax({
  /* url-адресa PHP-обробника AJAX-запиту */
  url: 'http://.../php_handler.php',
  /* метод відправки AJAX даних */
  method: 'POST',
  /* дані, що відправляємо обробнику */
  data: {"startFrom" : startFrom},
  /* що необхідно виконати після запиту */
  }).done(function(data){            
    /* вносимо нові дані на веб-сторінку*/
    $("#articles").append(data); 
    /* та збільшуємо номер id контенту, що будемо виводити */               
    startFrom += 10;              
    });
};
            
</script>

2.4. Час виконання AJAX-запиту

2.4.1. Індикатор завантаження. Варто також реалізувати функцію скрипту, що показує процес виконання завантаження контенту, так як час виконання запиту може бути різний і при достатньо довгому очікуванні користувач помилково подумає, що контент закінчився.

2.4.2. Мульти-AJAX-запит. Як у фільмі "5 Елемент": - Корбен Даллас Мультипаспорт :).
Бажано реалізувати функцію, що виключає можливість відправлення більше одного AJAX-запиту в один і той самий час. Тобто, щоб скрипт не відправив Вам два чи більше раз однаковий контент.

Щоб реалізувати дану функцію:
1. Застосуємо прапор inprogress. Суть даного прапору буде слідуюча, якщо запит не виконується inprogress = false.
2. Якщо AJAX-запит виконується inprogress=true.
3. Додатково застосуємо умову під час відправлення AJAX-запиту на стан прапорця.

Схема роботи даної функції скрипту щось на зразок:

<script>
$(document).ready(function(){
var inProgress = false;

/*двійна умова виконання AJAX-запиту: по висоті та стану прапору*/
if( height & !inProgress) {
  $.ajax({
     url: '....php',            
     method: 'POST',            
     data: {...},
            
     /* до відправки запиту */
     beforeSend: function() {
     /* змінюємо на true,*/
     inProgress = true;}
     }).done(function(data){                            
      /* вносимо нові дані */
      $("#articles").append(data);                      
      startFrom += 10; 
      /* По факту закінчення запиту*/
      inProgress = false;
    }); 
};	

</script>

2.5. Зупинка AJAX-запиту

Що ж робити якщо вибраний весь контент/статті в таблиці Бази Даних?

Я вирішив цю задачку слідуючим чином: Якщо дані відсутні, що повертаються від PHP-обробника, то виводимо повідомлення "Статті закінчились"

<script>
/* виконання AJAX-запиту */
$.ajax({  
  /* що необхідно виконати після запиту */
  }).done(function(data){            
    
    if (data.length>0) {                     
      /* вносимо нові дані */
      $("#articles").append(data); 
      /* збільшуємо номер id контенту*/               
      startFrom += 10; 
    }else{
      $("#data_info").text('Статті закінчились!');
    };             
  });
</script>

3. Серверна частина

PHP-скрипт, що обробляє AJAX-запит має вигляд:

<?php
// отримуємо номер id статті з якої будемо довантажувати контент 
$startFrom = $_POST['startFrom'];

// з'єднуємось з БД
$mysqli = new mysqli("localhost","user","password","database");
// встановлюємо кодування обміну даними utf8
mysqli_set_charset($mysqli, "utf8");

// порахуємо кількість записів в таблиці
$res = $mysqli->query("SELECT count(id) as count 
			FROM Article_List;");
$row_count = $res->fetch_assoc(); 
$count_articles =  $row_count["count"];

// вибираємо необхідні дані із таблиці БД
$result = $mysqli->query("SELECT * 
			FROM Article_List 
			LIMIT $startFrom,10");
if ($startFrom<$count_articles ) {  
  while ($row = $result->fetch_assoc()){ 
  
    // формуємо HTML-сторінку
    echo "<div class='one_article'><h4>Тема: ". 
    $row['article_theme']."</h4>Id статті: ".
    $row['id']." категорія ".
    $row['article_category'].",<br>Лінк на статтю: ".
    $row['article_link']."</br> Лінк на картинку: ". 
    $row['article_picture_link']."<p>Коротко:<br>". 
    $row['article_preview']."</p></div>";
  };   
};
$mysqli->close();
?>

Коротко про роботу скрипту;

1. Отримуємо змінну $startFrom, яка використовується, щоб створити SQL-запит до таблиці Бази Даних, з якого id виводити контент. Тобто дані виводяться, наприклад, з 10, 20 , 30 рядка й так далі... Кількість записів визначаємо оператором LIMIT, в даному випадку вказано виводити по 10 записів.

SELECT * FROM Article_List LIMIT $startFrom,10

2. З'єднуємось з БД та вибираємо необхідні дані.

3. Необхідно ще реалізувати слідуючий момент, необхідно передати контент браузеру в кількості записів в таблиці. Щоб порахувати кількість записів таблиці запишем SQL-запит:

$res = $mysqli->query("SELECT count(id) as count 
			FROM Article_List;");
$row_count = $res->fetch_assoc(); 
$count_articles =  $row_count["count"];

Якщо AJAX-запит присилає звернення $startFrom більше кількості записів в таблиці $count_articles, то PHP-скрипт, звісно, ніяких данних не віддає. А стороні клієнту ми перевіряємо if (data.length>0) {... }, якщо даних немає, то виводимо інформаційне повідомлення "Статті в БД закінчились!"


4. Демо сторінка

Приклад роботи веб-сторінки з дозавантаженням статей із таблиці Бази Даних можна переглянути на окремій сторінці:


5. Використані інтернет джерела:

  1. jQuery API Asynchronous HTTP Ajax request
  2. Ресурс w3schools AJAX Tutorial
  3. Ajax with jQuery: A Beginner's Guide