9

Реализация поиска по сайту на основе Google AJAX Search API и jQuery

Дмитрий Кораблинов
21 октября 2009 года

Поиск по сайту — функция, безусловно, очень важная, особенно для больших ресурсов, на которых найти нужную информацию бывает не так просто. Многие современные CMS содержат готовые компоненты для построения системы поиска. Но даже если такого компонента нет под рукой, не надо отчаиваться — крупные поисковые сервисы (в частности, Google) предоставляют API на базе JavaScript и AJAX, которые можно легко подключить к любому сайту.

Описание API поиска от Google можно найти здесь. На первый взгляд все выглядит предельно просто: нужно разместить на странице скрипт из 5-10 строк кода, и ура — вы получаете готовую мощную систему поиска по сайту. Но на мой взгляд, тут есть существенные недостатки — способ, рекомендуемый Google (использование объекта google.search.searchControl), формирует несемантичную и явно избыточную HTML-разметку, которая к тому же «обвешана» дополнительнымы CSS-правилами, которые подойдут не каждому сайту.

Поэтому я хочу описать способ реализации поиска по сайту с использованием этого же API, но на более низком уровне, что позволяет формировать любую HTML-разметку и украшать ее собственными стилями. Для удобства работы с DOM я также буду использовать фреймворк jQuery. Сразу оговорюсь, что я не буду подробно расписывать назначение и возможности используемых объектов из API, об этом можно прочесть в документации. Я только покажу один, достаточно универсальный, вариант использования этих объектов в контексте произвольного сайта. Безусловно, приведенный ниже код — это не вселенская истина, а только лишь основа для реализации собственного решения.

Итак, начнем по порядку.

Шаг 0. Изучение предмета

Перед использованием Google AJAX Search API обязательно нужно изучить документацию и
условия предоставления услуги.
Это важно, так как не на всех web-ресурсах можно использовать свободно распространяемые технологии, в том числе и данный API.

Шаг 1. Создание страницы поиска

<form class="search-form">
    <input type="text" value="" />
    <input type="submit" value="Найти" />
</form>
<div class="google-logo">
    Технология <a href="http://google.ru"><img src="http://www.google.com/uds/css/small-logo.png" alt="Google" /></a>
</div>
<div class="search-loading">Поиск...</div>                
<div class="search-result">
    <h2>Результаты поиска: &laquo;<span class="query"></span>&raquo;</h2>
    <ol class="results"></ol>
    <div class="paging">        
        Другие страницы:
        <ul></ul>
    </div>
</div>        
<div class="search-fail">К сожалению, по вашему запросу ничего не найдено.</div>

* This source code was highlighted with Source Code Highlighter.

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

  1. Стандартная форма поиска form.search-form с двумя элементами управления — текстовым полем и кнопкой.
  2. Блок div.google-logo с логотипом Google (логотип обязательно должен присутствовать на странице). Здесь нужно обратить внимание, что логотип предоставляется в формате .png, так что нужно не забыть пустить в ход какой-нибудь PNGfix.
  3. Блок div.search-loading, который отображается в процессе выполнения поиска. Здесь можно использовать всякие «аяксовые» картинки.
  4. Блок div.search-result для вывода результатов поиска. Он содержит в себе заголовок и контейнеры для вывода результатов и пэйджинга.
  5. Блок div.search-fail отображается, если поиск не вернул результатов.

Шаг 2. Подключение API

Подключение любых API от Google производится с помощью специального загрузчика API. Поэтому первым делом в секции <head> страницы подключаем скрипт загрузчика:

<script src="http://www.google.com/jsapi" type="text/javascript"></script>

* This source code was highlighted with Source Code Highlighter.

Заодно подключаем фреймворк jQuery (для получения jQuery я использую службы Google CDN):

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>    

* This source code was highlighted with Source Code Highlighter.

Дальше я буду создавать небольшую JavaScript-библиотеку поиска, поэтому подключаю также ее файл:

<script src="/js/google-search.js" type="text/javascript"></script>    

* This source code was highlighted with Source Code Highlighter.

Теперь начинаем писать код этой библиотеки. Первая задача — выполнить начальную инициализацию переменных и загрузить собственно API поиска.

// Создать переменную для объекта поиска
var webSearch;    

// Задать имя сайта
var siteName = 'www.site.test';

// Подключить Google AJAX Search API
google.load('search', '1', {'nooldnames': true, 'language': 'ru-RU', 'nocss': true});

// Зарегистрировать обработчик события полной загрузки страницы с библиотеками Google API
google.setOnLoadCallback(onPageLoad);

