
Живой поиск по играм

Затем я добавил строку поиска, которая отправляла посетителя на страницу с результатами полнотекстового поиска по названию и описанию игр, это примем за вторую версию.
Но желание предложить пользователям современные удобства не давало покоя, и вот сегодня я таки запустил живой поиск по сайту с играми :). Это будем считать поиск 3.0, потому, что он не просто живой, он еще и на флэше!
Ниже я расскажу основные моменты разработки, если вы захотите добавить такой гэджет на свой портал.
Такой поиск состоит из трех частей — клиент, сервер и верстка. Подробнее о каждой из них:
Сервер
В качестве сервера выступает простой скрипт, и если опустить проверки на корректность входных данных и форматирования результата, его задача сводится к возвращению списка игр, полученного по вот такому SQL запросу к базе данных:"SELECT * FROM games WHERE name LIKE '%$q%' AND published=1 ORDER BY name='$q' desc, name like '$q%' desc LIMIT 0, $limit";
В моем случае возвращается вот такой XML:
<?xml version="1.0" encoding="UTF-8" ?>
<DATA>
<STATUS cmd="search.game" code="0" repeat="false"/>
<CONTENT>
<SEARCH q="sub">
<GAME name="Submarine vs Aliens" img="*.jpg" link="*/Submarine-vs-Aliens" categories="Actions, Shooters, GT Production" order="0"/>
<GAME name="Haunted Suburb" img="*.png" link="*/Haunted-Suburb" categories="defence game" order="1"/>
<GAME name="Test Subject Blue" img="*.png" link="*/Test-Subject-Blue" categories="Platformers, Arcades" order="2"/>
</SEARCH>
</CONTENT>
<DEBUG workTime="0.0070781707763672"/>
</DATA>
Длинные урлы для этого сообщения я сократил с помощью *, в оригинале, конечно, идет полная ссылка на изображение и игру.
Как видно по дебагу, запрос выполняется очень быстро. Для справки — в таблице games сейчас немногим меньше тысячи записей.
Клиент
Помимо основной логики (слежение за вводом пользователя, обмен данными с сервером), клиент делает две хитрые вещи:- кэширует запросы
- следит за своим размером (высотой)
Слежение за размером необходимо для связи клиента с версткой, т.к. флэш не «прозрачен» для мыши и растягивать его область поверх документа следует только когда это необходимо для показа результатов, и сворачивать во всех остальных случаях. Непосредственно изменение размера реализуется в верстке с помощью JS, который клиент вызывает при изменении размера:
ExternalInterface.call("divHeight", divId, h.toString());
divHeight — имя JS метода в html странице с клиентом
divId — id дива, в который вставлен клиент
h — нужный размер (высота) для отображения клиента.
Вначале я думал сделать хитрый алгоритм для оптимизации количества ресайзов занимаемой области (растягивать сразу больше чем надо фактически, сокращать раз в секунду), но попробовав самый простой вариант — обновление при любом изменении h, остановился на нем. Кажется, он работает без проблем и не создает тормозов.
Кстати, я не стал вводить паузу между вводом пользователя и отправкой запроса серверу, все изменения тут же отправляются. В общем, думаю, это нормально, хотя возможен приход ответов вразнобой при быстром наборе и медленном канале. Для отбрасывания устаревших ответов может использоваться нода <SEARCH q=«sub»> — если q не совпадает с последним запросом, результат стоит проигнорировать.
Верстка
Верстка простая. Клиент вставляется в два дива:<div id='search' style="position:relative; width:221px; height:20px; z-index:101;">
<div id="searchTopDiv" style="position:absolute; width:221px; height:20px;">
<script language='JavaScript' type='text/javascript'>
AC_FL_RunContent(
'width', '100%',
'height', '100%',
'wmode', 'transparent',
'allowScriptAccess','sameDomain',
'FlashVars', 'maxRecords=2&divId=searchTopDiv'
);
</script>
</div>
</div>
Из AC_FL_RunContent для этого сообщения я удалил все, что имеет значение по дефолту, и оставил только то, на что нужно обратить внимание, но об этом чуть ниже, а пока про слои.
Первый слой (id=«search») помещается на страницу и занимает там некоторую область точно так же, как и обычная картинка. Он нужен для того, что бы определить минимальные габариты строки поиска, в моем случае это 221 x 20. Этот слой позиционируется как обычно — где вставили, там и окажется.
Второй слой (id=«searchTopDiv») немного другой, он выпадает из общей схемы позиционирования из-за стиля «position:absolute» и броузер не учитывает его размер при расположении соседних элементов — ему можно задать размер 500х500 но ни один элемент на странице не сдвинется. Именно этот слой и будет растягивать и сжимать поисковый клиент.
Клиент создается с размером в 100% от контейнера — это позволит им легко манипулировать.
Хотя это и не обязательно, но дизайн моего клиента потребовал встроить его с прозрачным фоном, поэтому wmode — transparent. Для такого клиента потеря производительности не должна быть критичной.
Так же ему передается два параметра через FlashVars — maxRecords и divId, первый ограничивает максимальное количество выдаваемых результатов, а второй передает программе идентификатор дива, который отвечает за размер (у меня на главной поиск в двух местах, и в нижнем влезает только 2 результата, поэтому это нужно).
Остался последний элемент мозаики — JS метод divHeight. Вот и он:
<script language='JavaScript' type='text/javascript'>
function divHeight (id, h){
var div = document.getElementById(id);
div.style.height = h + 'px';
}
</script>
Просто!
А поскольку это флэш, то еще и круто! :)
Пожалуйста, посмотрите, что в итоге получилось, может быть, обнаружатся проблемы с отображением, или просто какие-то косяки, пожалуйста, напишите про них в комментариях.
- +10
- GameTelegraph
Комментарии (28)
Хотя правая кнопка, да, нада!
так на него можно повесить лисенер и открывать в новой.
быдлоЦА открывает правой кнопкойэтим почти можно гордиться :)
Только, на мой взгляд, стоит ускорить анимация появления списка игр раза в 2. И еще бросается в глаза выделение оранжевым цветом из-за того что через время появляется и резко как-то. Лучше бы было, чтобы выделение появлялось сразу со списком или появлялось постепенно, а не резко, например из прозрачного становилось непрозрачным или что-то типа того.
еще бы открытие фоновой вкладки в меню по правому клику и было бы вообще хорошо)
еще мне кажется лучше заменить текст «Run full-text search for me!» на что-то типа обычного "...more", отцентрованного по центру или по правому краю.
Заодно добавил исключение для однобуквенного поиска — теперь можно без проблем искать Q. :)
А почему используется XML а не JSON?
насчет XML/JSON — каких-то особенных причин тому нет, просто XML, может быть поменяю потом, если будет необходимость.
А по теме — согласен с Евгением, т.к. с точки зрения юзабилити «full-text search» для обычного пользователя что-то совсем загадочное
насчет full-text обещаю подумать еще пару раз. :)
только заметил, что поиск выдает разный результат на главной странице (или в категории) и на странице с какой-нить игрой. например по запросу «red».