В первой части урока мы рассмотрели организацию поиска по базе данных MySQL средствами AJAX, PHP и XML. Теперь я хочу показать этот же пример, только с использованием библиотеки prototype. Глобальных изменений не произошло, внешне работает абсолютно одинаково. В конце урока попытаемся подвести небольшую сравнительную характеристику двух этих методов.

Пример: http://logicerror.pp.ru/upload/ajax_search_prototype/

Сравните внешне с предыдущим примером:
http://logicerror.pp.ru/upload/ajax_search_xml/

Элементы всё те же:

  1. база данных MySQL
  2. внешний вид - index.html
  3. ajax скрипт - script.js
  4. php двигатель - search.php
  5. ну и собственно prototype.js

Скачать последнюю версию библиотеки prototype можно здесь: http://www.prototypejs.org/ (оф. сайт библиотеки)

Все файлы лежат у нас в одном каталоге. Кому удобнее, может распределить их по различным каталогам на своё усмотрение (js, css, include, …), только не забудьте сделать соответствующие изменения в коде. Итак, начнем!

MySQL database

База данных у нас осталась без изменений, причем лично я ее и не дублировал, то есть вы можете подключиться к той же базе, что и в предыдущем уроке. Тем кто опоздал дублирую структуру.

CREATE TABLE `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) collate utf8_unicode_ci NOT NULL,
  `content` text collate utf8_unicode_ci NOT NULL,
  `author` varchar(255) collate utf8_unicode_ci NOT NULL,
  `timestamp` int(11) NOT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

Ну и, конечно же, моя любимая ссылочка на мусор в базу данных ;) http://logicerror.pp.ru/upload/ajax_search_xml/junk.sql

HTML revised

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Language" content="ru">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>AJAX PHP search example - Prototype</title>
 
<link rel="stylesheet" href="style.css" type="text/css">
<script src="script.js" type="text/javascript"></script>
<script src="prototype.js" type="text/javascript"></script>
 
</head>
<body>
<div id="wrap">
<form onsubmit="search(); return false;">
<input type="text" class="input" id="search_input" value=""> <input type="submit" class="button" id="search_button" value="&raquo; поиск">
</form><br>
 
<div id="search_results">
</div>
 
<div id="searching" style="display: none">
	searching
</div>
 
</div>
</body>
</html>

Здесь мы добавили одну строчку, для подключения библиотеки prototype (естественно при условии того, что файл лежит в том же каталоге, что и index.html):

<script src="prototype.js" type="text/javascript"></script>

Стиль поля searching изменился, пришлось вынести этот атрибут (display: none) из каскадных таблиц, а почему я объясню чуть ниже:

<div id="searching" style="display: none">

Ну и заголовок странички малость изменили ;)

AJAX “prototyping”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function search() {
  var sSearch = $F("search_input");
 
  if (sSearch.length < 3)
  {
    alert("Запрос должен быть не короче 3-х символов.");
    return false;
  }
 
  $('search_results').hide();
  $('searching').show();
 
  new Ajax.Updater('search_results', 'search.php',
    { method: 'get',
      parameters: { search: sSearch },
      onComplete: function () {
        $('search_results').show();
        $('searching').hide();
      }
    }
  );
}

Коротко, правда? Разбираем.

1
2
3
4
5
6
7
var sSearch = $F("search_input");
 
if (sSearch.length < 3)
{
  alert("Запрос должен быть не короче 3-х символов.");
  return false;
}

Здесь осталось всё как есть, кроме обращения к текстовому полю с идентификатором search_input. В предыдущем уроке мы использовали родной document.getElementById().value, что в принципе и повторяет оператор $F в библиотеки prototype. Очень удобно и чисто.

$('search_results').hide();
$('searching').show();

В предыдущем уроке, поле search_results (результаты поиска) мы очищали через свойство .innerHTML. Здесь нам достаточно его спрятать (метод hide()), так как Ajax.Updater() у нас сам очистит это поле в нужный момент.

Ну и показываем поле searching методом .show(). Остановимся здесь на миг. Выше я говорил про атрибут display: none, который пришлось перенести в html из css. Дело в том, что, если этот атрибут хранится в css, то показать блок методом .show() мы не сможем (наверное это особенность prototype ;) ) - пришлось бы использовать .style.display = “block”, но так гораздо удобнее, согласитесь…

Далее следует AJAX запрос на обновление (Updater)

1
2
3
4
5
6
7
8
9
new Ajax.Updater('search_results', 'search.php',
  { method: 'get',
    parameters: { search: sSearch },
    onComplete: function () {
      $('search_results').show();
      $('searching').hide();
    }
  }
);

Уже знакомый нам запрос, ничего сложного. Обновлять будем поле search_results (результаты поиска). Запрашивать будем search.php - наш двигатель. Используем метод GET, передавая переменную sSearch (наш поисковой запрос) в качестве параметра search (получается что-то вроде search.php?search=…).

Ну и прикручиваем обработчик события Complete (готово) - функцию, которая будет прятать строку “ищу” (searching) и показывать поле результатов поиска (search_results). Причем, здесь нам и не нужно ничего добавлять в поле результатов, так как, получив результат, данный вид запроса самостоятельно поместит его в поле search_results. Это особенность запроса на обновление - Ajax.Updater.

PHP двигатель

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
  $db = mysql_connect("localhost", "root", "");
  mysql_select_db("ajax_search");
  mysql_query("SET CHARACTER SET utf8");
 
  header('Content-type: application/xml; charset=utf-8');
  header('Cache-Control: no-cache');
 
  $sString = mysql_real_escape_string($_GET["search"], $db);
  $sql="SELECT * FROM `articles` WHERE `title` LIKE '%$sString%' OR `content` LIKE '%$sString%' ORDER BY `id` DESC LIMIT 10";
  $rs=mysql_query($sql,$db);
 
  if (mysql_num_rows($rs) > 0)
  {
    while ($row = mysql_fetch_array($rs))
    {
      $content=htmlspecialchars(strip_tags($row["content"]));
      if (mb_strlen($content, "utf-8") > 250) $content = mb_substr($content, 0, 250, "utf-8") . "...";
?>
<div class="result">
	<h1><?=htmlspecialchars($row["title"]);?></h1>
	<?=$content;?>
</div>
<?
	}
  }
  else
  {
?>
<div class="result">
	<h1> </h1>
	Ничего не найдено
</div>
<?
  }
?>

В php у нас тоже мало чего изменилось, а именно представление данных. В предыдущем уроке мы использовали XML, а здесь мы используем уже готовый для вывода HTML. Надеюсь вопросов не возникнет. (Не забудьте вместе с XML убрать и его заголовки).

Кстати Content-type советую оставить application/xml, т.к. некоторые браузеры до сих пор не любят ajax запросы к иным форматам.

Вот и всё. Ниже подведена сравнительная характеристика двух методов.

XML vs. Prototype

XML

  • Общий размер: 16 кб
  • Строк кода: 181
  • Время написания: ~2ч.

Prototype

  • Общий размер: 144 кб
  • Строк кода: 141
  • Время написания: ~1ч.

Если кто-нибудь еще и скорость выполнения проверит - дайте знать.

Размер указан без учета каких-либо методов сжатия.

Отсюда следует вывод. Написание самой такой системы, конечно же легче с использованием prototype, тем самым вы избавляете себя от лишнего парсинга. Тем не менее, потратив чуть больше времени, можно уменьшить объем конечного результата в 9 раз, ну естественно если вы не использовали prototype в другом месте на своей странице (наверное нужно все эти библиотеки уже начать интегрировать в браузеры, и чтобы само-обновлялись).

Ну и конечно же, это еще и дело вкуса ;)

Полезные ссылки

Google Bookmarks Digg Reddit del.icio.us Ma.gnolia Technorati Slashdot Yahoo My Web News2.ru БобрДобр.ru RUmarkz Ваау! Memori.ru rucity.com МоёМесто.ru Mister Wong