* This source code was highlighted with Source Code Highlighter.

Здесь есть два важных момента. Во-первых, вызов загрузчика выполняется с дополнительными параметрами — это позволяет избежать загрузки ненужных фрагментов JavaScript и CSS, соответственно, немного увеличивается производительность.
Во-вторых, любые действия с API поиска можно производить только после полной загрузки API и страницы, поэтому нужно зарегистрировать обработчик соответствующего события.

Шаг 3. Реализация обработчиков событий

Всего обработчиков событий у нас будет три — на события загрузки страницы, начало поиска и завершение поиска.

Обработчик события полной загрузки страницы с библиотеками Google API

function onPageLoad() {
    // Создать объект web-поиска
    webSearch = new google.search.WebSearch();
    
    // Ограничить область поиска заданным сайтом
    webSearch.setSiteRestriction(siteName);
    
    // Задать расширенный размер результатов
    webSearch.setResultSetSize(google.search.Search.LARGE_RESULTSET);                    
    
    // Запретить автоматическую генерацию HTML-кода для результатов
    webSearch.setNoHtmlGeneration();
    
    // Зарегистрировать обработчик события завершения поиска
    webSearch.setSearchCompleteCallback(this, onWebSearchComplete);            
    
    // Зарегистрировать обработчик события нажатия на кнопку поиска и выполнить его
    $('.search-form :submit, .search-form :image')
        .click(function() {
            if ($('.search-form :text').val() != '') {
                onWebSearchStarting();
                webSearch.execute($('.search-form :text').val());
            }
            return false;
        })
        .click();
}

* This source code was highlighted with Source Code Highlighter.

Здесь все довольно просто — нужно создать объект поиска, настроить его подходящим образом и зарегистрировать обработчик кнопки в форме поиска. К сожалению, API не дает возможности привязать к объекту поиска обработчик события начала поиска — его приходится вызывать вручную.
Кроме того, на некоторых сайтах форма поиска создается на каждой странице и после нажатия кнопки выполняет перенаправление на страницу поиска. Поэтому я имитирую нажатие на кнопку поиска сразу после загрузки страницы. Если текстовое поле формы поиска будет при этом пустым, никаких действий выполняться не будет.

Обработчик события начала поиска

function onWebSearchStarting() {
    // Очистить контейнеры результатов и пэйджинга
    $('.search-result .results').empty();
    $('.search-result .paging ul').empty();
    
    // Скрыть блоки результатов запроса
    $('.search-result').hide();
    $('.search-fail').hide();
    
    // Отобразить блок с информацией о процессе поиска
    $('.search-loading').show();                
}

* This source code was highlighted with Source Code Highlighter.

Эта функция просто перестраивает содержимое страницы на время выполнения поиска.

Обработчик события завершения поиска

function onWebSearchComplete() {    
    // Скрыть блок с информацией о процессе поиска
    $('.search-loading').hide();        
        
    if (webSearch.results.length > 0) {    // Если поиск вернул результаты, отобразить их
        // Поместить текст запроса в соответствующий элемент
        $('.search-result .query').text($('.search-form :text').val());
        
        // Отобразить результаты поиска в заданном контейнере
        showSearchResults($('.search-result .results'));        
                
        // Если поиск вернул больше одной страницы, вывести элементы пэйджинга в заданный контейнер,
        // иначе не отображать пэйджинг
        if (webSearch.cursor.pages.length > 1) {
            showSearchPaging($('.search-result .paging ul'))            
            $('.search-result .paging').show();
        }
        else {
            $('.search-result .paging').hide();        
        }
        
        // Отобразить блок с результатами
        $('.search-result').show();
    }
    else { // Если поиск не вернул результатов, отобразить соответствующее сообщение
        $('.search-fail').show();
    }
}

* This source code was highlighted with Source Code Highlighter.

После завершения поиска выполняется проверка реузьтатов и модификация разметки. Думаю, из комментариев в коде все должно быть понятно.

Шаг 4. Реализация функций обработки результатов

После завершения поиска результаты доступны в свойствах объекта поиска results и cursor в виде JSON-объектов. Соответственно, вывод результатов на страницу — это уже дело техники.

Сначала пробегаем свойство results и формируем разметку результатов поиска:

