Текст ниже — перевод статьи "Unobtrusive Javascript", чей автор Christian Heilmann любезно дал мне согласие на перевод. Оригинальный адрес статьи www.onlinetools.org/articles/unobtrusivejavascript/chapter2.html
Для неопытных Javascript-разработчиков HTML — это площадка для игр.
HTML: <a href="index.html" onmouseover="image1.src='1on.gif'" onmouseout="image1.src='1off.gif'"> <img src="1off.gif" name="image1" border="0" height="150" width="150" alt="home"></a>
или если они чуть более продвинутые:
HTML:
<a href="index.html"
onmouseover="roll('home',1)"
onmouseout="roll('home',0)">
<img src="home.gif" name="home" border="0"
height="150" width="150"
alt="home"></a>
Javascript:
// предзагрузка изображений
homeoff = new Image();
homeoff.src = 'home.gif';
homeon = new Image();
homeon.src = 'homeoff.gif';
function roll(imgName,a)
{
imgState=a==0?eval(imgName + 'on.src'):eval(imgName + 'off.src');
document.images[imgName].src = imgState;
}В любом случае все вызовы событий находятся в HTML, и если имя функции поменяется, нам нужно будет внести изменения в каждом документе. Кроме того, каждый ролловер будет означать большее количество разметки, которая добавиться к общему весу страницы.
Давайте забудем на мгновение, что почти каждый эффект ролловера в наши дни скорее достигается с помощью CSS, чем с помощью Javascript, и допустим, что мы хотим использовать нижеследующую разметку и создать ролловер для изображения.
HTML: <a href="index.html"><img src="home.gif" id="home" alt="home"></a>
Итак, как сменить изображение, когда на него наводиться курсор мыши?
Каждый XML- (а также и HTML-) документ — это дерево узлов. Узел — часть этого дерева (представляйте файл или папку в проводнике Windows, когда вы просматриваете ваш диск). Узел может быть двенадцатью разными вещами, в HTML только три из них действительно интересны: element, TextNode и AttributeNode.
Давайте посмотрим, какие функции и атрибуты мы можем использовать, чтобы перемещаться по дереву узлов документа, и как перепрыгивать от одного элемента до другого.
getElementById('elementID')elementID в виде объекта.getElementsByTagName('tag')tag в виде массива.Разумеется, мы можем смешивать и сочетать эти два варианта. Несколько примеров:
document.getElementById('navigation').getElementsByTagName('a')[3];
// возвращает четвёртую ссылку внутри элемента,
// который имеет ID 'navigation'
document.getElementsByTagName('div')[2].getElementsByTagName('p')[0];
// возвращает первый параграф внутри третьего div в документе.childNodesfirstChild и lastChild, это сокращенные варианты childNodes[0] и childNodes[this.childNodes.length-1].parentNodenextSiblingpreviousSiblingВсе это по желанию может быть смешано так, как нам нужно.
Javascript:
var other=document.getElementById('nav').childNodes[3].firstChild;
// возвращает четвёртый элемент первого подэлемента
// внутри элемента с ID=nav
var prevlink=o.parentNode.previousSibling.firstChild.childnodes[2];
// возвращает третий узел внутри предыдущего элемента,
// того же уровня, что и родительский элемент элемента о.attributesdatanodeNamenodeTypenodeValuenull, если это элемент.getAttribute (attribute)attribute.Javascript:
var other=document.getElementById('nav').firstChild;
if(other.nodeType==3)
{
other.data='newtext';
}
if(other.nodeType==1)
{
other.firstChild.data='newtext';
}Итак, чтобы достичь изображения в нашем примере, мы будем использовать либо getElementsByTagName, либо getElementById.
HTML:
<a href="index.html"><img src="home.gif" id="home" alt="home"></a>
Javascript:
function findimg()
{
var image;
image=document.getElementById('home');
if (image)
{
image.style.border='3px dashed #ccc';
}
}
//или:
function findimg()
{
var imgs,i;
imgs=document.getElementsByTagName('img');
for(i in imgs)
{
if(/home.gif/.test(imgs[i].src))
{
imgs[i].style.border='3px dashed #ccc';
}
}
}Использовать getElementById гораздо проще, так как нам не нужно пробегать все элементы и искать уникальный идентификатор. В этом примере мы проверяем, содержит ли атрибут src объекта изображения значение 'home.gif'. Более общий способ — проверить назначен ли элементу специальный класс.
HTML:
<a href="index.html"><img src="home.gif" class="roll" alt="home"></a>
Javascript:
function findimg()
{
var imgs,i;
imgs=document.getElementsByTagName('img');
for(i in imgs)
{
if(/roll/.test(imgs[i].className))
{
imgs[i].style.border='3px dashed #ccc';
}
}
}Итак, чтобы добавить эффект ролловера, все что нам надо сделать — это добавить функцию, которая переключает источник изображения и прикрепляет обработчик события к картинке.
function findimg()
{
var imgs,i;
// перебираем все изображения в документе
imgs=document.getElementsByTagName('img');
for(i=0;i<imgs.length;i++)
{
// проверяем существует ли класс 'roll'
if(/roll/.test(imgs[i].className))
{
// добавляем функцию roll на события onmouseover и onmouseout,
//затем посылаем само изображение как объект
imgs[i].onmouseover=function(){roll(this);};
imgs[i].onmouseout=function(){roll(this);};
}
}
}
function roll(o)
{
var src,ftype,newsrc;
// послать src изображения и найти расширение файла
src = o.src;
ftype = src.substring(src.lastIndexOf('.'), src.length);
// проверить содержит ли источник изображения строку _on и,
// если да - удалить её
if(/_on/.test(src))
{
newsrc = src.replace('_on','');
}else{
// в противном случае добавить _on к src
newsrc = src.replace(ftype, '_on'+ftype);
}
o.src=newsrc;
}
window.onload=function(){
findimg();
}Здесь можно проверить этот пример
Вроде бы все хорошо, но мы забыли одну вещь: хотя то, что получилось, просто замечательно, ролловер должен работать и без мыши. Чтобы достигнуть этого, мы должны проверить, находиться ли фокус на ссылке вокруг изображения, так как сама картинка, если на неё поставлена ссылка, недостижима с клавиатуры.
Чтобы сделать проверку, нам надо получить элемент, который содержит изображение, в данном случае — ссылку. Мы сделаем это с помощью команды parentNode. Так как это заодно изменяет объект, которые передан как параметр функции roll(), нам надо будет найти изображение снова. Поэтому мы перебираем дочерние узлы ссылок и смотрим, который из них одновременно и элемент, и изображение, проверив nodeType and nodeName. Это необходимо, так как некоторые браузеры рассматривают пробелы в источнике изображения как узел, другие же нет.
function findimg()
{
var imgs,i;
// перебираем все изображения, проверяем содержат ли они класс roll
imgs=document.getElementsByTagName('img');
for(i=0;i<imgs.length;i++)
{
if(/roll/.test(imgs[i].className))
{
// добавляем функцию roll к родительскому элементу изображения
imgs[i].parentNode.onmouseover=function(){roll(this);};
imgs[i].parentNode.onmouseout=function(){roll(this);};
imgs[i].parentNode.onfocus=function(){roll(this);};
imgs[i].parentNode.onblur=function(){roll(this);};
}
}
}
function roll(o)
{
var i,isnode,src,ftype,newsrc,nownode;
// перебираем все дочерние узлы
for (i=0;i<o.childNodes.length;i++)
{
nownode=o.childNodes[i];
// если узел это и элемент, и IMG,
// то установить значение переменной и выйти из цикла
if(nownode.nodeType==1 && /img/i.test(nownode.nodeName))
{
isnode=i;
break;
}
}
// проверить src и сделать ролловер
src = o.childNodes[isnode].src;
ftype = src.substring(src.lastIndexOf('.'), src.length);
if(/_on/.test(src))
{
newsrc = src.replace('_on','');
}else{
newsrc = src.replace(ftype, '_on'+ftype);
}
o.childNodes[isnode].src=newsrc;
}
window.onload=function(){
findimg();
}Проверьте этот независимый от наличия мыши код
Просто скачайте демонстрационный HTML и попробуйте сделать одно из следующих заданий. Пройдите по ссылке рядом с заданием, чтобы увидеть одно из возможных решений. Решения, в качестве демонстрации, имеют встроенный Javascript, и код не выделяется в отдельный документ так, как это положено. Это сделано, чтобы помочь вам увидеть всю необходимую разметку в одном документе, это легче чем в двух разных.
window.location.hostname) и добавьте href каждой ссылки в круглых скобках после ссылки. Пока вы ещё только изучаете, как это сделать правильно, используйте атрибут innerHTML объекта ссылки, чтобы изменить его содержание. Решение для внешних ссылок.target. Решение для всплывающих окон