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

поиск по сайту gametelegraph.comВ начале у меня на сайте был поиск с помощью самих пользователей (они могли походить по ссылкам и найти что-нибудь нужное :) ), назовем это первой версией поиска по моему сайту.

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

Но желание предложить пользователям современные удобства не давало покоя, и вот сегодня я таки запустил живой поиск по сайту с играми :). Это будем считать поиск 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>

Просто!

А поскольку это флэш, то еще и круто! :)

Пожалуйста, посмотрите, что в итоге получилось, может быть, обнаружатся проблемы с отображением, или просто какие-то косяки, пожалуйста, напишите про них в комментариях.

Комментарии (28)

0
Очень живо и красиво!
0
Спасибо! Жду следующую Q, не критики ради, а удовольствия для! :)
0
DiscoFish, специально для тебя и любителей игры Q — теперь поиск пропускает однобуквенный запрос 'Q'. :)
0
Благодарю много раз! :)
+4
а правая кнопка для новой вкладки, а?
0
Это даже на конге работает через задницу :)
+2
Сделал прямоработающее меню по правой кнопке. :)
0
А [SHIFT/CTRL]+ENTER? :)
Хотя правая кнопка, да, нада!
0
Не знаю на счёт правой кнопки, знаю, в новой вкладке открывается по нажатию колёсиком.
так на него можно повесить лисенер и открывать в новой.
0
быдло ЦА открывает правой кнопкой
+1
и я еще
0
ну значит нет експириенса продолжительного интенсивного интернет серфинга, раз не качнул скилы быстрого управления браузером)
этим почти можно гордиться :)
0
Очень красиво и вроде безглючно.
0
Выглядит просто супер!
Только, на мой взгляд, стоит ускорить анимация появления списка игр раза в 2. И еще бросается в глаза выделение оранжевым цветом из-за того что через время появляется и резко как-то. Лучше бы было, чтобы выделение появлялось сразу со списком или появлялось постепенно, а не резко, например из прозрачного становилось непрозрачным или что-то типа того.
0
Симпатичная реализация.
+1
выглядит классно. в последней опере полет нормальный.

еще бы открытие фоновой вкладки в меню по правому клику и было бы вообще хорошо)

еще мне кажется лучше заменить текст «Run full-text search for me!» на что-то типа обычного "...more", отцентрованного по центру или по правому краю.
0
Иногда возникает ситуация, когда поиск по названию не дает результата вообще или дает 1-2 результата вместо четырех ранее показанных, в этом случае «more» мне кажется странным. Т.е. если бы все слоты были бы заняты, и были бы еще результаты, тогда да, но по сути это другой поиск и там другие результаты, поэтому мне кажется разумным его так обособить.
0
Спасибо за отзывы, действительно про правую кнопку забыл. Сейчас добавил туда две стандартные функции + копирование ссылки в буфер вместо открытия.

Заодно добавил исключение для однобуквенного поиска — теперь можно без проблем искать Q. :)
0
Открывать в новой вкладке можно и с помощью JS (внешняя функция). Но я считаю, что лучше поменьше флеше на странице держать.

А почему используется XML а не JSON?
0
Клевый поиск, только «Открыть в новой вкладке» надо наверно написать по английски?.. или учитывается язык системы?
0
Конечно учитывается :)
0
Флэш может открыть ссылку в новом окне, но современные броузеры интерпретируют это как в новой вкладке, т.ч. я открываю вкладку с помощью самого флэша.

насчет XML/JSON — каких-то особенных причин тому нет, просто XML, может быть поменяю потом, если будет необходимость.
0
Да необходимости особой нет, просто трафика меньше JSON кушает, ну и мне привычно в ответах сервера видеть именно JSON :).
0
Ну в данном случае трафиком можно смело пренебречь. :) К тому же gzip.
+1
пользуясь случаем хочу сказать, что у вас один из самых красивых флеш порталов! :)

А по теме — согласен с Евгением, т.к. с точки зрения юзабилити «full-text search» для обычного пользователя что-то совсем загадочное
  • qdrj
  • qdrj
0
повезло, наверное :)

насчет full-text обещаю подумать еще пару раз. :)
0
прикольно!
только заметил, что поиск выдает разный результат на главной странице (или в категории) и на странице с какой-нить игрой. например по запросу «red».
0
На странице с игрой выдача ограничена 2-мя результатами, а так набор игр одинаковый. Дело в том, что там разворачивается игра, и третий пункт, если бы он был, залез бы под флэш игры.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.