function showSearchResults(resultsContainer) {
    // Установить начальное значение нумерации элементов
    resultsContainer.attr('start', Number(webSearch.cursor.pages[webSearch.cursor.currentPageIndex].start) + 1);        
    
    // Сгенерировать HTML-разметку для каждого результата и добавить ее в контейнер
    $.each(webSearch.results, function(i, resItem) {            
        $('<li/>')
            .append( $('<a/>').html(resItem.titleNoFormatting).attr('href', resItem.unescapedUrl) )
            .append( $('<p/>').html(resItem.content) )
            .appendTo(resultsContainer);
    });
}

* This source code was highlighted with Source Code Highlighter.

Затем формируем разметку пэйджинга, используя свойство cursor:

function showSearchPaging(pagingContainer) {
    // Если текущая страница - не первая, создать и добавить в контейнер кнопку "Назад"
    if (webSearch.cursor.currentPageIndex > 0) {
        $('<li>')
            .append ( $('<a/>').attr('href', '#').text('Назад').data('pageNumber', webSearch.cursor.currentPageIndex - 1) )
            .appendTo(pagingContainer);
    }            

    // Сгенерировать HTML-разметку для каждого элемента пэйджинга и добавить ее в контейнер
    $.each(webSearch.cursor.pages, function(pageIndex, pageItem) {            
        (webSearch.cursor.currentPageIndex == pageIndex
            ? $('<li/>').text(pageItem.label)
            : $('<li/>').append( $('<a/>').attr('href', '#').text(pageItem.label).data('pageNumber', pageIndex) )
        ).appendTo(pagingContainer);
    });

    // Если текущая страница - не последняя, создать и добавить в контейнер кнопку "Вперед"
    if (webSearch.cursor.currentPageIndex < webSearch.cursor.pages.length - 1) {
        $('<li/>')
            .append ( $('<a/>').attr('href', '#').text('Вперед').data('pageNumber', webSearch.cursor.currentPageIndex + 1) )
            .appendTo(pagingContainer);
    }
    
    // Зарегистрировать обработчик нажатия для всех ссылок в контейнере
    pagingContainer.find('a').click(function() {
        var pageNum = $(this).data('pageNumber');
        onWebSearchStarting();
        webSearch.gotoPage(pageNum);
        return false;
    });
}

* This source code was highlighted with Source Code Highlighter.

Опять же, логика описана в комментариях. Единственный тонкий момент — в обработчике события Click ссылок в пэйджинге индекс кликнутой ссылки в массиве cursor.pages неизвестен, поэтому я использую функцию jQuery data() для привязки этого индекса к jQuery-оболочке ссылки.

Шаг 5. Enjoy!

Остается только определить правила CSS для элементов страницы поиска, подходящие для конкретного сайта.

Рабочий пример такой организации поиска можно посмотреть на нашем сайте.

Метки: , ,

9 комментариев к записи «Реализация поиска по сайту на основе Google AJAX Search API и jQuery»

  1. sus@nin,

    Так вот, у вас эта херня (http://www.htc-cs.ru/search.htm) ))) не работает по нажатию на Ентер, только при клике на кнопку (ИЕх).
    Во вторых, сайт к сожалению не сильно быстро индексируется — это понятно, но для других вполне. По сравнению с тупо_Я, в плане индексации, гугл конечно же лучше.

  2. Артем,

    Здравствуйте ,Можно ли где-то найти готовый код для стартовой страницы чата на движке август ?я просто новичёк в этом деле а страницу хочется ,что бы чат лан порадовать

  3. todd,

    спасибо

  4. Logioniz,

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

  5. dok,

    Logioniz,

    Ссылка на официальную документацию Google приведена в начале поста. Естественно, документация описывает только интерфейсы API и способы работы с ними. Принцип построения страницы поиска, обращения к API и обработки DOM — разработка автора статьи ))

  6. Logioniz,

    Ога, сорри, первый раз увидел, как до элементов добираются через ${‘.class ‘}, а не что-то вроде такого "document.getElementById(id)". Подумал api предоставляет такой интерфейс доступа к элементам :) O_o

  7. dok,

    Logioniz,

    "Вы все еще используете getElementById? Тогда мы идем к вам!")))
    А если серьезно, то изучайте и используйте jQuery в своих проектах. Очень полезный и удобный фреймворк, избавляет от большого количества рутинного кода.

  8. Alex Osster,

    Отличная статья!
    К сожалению наткнулся на её слишком поздно…уже сам разобрался)) Есть ещё вариант на прямую обращаться к сервису AJAX запросом. А вот JQuery не всегда удобно использовать, ИМХО штука хорошая, но и основы знать полезно ;).

  9. Rusifikator312,

    То что я искал… Спасибо Автору!

Ответить на сообщение sus@nin