Як створити веб-сайт за допомогою AJAX - Блог ITVDN
ITVDN: курси програмування
Відеокурси з
програмування
УКР
  • РУС
  • УКР

    Вибери свою IT спеціальність

    Підписка
    УКР
    • РУС
    • УКР
    Arrow
    Хочеш доступ до усіх відеокурсів надовго? Обирай преміум Весняний. Акція до 31 березня
    Arrow

    Як створити веб-сайт за допомогою AJAX

    advertisement advertisement

    Создания простого чата

    Для начала создадим простой чат с помощью HTML&CSS и PHP&MySQL

    Проектирование Базы Данных

    1. Переходим к phpMyAdmin.
    2. Создаем новую базу данных, называем “chatdb”.
    3. Создаем новую таблицу, называя “Posts”, включая в себя 4 столбца:
    • “id” тип колонки INT, автоматическое увеличение на 1 (задаем A_I в ячейку с флажком) основной ключ (index);
    • “nick” тип колонки VARCHAR и длина 100;
    • “post_text” тип колонки TEXT;
    • “post_dt” тип колонки DATETIME по умолчанию является CURRENT_TIMESTAMP.

    Создание веб-сайта.

    1. Во-первых, создадим главную страницу. Список комментариев и отправка формы, используя кнопку. Всё будет находится в файле “index.php” .  Давайте создадим этот файл и напишем что-то вроде этого: 

    <html>

    <head>

    head>

    <body>

    php

    $mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

    /* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

    /* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

    /* "chatdb" is DB's name. */

    /* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

    $result = $mysqli->query("SELECT * FROM posts;");

    ?>

    <style>

    /* All CSS is very simplified. I provide it for example and no more.

     * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

     */

    .content {

      display: table;

      width: 50%;

      min-width: 400px;

      height: 80%;

      /* Center horizontally and vertically */

      position: absolute;

      left: 0; right: 0;

      top: 0; bottom: 0;

      margin: auto;

      /* Design */

      border: 1px solid;

      background-color: silver;

      padding: 5px;

    }

    /* For mobile devices */

    @media (max-width: 400px) {

      .content {

        width: 100%;

        min-width: 0;

        padding: 0px;

      }

    }

    style>

    <div class="content">

    <div id="comments" style="overflow-y: scroll; height: 100%;">

    php

    if ($result) {

      while ($post = $result->fetch_object()){

        $nick = $post->nick;

        $post_dt = $post->post_dt;

        $post_text = $post->post_text;

       

        echo "<b>$nickb> ($post_dt):<br>";

        echo "$post_text<br>";

        echo "<br>";

      }

      $result->close();

    }

    ?>

    div>

    php

    $mysqli->close();

    ?>

    <form action="post.php" method="post" style="height: 0; display: table-row;">

      Nick:<br>

      <input type="text" name="nick" style="width: 100%;">input><br>

      <br>

      Text:<br>

      <textarea name="text" style="width: 100%;">textarea><br>

      <br>

      <input type="submit">input>

    form>

    div>

    <script type="text/javascript">

        var divComments = document.getElementById('comments');

        divComments.scrollTop = divComments.scrollHeight;

    script>

    body>

    html>

    2. Дальше давайте создадим “post.php” файл и напишем такое: 

    php

    $nick = $_POST['nick'];

    $post_text = $_POST['text'];

    $mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

    $nick = $mysqli->real_escape_string($nick);

    $nick = htmlspecialchars($nick);

    $post_text = $mysqli->real_escape_string($post_text);

    $post_text = htmlspecialchars($post_text);

    $mysqli->query("INSERT INTO posts (nick, post_text) VALUES ('$nick', '$post_text');");

    $mysqli->close();

    /* Redirect To Main Page */

    header('Location: ' . $_SERVER['HTTP_REFERER']);

    ?>

    3. Откроем ваш чат в любом продвинутом браузере. Вся работа: 

    4. Напишите ник и текст, а потом нажмите на кнопку отправки. 

    Когда отправили форму, сразу же происходит перенаправление формы главной страницы в “post.php”. “Post.php” моментально наполняет данными таблицу и перенаправляет на главную страницу. Также “post.php” содержит начальный XSS и SQL защищенный вход. Для упрощения не отправляем клиентам время с JS на “post_dt” на внесения данных, а указываем значение по умолчанию – CURRENT_TIMESTAMP, который предоставляет нынешнюю дату и время на сервер.

    Когда количество комментариев больше, чем экран может вместить, то комментарии   переполнены в div, используется вертикальный скроллбар. Во время загрузки страницы JS автоматически опускает скроллбар вниз к недавнему комментарию.

    Что тут не так?

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

    Это очень, очень серьезная проблема для любого чата.

    Как это исправить?

    Очевидно, один из путей сделать это - использовать HTTP-запрос к фоновой работе автоматически (с помощью JS) и асинхронно, то есть это один из способов обеспечить выполнение AJAX в любой form.

    Проблема номер 2. Также неправильно то, что кнопка отправки перезагружает страницу (перенаправляет на вторую страницу и следующим шагом возвращает назад).

    При перезагрузке страницы сбрасывает “Nick” в  поле (также, как любые другие изменения, те, что сделали с пользователем)

    Как это исправить?

    Конечно, можно обеспечить выполнение обхода для сохранения изменений и перезагрузки на перезагружаемой странице. Но не эффективнее ли устранить причину, чем последствие? Можно только убрать перезагружаемую страницу и эта проблема будет решена автоматически.

    Проблема номер 2.1. Видите ли что-то необычное тут?

    Это слишком быстро?

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

    Давайте попробуем.  Давайте немного изменим “post.php”, после $mysql->query() добавив это: 

    for ($i = 0; $i < 1000000000; $i++) { }

    Старайтесь размещать какие-либо комментарии. Что мы видим? Нет, UI не остановилось (заморозилось), но браузер ждет до того, как закончится подключение:  

    Да, если “post.php” вызывает какую-то необработанную ошибку, то чат исчезает, и пользователь видит пустое окно с сообщением о непонятной ошибке. Чтобы вернуться к чату, пользователю стоит нажать кнопку “Back” в браузере. И это проблема номер 2.2.

    Давайте уберем петлю с “post.php” и исправим эти проблемы.

    Реализация легкого AJAX в простой чат

    Автоматическое обновление комментариев

    Эта веб-страница без AJAX? Это веб-страница, которая полностью перезагружается.

    Эта веб-страница c AJAX? Это веб-страница, что перезагружается частично.

    Где же взять части этих страниц? Стоит разделить нашу страницу на части, в этом случае сервер генерирует страницу частично.

    Страница будет состоять из двух частей – блок комментариев и другой контент страницы. Комментарии будут загружаться и перезагружаться отдельно от другой страницы.

    Давайте сделаем первую часть, то есть блок комментариев.

    Для начала создадим пустой файл, назовем “getcomment.php”.

    Дальше переходим в “index.php” для того, чтобы вырезать комментарии и далее отделить его.
    1. Вырезаем инициализированный блок MySQL с “index.php" 

    php

    $mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

    /* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

    /* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

    /* "chatdb" is DB's name. */

    /* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

    $result = $mysqli->query("SELECT * FROM posts;");

    ?>

    вставляем в “getcomments.php”.

    2. Следующее, вырежем контент div c комментариями с “index.php”:

    php

    if ($result) {

      while ($post = $result->fetch_object()){

        $nick = $post->nick;

        $post_dt = $post->post_dt;

        $post_text = $post->post_text;

       

        echo "<b>$nickb> ($post_dt):<br>";

        echo "$post_text<br>";

        echo "<br>";

      }

      $result->close();

    }

    ?>

    И вставим (добавим) в “getcomments.php” после инициализации MySQL.

    3. Дальше, вырежем недалекий блок MySQL с “index.php”:

    php

    $mysqli->close();

    ?>

    Вставим его в конец файла “getcomments.php”.

    4. Наконец-то, убираем JS-скрипт, который опускает скролл в самый низ.

    <script type="text/javascript">

    var comments = document.getElementById('comments');

    comments.scrollTop = comments.scrollHeight;

    script>

    Не переживай, это только временно.

    5. Сделано. Теперь имеем что-то наподобие этого:

     <html>

    <head>

    head>

    <body>

    <style>

    /* All CSS is very simplified. I provide it for example and no more.

     * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

     */

    .content {

      display: table;

      width: 50%;

      min-width: 400px;

      height: 80%;

      /* Center horizontally and vertically */

      position: absolute;

      left: 0; right: 0;

      top: 0; bottom: 0;

      margin: auto;

      /* Design */

      border: 1px solid;

      background-color: silver;

      padding: 5px;

    }

    /* For mobile devices */

    @media (max-width: 400px) {

      .content {

        width: 100%;

        min-width: 0;

        padding: 0px;

      }

    }

    style>

    <div class="content">

    <div id="comments" style="overflow-y: scroll; height: 100%;">

    div>

    <form action="post.php" method="post" style="height: 0; display: table-row;">

      Nick:<br>

      <input type="text" name="nick" style="width: 100%;">input><br>

      <br>

      Text:<br>

      <textarea name="text" style="width: 100%;">textarea><br>

      <br>

      <input value="Submit" type="submit">input>

    form>

    div>

    body>

    html>

    getcomments.php:

     php

    $mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

    /* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

    /* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

    /* "chatdb" is DB's name. */

    /* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

    $result = $mysqli->query("SELECT * FROM posts;");

    ?>

    Вероятно, теперь наша страница разделена.

    Давайте проверим её. Переходим http (точнее ССЫЛКА для локального сервера).

    Дальше, переходим на главную страницу, http:///index.php

    Это удивительно! Всё удачно получилось, разделив страницу на части за пару минут!

    Не останавливаемся на этом. Теперь “glue” эти части с помощью AJAX. Как это сделать?

    1. Для начала стоит создать пустой JS-скрипт на главной странице:

    <script type="text/javascript">

    alert('Test');

    script>

    Добавив это после тега div, перед закрывающимся тегом .

    2. Сделаем HTTP GET запрос от JS к “getcommet.php”

    Для этого используем XMLHtttpRequest (XHR) класс:

    <script type="text/javascript">

    var xhr = new XMLHttpRequest();

    xhr.open('GET', '/getcomments.php', false);

    xhr.send(null);

    if (xhr.status == 200) {

      alert(xhr.responseText);

    }

    script>

    Это работает, но не читает старые версии IE те, что не поддерживают такую инициализацию.

    Для получения более кросс-браузерного пути переходим в

    и добавляем это:

    <script type="text/javascript">

    function getXmlHttp(){

      var xmlhttp;

      try {

        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

      } catch (e) {

        try {

          xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

        } catch (E) {

          xmlhttp = false;

        }

      }

      if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

        xmlhttp = new XMLHttpRequest();

      }

      return xmlhttp;

    };

    script>

    И главный скрипт (в конце)

    <script type="text/javascript">

    var xhr = getXmlHttp();

    xhr.open('GET', '/getcomments.php', false);

    xhr.send(null);

    if (xhr.status == 200) {

      alert(xhr.responseText);

    }

    script>

    Как видно, теперь JS получает контент со страницы “getcomments.php” и показывает это в предупреждении.

     

    2.1. Вопрос: «Это на самом деле AJAX (Asynchronous Javascript And Xml)?»

    Это AJAX, потому что запрос сервера отформатирован в HTML (который основан на XML).

    Но действительно ли это AJAX, это асинхронно?

    Проверим. Добавим эти уже знакомые строки в любое место между в “getcomments.php”:

    for ($i = 0; $i < 1000000000; $i++) { }

    Что теперь видно на загружаемой странице?

    Вначале страница зависает, его замораживает UI (становится не реагирующим на нажатие левой/правой кнопки мыши):

    Дальше Chrome показывает навязчивое всплывающие окно, сообщающее об удалении страницы:

    Это не AJAX! Это JAX! Как его сделать асинхронным?

    К счастью, ХHR также поддерживает асинхронный режим:

    <script type="text/javascript">

    var xhr = getXmlHttp();

    xhr.open('GET', '/getcomments.php', true); /* true for asynchronous */

    xhr.onreadystatechange = function() {

      if (xhr.readyState == 4) {

        if(xhr.status == 200) {

          alert(xhr.responseText);

        }

      }

    };

    xhr.send(null);

    script>

    В этом случае браузер не ждет ответа с главного потока пользовательского интерфейса, он запускает в другом (асинхронно) и вызываемым событием “onreadystatechange” в главном контексте UI. 

    Теперь всё в порядке, страница полностью доступна, пока запрос запущен, и после ответа получит предупреждение.

    for ($i = 0; $i < 1000000000; $i++) { }

    И продолжаем работу.

    3. Добавляем этот контент в div  вместо предупреждения. Заменить это:

    alert(xhr.responseText); 

    C этим:

    var divComments = document.getElementById('comments');

    divComments.innerHTML = xhr.responseText;

    Возвращаем назад, клиент видит “glued” страницу с блоком комментариев.

    4. Дальше следует установить интервал для автоматической проверки новых комментариев время от времени… и также восстановить удаленный сценарий автоматической прокрутки. 

    <html>

    <head>

    <script type="text/javascript">

        function getXmlHttp() {

            var xmlhttp;

            try {

                xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

            } catch (e) {

                try {

                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

                } catch (E) {

                    xmlhttp = false;

                }

            }

            if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

                xmlhttp = new XMLHttpRequest();

            }

            return xmlhttp;

        };

    script>

    head>

    <body>

    <style>

    /* All CSS is very simplified. I provide it for example and no more.

     * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

     */

    .content {

      display: table;

      width: 50%;

      min-width: 400px;

      height: 80%;

      /* Center horizontally and vertically */

      position: absolute;

      left: 0; right: 0;

      top: 0; bottom: 0;

      margin: auto;

      /* Design */

      border: 1px solid;

      background-color: silver;

      padding: 5px;

    }

    /* For mobile devices */

    @media (max-width: 400px) {

      .content {

        width: 100%;

        min-width: 0;

        padding: 0px;

      }

    }

    style>

    <div class="content">

    <div id="comments" style="overflow-y: scroll; height: 100%;">

    div>

    <form action="post.php" method="post" style="height: 0; display: table-row;">

      Nick:<br>

      <input type="text" name="nick" style="width: 100%;">input><br>

      <br>

      Text:<br>

      <textarea name="text" style="width: 100%;">textarea><br>

      <br>

      <input value="Submit" type="submit">input>

    form>

    div>

    <script type="text/javascript">

        var divComments = document.getElementById('comments');

        function loadComments() {

            var xhr = getXmlHttp();

            xhr.open('GET', '/getcomments.php', true);

            xhr.onreadystatechange = function () {

                if (xhr.readyState == 4) {

                    if (xhr.status == 200) {

                        if (xhr.responseText !== divComments.innerHTML) {

                            divComments.innerHTML = xhr.responseText;

                            divComments.scrollTop = divComments.scrollHeight;

                        }

                    }

                }

            };

            xhr.send(null);

        };

        loadComments();

        setInterval(loadComments, 1000)

    script>

    body>

    html>

    Теперь проблема исправить это. Новые комментарии с другого пользовательского чата (другие вкладки браузеров, окон и экземпляров) получают каждые 1000 миллисекунды (1 секунду) автоматически.

    Но отправка комментариев уже вызывает перезагрузку нашей страницы.

    Отправка комментариев без перезагрузки

    Как написано выше, XHR помогает отправлять HTTP GET-запросы без перезагрузки страницы и GUI заморозки (асинхронно).

    Теперь отправляем HTTP-запрос асинхронно, но на этот раз POST запрос, а не GET.

    И, естественно, XHR позволяет это. Используем метод send(). Для GET указываем null. Для POST устанавливаем запрос “body”.Также нужно добавить “Content-Type:application/x-www-from-urlencoded” в header  для того, чтобы разрешить серверу знать, какой формат использовать для отправки данных.

    Заметка: если не знаете, что отправлять, то можно захватить регулярный запрос с помощью “Fiddler” или же любой другой HTTP-перехватчик и только просимулировать запрос. HTTP-перехватчик — это незаменимый инструмент для работы с HTTP/HTTPS. Это позволяет увидеть все headers и bodies по всем HTTP(S)-запросам, что отправляются в систему. Лучше использовать “Fiddler”, это бесплатное, современное и очень простое приложение, что может поддерживать HTTP/HTTPS и оба Win x86/x64.

    1. Для начала создадим пустой JS скрипт в HTML. Разместить до самого

    тега, потому что этот скрипт будет использован для отправки формы комментария (форма будет вызывать этот скрипт при отправке).2. В этом скрипте, реализуем функцию, что будет отправлять ник и комментарии в “post.php”

     <script type="text/javascript">

    function postComment(nick, text) {

      var xhr = getXmlHttp();

      xhr.open('POST', '/post.php', true);

      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

      xhr.onreadystatechange = function() {

        if (xhr.readyState == 4) {

          if (xhr.status == 200) {

            /* it isn't required to add comment to DOM manually, it will done automatically on next refresh via AJAX */

          }

        }

      };

      xhr.send('nick=' + nick + '&text=' + text); /* joining the data in format simulates form */

    };

    script>

    3. Следующие, перезагружая страницу при отправке: 

    ... onsubmit="return false;">

    Также добавим вызов “postComment’s”:

    action="post.php" method="post" style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

    4. Наконец, необязательно, но можно убрать “action” и “method” с формы:

     <form style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

    5. Результат:

    <html>

    <head>

    <script type="text/javascript">

        function getXmlHttp() {

            var xmlhttp;

            try {

                xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

            } catch (e) {

                try {

                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

                } catch (E) {

                    xmlhttp = false;

                }

            }

            if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

                xmlhttp = new XMLHttpRequest();

            }

            return xmlhttp;

        };

    script>

    head>

    <body>

    <style>

    /* All CSS is very simplified. I provide it for example and no more.

     * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

     */

    .content {

      display: table;

      width: 50%;

      min-width: 400px;

      height: 80%;

      /* Center horizontally and vertically */

      position: absolute;

      left: 0; right: 0;

      top: 0; bottom: 0;

      margin: auto;

      /* Design */

      border: 1px solid;

      background-color: silver;

      padding: 5px;

    }

    /* For mobile devices */

    @media (max-width: 400px) {

      .content {

        width: 100%;

        min-width: 0;

        padding: 0px;

      }

    }

    style>

    <div class="content">

    <div id="comments" style="overflow-y: scroll; height: 100%;">

    div>

    <script type="text/javascript">

        function postComment(nick, text) {

            var xhr = getXmlHttp();

            xhr.open('POST', '/post.php', true);

            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

            xhr.onreadystatechange = function () {

                if (xhr.readyState == 4) {

                    if (xhr.status == 200) {

                        /* it isn't required to add comment to DOM manually, it will done automatically on next refresh via AJAX */

                    }

                }

            };

            xhr.send('nick=' + nick + '&text=' + text);

        };

    script>

    <form style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

      Nick:<br>

      <input type="text" name="nick" style="width: 100%;">input><br>

      <br>

      Text:<br>

      <textarea name="text" style="width: 100%;">textarea><br>

      <br>

      <input value="Submit" type="submit">input>

    form>

    div>

    <script type="text/javascript">

        var divComments = document.getElementById('comments');

        function loadComments() {

            var xhr = getXmlHttp();

            xhr.open('GET', '/getcomments.php', true);

            xhr.onreadystatechange = function () {

                if (xhr.readyState == 4) {

                    if (xhr.status == 200) {

                        if (xhr.responseText !== divComments.innerHTML) {

                            divComments.innerHTML = xhr.responseText;

                            divComments.scrollTop = divComments.scrollHeight;

                        }

                    }

                }

            };

            xhr.send(null);

        };

        loadComments();

        setInterval(loadComments, 1000)

    script>

    body>

    html>

     Теперь простая реализация AJAX подошла к концу. Это ещё не конец, это только начало. Есть ещё достаточно всего для изучения и улучшения.

    КОМЕНТАРІ ТА ОБГОВОРЕННЯ
    advertisement advertisement

    Купуй передплатуз доступом до всіх курсів та сервісів

    Бібліотека сучасних IT знань у зручному форматі

    Вибирай свій варіант підписки залежно від завдань, що стоять перед тобою. Але якщо потрібно пройти повне навчання з нуля до рівня фахівця, краще вибирати Базовий або Преміум. А для того, щоб вивчити 2-3 нові технології, або повторити знання, готуючись до співбесіди, підійде Пакет Стартовий.

    Стартовий
    • Усі відеокурси на 3 місяці
    • Тестування з 10 курсів
    • Перевірка 5 домашніх завдань
    • Консультація з тренером 30 хв
    59.99 $
    Придбати
    Весняний
    • Усі відеокурси на 15 місяців
    • Тестування з 24 курсів
    • Перевірка 20 домашніх завдань
    • Консультація з тренером 120 хв
    90.00 $
    219.99 $
    Придбати
    Акція
    Преміум
    • Усі відеокурси на 12 місяців
    • Тестування з 24 курсів
    • Перевірка 20 домашніх завдань
    • Консультація з тренером 120 хв
    169.99 $
    Придбати
    Notification success