Заметки веб-работника
11 августа 2006

Всплывающие подсказки в духе AJAX

Модный термин в заголовке статьи не должен вводить в заблуждение. Несмотря на свою современность, техника, подобная той, что рассматривается в предложенном здесь примере, скорее соответствуют духу «old school», так как известна уже достаточно давно. Сегодня, когда компьютеры стали мощнее, а браузеры – совершеннее, целый класс приемов, раннее известный как Remote Scripting, получил второе дыхание, а вместе с ним и новое имя – AJAX.

В целом, конечно, AJAX – не просто свежий взгляд на старые приемы, это и новый подход к созданию приложений, и новый подход к разработке интерфейсов, и принципиально иная функциональность. Понятно, воплощение подобных полноценных проектов – довольно трудоемкая задача. Но очевидно также и следующее, сегодня многие передовые идеи AJAX применимы не только для «навернутых» веб-аппликаций, им по силам вдохнуть жизнь и в «обычные» домашние страницы, сделать их более интерактивными. В качестве наглядного примера такого «оживления» можно предложить и заявленное в теме статьи простое, но, несомненно, полезное решение.

Итак, реализуем механизм подсказок, которые будут появляться при подведении мыши к неким элементам в окне браузера, причем необходимые для отображения данные должны подгружаться в фоновом режиме с сервера. Роль «неких элементов» отдадим, к примеру, гиперссылкам.

Сценарий может быть следующий: находим на странице все ссылки, у которых id соответствуют заданному шаблону (например, id="hintxxx", где xxx – число); для таких ссылок создаем обработчиков событий, чтобы при наведении мыши, при помощи объекта XMLHttpRequest, подгружалась требуемая подсказка. Для упрощения примера, оставим за кадром серверную часть – запрос будет осуществляться просто к определенному текстовому файлу на сервере. Вот необходимый скрипт:

var curHintId = null; // id активной ссылки

// Делаем XMLHttpRequest "универсальным"
if(!window.XMLHttpRequest && window.ActiveXObject)
   var XMLHttpRequest = function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

// Объект, для определения координат мыши
var mouse = {
   x : function(e)
   {
      if (window.event)
         return window.event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
      else if (window.captureEvents)
         return e.pageX;
      else
         return null; 
   },
   y : function(e)
   {
      if (window.event)
         return window.event.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
      else if (window.captureEvents)
         return e.pageY;
      else
         return null;   
   }
}

function hintsForLinks()
{
   if (window.XMLHttpRequest)
   {
      var hintbox = document.getElementById("hintbox");
      var allLinks = document.getElementsByTagName("a");
      
      // Выбираем только линки для которых есть подсказки (id = "hintxxx")
      var links = new Array();
      var e = 0;
      for(i = 0; i < allLinks.length; i++)
      {
         if (allLinks[i].id.match(/hint\d+/i))
         {
            links[e] = allLinks[i];
            e++;
         }
      }
      
      // Создаем обработчиков событий для ссылок с подсказками
      for(i = 0; i < links.length; i++)
      {
         links[i].onmouseover = function()
         {
            // Здесь может быть "полноценный" запрос
            getXMLDoc("f/" + this.id + ".txt");
            curHintId = this.id;
         }
         links[i].onmouseout = function()
         {
            hintbox.style.left = "-1000px"; // прячем hintbox
            hintbox.innerHTML = "";
         }
         links[i].onmousemove = function(e)
         {
            if (mouse.x(e) && hintbox.innerHTML != "")
            {
               var dx = (document.body.clientWidth - mouse.x(e) + document.body.scrollLeft < hintbox.offsetWidth) ? hintbox.offsetWidth + 15 : 0;
               var dy = (document.body.clientHeight - mouse.y(e) + document.body.scrollTop < hintbox.offsetHeight) ? hintbox.offsetHeight + 15 : 0;
               var x = mouse.x(e) + 10 - dx;
               var y = mouse.y(e) + 10 - dy;
               hintbox.style.left = (x - document.body.scrollLeft > 0) ? x : document.body.scrollLeft;
               hintbox.style.top = (y - document.body.scrollTop > 0) ? y : document.body.scrollTop;
            }
         }
      }
   }
}

function getXMLDoc(url)
{
   try
   {
      req = new XMLHttpRequest();
      if (req)
      {
         // Обработчик, в случае изменения состояние объекта req
         req.onreadystatechange = function () 
         {
            // req.readyState == 4 - отклик с сервера получен.
            if (req.readyState == 4)
            {
               // req.status == 200 - запрос успешно выполнен.
               if (req.status == 200)
               {
                  // Для нашего случая просто заполняем hintbox текстовым содержимым файла. 
                  var hintbox = document.getElementById("hintbox");
                  hintbox.innerHTML = req.responseText;
                  try
                  {
                     document.getElementById(curHintId).fireEvent("onmousemove");
                  }
                  catch(e)
                  {
                     hintbox.style.left = mouse.x(e) + 10;
                     hintbox.style.top = mouse.y(e) + 10;
                  }
               }
            }
         }
         req.open("GET", url, true);
         req.send("");
      }
   }
   catch(e) 
   {
      return;
   }
}

Функцию hintsForLinks() «вешаем» на событие onload страницы, на которой также не забываем, во-первых, разместить див с id="hintbox" (явно или с помощью JavaScript), во-вторых, описать для него нужные стили, к примеру, такие:

#hintbox{
   position:absolute;
   z-index:1;
   width:300px;
   left:-1000px;
   padding:0.7em 1em;
   font-size:80%;
   background:#cce;
   border:1px solid #99c;
   opacity:0.9;
   filter: progid:DXImageTransform.Microsoft.Alpha(Opacity = 90);
}

Благодаря кэшированию GET-запросов браузером, в случае очередной необходимости, подсказка появится без повторного обращения к серверу. В качестве рабочего примера выступает следующий абзац.

Пример АНТИ-ПСИХОЛОГИЗМ – парадигмальная установка, постулируемая модернизмом и в особенности постмодернизмом, которая заключается в программной элиминации субъективного фактора при интерпретации феноменов культуры. В отличие от классической философии, фундированной презумпцией объективности содержания адекватного знания о мире, философия 20 в. подвергает этот «психологизм» радикальному сомнению: трансцендентализм семантически сопрягает психологизм с когнитивным натурализмом, в силу чего теория познания, отвечающая требованиям антинатурализма, мыслится как базирующаяся на парадигме анти-психологизма.


Теги: JavaScript AJAX

Комментарии

1
UNV (Вт, 2 Сен 2008 22:21:16 +0300)
 

О! Я как раз недавно нечто подобное соорудил (правда, в более монументальном стиле - при наводе на ссылку с зажатым Ctrl подгружается большой динамический HTML-ник и отображается тултипом.

Но тут возникает другая проблема - как убрать стандартный тултип, задаваемый атрибутом title? Ещё нужно учесть, что в Опере на ссылке даже без установленного title в качестве всплывающей подсказки показывается адрес.

В моём случае ситуация осложняется тем, что пользователь мог зажать Ctrl уже после того, как навёл мышкой на ссылку и стандартная подсказка всплыла (т.е. просто обнулить title вряд ли поможет).

Есть идеи?

2
UNV (Вт, 2 Сен 2008 22:26:24 +0300)
 

Хотя если вместо link.title = null использовать link.removeAttribute("title"), ситуация улучшается - Опера и Огнелис сразу же скрывают стандартный тултип. Проблема остаётся только с IE (смотрю в шестёрке) - он уже отображаемый тултип скрывать не хочет.

3
Андрей Лысенко (Ср, 3 Сен 2008 13:45:28 +0300)
 

Да, к сожалению, есть такой момент для Оперы и предложенный вами вариант вполне решает проблему. Что касается ситуации с IE, то, что мешает отказаться от атрибута title?

4
UNV (Ср, 3 Сен 2008 23:26:31 +0300)
 

Совсем от title отказаться мешает то, что там тоже прописана полезная информация :) На ссылочку навешено немало функций.

Но если при наведении на ссылку с зажатым Ctrl удалять title, то проблем с IE почти не возникает. Единственно - если Ctrl был нажат уже после наведения на ссылку и тултип успел показаться, удаление title не скрывает тултип. Но с этим в принципе можно жить.

5
Never Lex (Сб, 24 Окт 2009 13:36:32 +0300)
 

Не нашёл более простого аналогичного скрипта. Респект.

Но. Без Доктайпа не работает. Можно это побороть?
И куда link.removeAttribute("title") пихать?

Спасибо заранее.

6
Never Lex (Сб, 24 Окт 2009 14:01:46 +0300)
 

Точнее с Доктайпом не работает. Ошибся. Это реальная проблема.

7
a1k (Пт, 30 Апр 2010 9:56:24 +0300)
 

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

8
Андрей Лысенко (Пт, 30 Апр 2010 14:11:34 +0300)
 

Конкретно по этому скрипту - для каждой подсказки создается свой текстовый файл, название которого совпадает с id ссылки (+ расширение .txt)

9
Sam (Пн, 6 Дек 2010 22:28:10 +0200)
 

Способ заинтересовал, но.. увы.. я не профи и ничего не получается, совсем.

_______

Вы можете оставить свой отзыв по данной статье:

  Имя
  E-mail (не публикуется)
  Веб-сайт

Комментарий (Теги форматирования не поддерживаются)