Создание скриптов с элементами и коллекциями

Каждый документ HTML состоит из комбинации HTML-тегов и их атрибутов. Эти элементы определяют структуру документа и способ представления контента. С помощью динамической объектной модели HTML (DHTML) можно исследовать и изменить эти элементы и их модифицирующие атрибуты. В следующих разделах разъясняется, как обращаться к элементам документа, используя коллекции элементов.

  • Коллекции all и children 
  • Использование коллекций 
  • Создание новых коллекций: Метод tags 
  • Обращение к свойствам элемента 
  • Исследование иерархии элемента 
  • Получение положения и размеров элемента 
  • Прокрутка элементов в представлении 

Коллекции all и children

Документ HTML — это иерархическая структура тегов, определяющих содержимое документа. Коллекция all в объекте документа представляет все элементы в иерархии документа. Каждый элемент представлен как программируемый объект, отображающийся в коллекции в исходном порядке. К отдельным объектам элементов можно обращаться по индексу или идентификатору (уникальному имени), как показано в следующем примере.

<HTML>

<HEAD><TITLE>Элементы: Сбор</TITLE>

<SCRIPT LANGUAGE="JScript">

function showElements() {

    var tag_names = "";

    for (i=0; i<document.all.length; i++)

        tag_names = tag_names + document.all(i).tagName + " ";

    alert("Этот документ содержит: " + tag_names);

}

</SCRIPT>

</HEAD>

<BODY onload="showElements()">

<H1>Привет!</H1>

<P>Этот документ <B>очень</B> короткий.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_01.htm

При загрузке этого документа, скрипт (обработчик события onload) отображает список элементов в документе, перебирая коллекцию all. Он отображает следующее сообщение.

Этот документ содержит: HTML HEAD TITLE SCRIPT BODY H1 P B

В этом сообщении представлен каждый элемент HTML из предыдущего примера. В списке не отображаются закрывающие теги элементов, поскольку каждый объект элемента представляет как открывающий, так и закрывающий теги. Коллекция также не показывает полностью иерархию элементов, т. е. нельзя определить, какие элементы содержат другие элементы. Коллекция перечисляет элементы в том порядке, в котором они появляются в исходном HTML-коде документа.

Во многих отношениях коллекция all похожа на массив. Она содержит один или более элементов, все элементы одного типа — в данном случае объекты элементов. К элементам обращаются с помощью значений индекса с нулевым основанием или по имени или идентификатору. Значение индекса первого элемента 0, второго — 1 и т. д. С помощью свойства length можно определить количество элементов в коллекции.

Поскольку все элементы в коллекции all являются объектами элементов, к ним можно применять свойства и методы. Например, можно использовать свойство tagName, чтобы получить имя тега HTML элемента, как было сделано в предыдущем примере. Подобным образом можно получить доступ к свойствам и методам соответствующего элемента, обращаясь к нему через коллекцию document.all.

Коллекция all всегда представляет текущее состояние документа и автоматически обновляется, чтобы отразить изменения, внесенные в документ. Например, если получить коллекцию и добавить или удалить содержимое документа, которое изменяет структуру HTML, коллекция автоматически отражает новый контент HTML в последовательности исходного кода.

В некоторых случаях коллекция all может содержать больше элементов, чем фактически имеется в файле документа. В частности, коллекция всегда содержит элементы html, head, TITLE и BODY, даже если они не присутствуют в исходном коде. Аналогично, коллекция всегда содержит элемент tBody для каждого элемента table, независимо от того, указан ли элемент tBody в исходном HTML-коде.

Коллекция all также включает комментарии (!) и неизвестные или недействительные теги. Целью является предоставление пользователю точной картины контента документа. Неизвестные или недействительные теги — это как правило теги с ошибками или расположенные не на своих местах. Знание того, что это за теги и где они расположены, дает возможность заменить их на правильные теги. Коллекция all перечисляет неизвестные и недействительные открывающие и закрывающие теги отдельно; она не пытается объединить их в один элемент.

В следующем примере отображается сообщение "HTML HEAD TITLE SCRIPT BODY ! P ZZZ> /ZZZ> /B".

<HTML>

<HEAD><TITLE>Элементы: Сбор</TITLE>

<SCRIPT LANGUAGE="JScript">

function showElements() {

    var tag_names = "";

    for (i=0; i<document.all.length; i++)

        tag_names = tag_names + document.all(i).tagName + " ";

    alert("Этот документ содержит: " + tag_names);

}

</SCRIPT>

</HEAD>

<BODY onload="showElements()">

<!-- Комментарий -->

<P>В этом документе имеются <ZZZ>неизвестный</ZZZ> и недействительный</B> теги.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_02.htm

Помимо коллекции all в объекте document, каждый отдельный элемент также предоставляет коллекцию all. Вспомните иерархический стиль HTML — это поможет понять принцип коллекции all для каждого элемента. Коллекция all для элемента содержит все элементы, которые содержатся в данном элементе. Например, коллекция all для элемента HTMLбудет содержать весь исходный код, за исключением самого элемента HTML (это будет единственным отличием между коллекцией all для элемента HTML и коллекцией document.all).

Каждый элемент также предоставляет коллекцию children, которая содержит только элементы, являющиеся прямыми потомками в иерархии HTML. Говоря иначе, коллекция children содержит только те элементы, свойство parentElement которых возвращает данный элемент. Для перекрывающихся элементов содержимое коллекции children не определено.

В следующем примере возвращается длина и содержимое коллекций документа all и children. Следует отметить, что у тега html существует только два дочерних элемента — head и BODY. Элементы TITLE и script являются дочерними элементами тега head, а не тега html.

<HTML id=theHTML>

<HEAD>

<TITLE> Взгляд на коллекции all и children</TITLE>

<SCRIPT>

function showme() {

alert('all: ' + window.theHTML.all.length);

for (i=0; i < theHTML.all.length;i++)

{

alert(theHTML.all[i].tagName);

}

alert('children: ' + window.theHTML.children.length);

for (i=0; i < theHTML.children.length;i++)

{

alert(theHTML.children[i].tagName);

}

}

</SCRIPT>

</HEAD>

<BODY onload=showme()>

<DIV> Текст в элементе DIV. Этот элемент DIV будет в

коллекции all элемента HTML.</DIV>

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_03.htm

Использование коллекций

Объектная модель DHTML предоставляет несколько коллекций, которые можно использовать для доступа к элементам документа. Коллекции в объектной модели DHTML похожи на массив переменных, созданный на языке программирования. Элемент можно извлечь из коллекции по его имени или идентификатору, либо по порядковому индексу, который указывает позицию элемента в коллекции. Индексы коллекций имеют нулевое основание, поэтому первый элемент всегда имеет нулевой индекс. В следующем примере Microsoft JScript отображается имя тега элемента p, шестого элемента в коллекции.

<HTML>

<HEAD><TITLE>Элементы: Извлечение элементов</TITLE>

<SCRIPT LANGUAGE="JScript">

function showSixth() {

    var el = document.all(5);

    alert("Шестой элемент: " + el.tagName);

}

</SCRIPT>

</HEAD>

<BODY onload="showSixth()">

<P>Это очень простой документ.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_04.htm

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

var elLast = document.all(document.all.length-1);

alert("Последний элемент в этом документе: " + elLast.tagName);

Также можно извлекать элементы из коллекции, указывая идентификатор. В этом случае элемент должен иметь допустимый идентификатор, заданный в атрибуте ID. В следующем примере JScript отображается имя тега элемента с идентификатором MyID.

<HTML>

<HEAD><TITLE>Элементы: Идентификаторы в качестве индексов</TITLE>

<SCRIPT LANGUAGE="JScript">

function showElementWithID() {

    var el = document.all("MyID");

    alert("Элемент с идентификатором MyID: " + el.tagName);

}

</SCRIPT>

</HEAD>

<BODY onload="showElementWithID()">

<P ID="MyID">Это очень простой документ.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_05.htm

К элементам также можно обращаться по имени, но важно помнить, что атрибут name в основном применяется только к элементам, участвующим в отправке форм. Атрибут ID — это идентификатор, который применяется ко всем элементам.

Будьте внимательны! Хотя в теории ID означает "уникальный идентификатор", в реальности уникальность не применяется. Если несколько элементов имеют одинаковый идентификатор, результатом будет коллекция элементов с одним идентификатором, а не отдельные элементы. К элементам результирующей коллекции можно получить доступ только по порядку. Если ни один элемент не имеет идентификатора, результатом будет null.

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

if (document.all("MyID").length != null)

    alert("Первый элемент с идентификатором MyID:

             " + document.all("MyID").item(0).tagName);

Если заранее известно, что один и тот же идентификатор имеют несколько элементов, можно пропустить один шаг и использовать необязательный второй параметр метода item, чтобы извлечь элемент, не извлекая сначала коллекцию. В следующем примере JScript отображается то же сообщение, что и в предыдущем примере.

var el = document.all.item("MyID",0);

if (el != null)

    alert("Первый элемент с идентификатором MyID: " + el.tagName);

При использовании языков скриптов, таких как JScript и Microsoft Visual Basic Scripting Edition (VBScript), к элементам в коллекциях также можно обращаться с помощью синтаксиса индексирования данного языка. JScript поддерживает три способа индексации массива: целочисленный индекс, заключенный в квадратные скобки, идентификатор, заданный как заключенная в квадратные скобки строка, и идентификатор, перед которым стоит точка. В следующих инструкциях JScript показано, как они применяются.

var el = document.all[2];    // то же, что и document.all.item(2)

var el = document.all["MyID"];   // то же, что и document.all.item("MyID")

var el = document.all.MyID;      // то же, что и document.all.item("MyID")

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

Нельзя использовать идентификаторы для обращения к элементам коллекции imports — эта коллекция состоит из импортированных таблиц стилей, а не из элементов HTML, поэтому идентификаторы недоступны. Вместо этого используйте целочисленные индексы. Хотя для доступа к элементам коллекции frames можно использовать имена, убедитесь, что имена окон уникальны. В противном случае будет доступно только первое окно с заданным именем.

Создание новых коллекций: Метод tags

Метод tags создает коллекцию элементов, имеющих заданное имя тега. Этот метод фильтрует существующую коллекцию и создает новую коллекцию заданного имени тега. Например, в следующем коде JScript метод tags применяется к коллекции all для получения новой коллекции, содержащей только элементы table в документе. Затем к каждой таблице применяется граница.

var doc_tables = document.all.tags("TABLE");

for (i=0; i<doc_tables.length; i++)

    doc_tables(i).border = 1;

Метод tags ищет любые имена тегов, даже недействительные с точки зрения HTML. Если он находит один или несколько элементов с данным именем, то возвращает коллекцию. Если он не может найти элемент с данным именем, то возвращает пустую коллекцию. Свойство length используется для определения количества элементов в коллекции. Коллекция является пустой, если ее длина равна нулю.

Метод tags сохраняет порядок элементов при создании новой коллекции. Это значит, что первый элемент в новой коллекции также является первым экземпляром тега в документе.

Поскольку возвращаемая методом tags коллекция является подмножеством коллекции all, порядковое значение, используемое для обращения к элементу этой коллекции, отличается от порядкового значения, используемого для обращения к этому же элементу коллекции all. Иногда полезно знать оба порядковых значения. Свойство sourceIndex для элемента возвращает порядковую позицию элемента в коллекции документа all.

Обращение к свойствам элемента

Многие свойства элемента — это пары имя-значение, соответствующие HTML-атрибутам элемента и другим значениям, связанным с элементом. Можно получить значение свойства, чтобы определить, как задан соответствующий атрибут, и во многих случаях — изменить значение этого свойства, чтобы динамически воздействовать на элемент. Это ключевая концепция, на которой основано управление динамическими стилями и динамическим контентом. Обращение к свойствам, которые позволяют изменять стили и контент, выполняется посредством обращения к объекту элемента через коллекции, предоставленные в объектной модели DHTML. Например, можно выровнять по центру элемент H1, обратившись к элементу H1 через коллекцию all в документе, а затем задав его свойству align значение "center"; то же значение будет использоваться с атрибутом ALIGN.

var coll = document.all.tags("H1");

if (coll.length>0)

    coll(0).align="center";

Таким же образом можно изменить имя файла изображения для элемента img, задав его свойство src.

var coll = document.all.tags("IMG");

if (coll.length>0)

    coll(0).src="newimage.gif";

Большинство свойств имеют такое же имя и принимают такие же значения, как и соответствующий атрибут. Это значит, что большинство свойств принимают строки, перечисляемые значения или числовые значения. Если имя свойства и отличается от соответствующего ему атрибута, оно обычно довольно близко к нему. Например, свойство className соответствует атрибуту CLASS. Имена изменены для избежания конфликтов с ключевыми словами в распространенных языках скриптов или чтобы гарантировать, что имена свойств не содержат недопустимых в этих языках символов.

Несколько свойств представляют вложенные объекты. Например, объект style соответствует атрибуту STYLE и представляет вложенный объект, предоставляющий доступ ко всем атрибутам каскадных таблиц стилей (CSS), которые можно применить к элементу в качестве встроенного стиля. Объект style сам принимает свойства, которые можно задать, чтобы изменить внешний вид и форматирование элемента. В следующем примере объект style используется для изменения атрибута цвета CSS всех элементов H1 на зеленый.

var coll = document.all.tags("H1");

for (i=0; i<coll.length; i++)

    coll[i].style.color = "green";

Некоторые свойства не соответствуют атрибутам элемента. Эти свойства обычно предоставляют дополнительные сведения об элементе, которые недоступны через атрибуты. Например, свойство tagName задает имя тега HTML элемента, а свойство sourceIndex задает положение элемента в коллекции документа all.

Хотя значения многих свойств можно получать и задавать, некоторые свойства доступны только для чтения, т. е. их значения можно получать, но нельзя задавать или изменять. Например, свойство tagName доступно только для чтения — изменение имени тега элемента не допускается.

Иногда в документе HTML присутствуют недействительные атрибуты или атрибутам присваиваются недопустимые значения. Если атрибуту присвоено недопустимое значение, для соответствующего свойства всегда задается значение по умолчанию. В следующем примере "middle" является недопустимым значением для атрибута ALIGN, поэтому документ отображает сообщение "слева", что является значением по умолчанию для свойства align.

<HTML>

<HEAD><TITLE>Элементы: Использование свойств</TITLE>

<SCRIPT LANGUAGE="JScript">

function showAlignment() {

    var coll = document.all.tags("H1");

    if (coll.length>0)

        alert("Выравнивание для первого заголовка " + coll(0).align);

}

</SCRIPT>

</HEAD>

<BODY onload="showAlignment()">

<H1 ALIGN="center">Привет!</H1>

<P>Этот документ <B>очень</B> короткий.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_06.htm

Методы getAttribute, setAttribute и removeAttribute предоставляют доступ к атрибутам элемента без использования свойств. В эти методы передается имя атрибута и каждый из них выполняет со значением этого атрибута соответствующее действие — возвращает, задает или удаляет.

Например, можно получить и задать текущее значение атрибута ALIGN (вместо того, чтобы получить свойство align) с помощью методов getAttribute и setAttribute, как показано в следующем примере. Документ отображает текущее значение атрибута ("left"), а затем изменяет это значение на "center", выравнивая элемент H1 по центру.

<HTML>

<HEAD><TITLE>Элементы: Использование методов</TITLE>

<SCRIPT LANGUAGE="JScript">

function showAndSetAlignment() {

    alert(MyHeading.getAttribute("align"));

    MyHeading.setAttribute("align","center");

}

</SCRIPT>

</HEAD>

<BODY onload="showAndSetAlignment()">

<H1 ID=MyHeading ALIGN="left">Привет!</H1>

<P>Это короткий документ.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_07.htm

Методы атрибутов особенно полезны при работе с нераспознанными атрибутами и недопустимыми значениями. Например, если атрибут имеет недопустимое значение, метод getAttribute получит в точности это значение, а не значение атрибута по умолчанию. Это означает, что этот метод можно использовать для исследования реального содержимого документа HTML и принятия решений на этой основе. В следующем примере методы getAttribute и setAttribute используются для исправления выравнивания элемента H1 ("middle" является недопустимым значением).

<HTML>

<HEAD><TITLE>Элементы: Недопустимые значения</TITLE>

<SCRIPT LANGUAGE="JScript">

function checkValues() {

    if (MyHeading.getAttribute("align")=="middle")

        MyHeading.setAttribute("align","center");

    if (MyHeading.getAttribute("xyz")!="123")

        MyHeading.setAttribute("xyz","123");

}

</SCRIPT>

</HEAD>

<BODY onload="checkValues()">

<H1 ID=MyHeading XyZ="123" ALIGN="middle">Привет!</H1>

<P>Это короткий документ.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_08.htm

По умолчанию методы атрибутов getAttribute и setAttribute не различают строчные и прописные буквы при поиске неизвестного атрибута. Поэтому в предыдущем примере, хотя строка "xyz" не идентична строке "XyZ," эти методы получают и задают атрибут в любом случае. Можно заставить эти методы искать точное совпадение, задав для необязательного параметра чувствительности к регистру значение true. Например, если в предыдущий пример поместить следующий код, он отобразит сообщение "Не найден", так как "xyz" не совпадает с "XyZ".

if (document.all.MyHeading.getAttribute("xyz", true)==null)

    alert("Не найден");

Если при использовании этих методов в режиме чувствительности к регистру найдено несколько совпадений, фактически возвращаемый элемент может зависеть от платформы.

Исследование иерархии элемента

Элементы в документе HTML образуют иерархию, в которой одни элементы содержат другие. Элемент html на вершине иерархии содержит все остальные элементы в документе. Элемент BODY, содержащийся в элементе html, представляет документ. Блочные элементы, такие как p, содержат текст и встроенные элементы, которые сами могут содержать текст и встроенные элементы, и т. д.

Эту структурную иерархию можно исследовать с помощью метода contains и свойства parentElement. Коллекции all и children для каждого элемента также могут помочь определить структуру документа.

Метод contains возвращает значение trueили false, показывая, содержится ли один элемент в другом. Метод применяется к одному элементу, а другой элемент передается в него в качестве параметра. Например, в следующем примере отображается сообщение "True!", поскольку элемент BODY содержит элемент p.

<HTML>

<HEAD><TITLE>Элементы: Иерархия</TITLE>

<SCRIPT LANGUAGE="JScript">

function showContains() {

    var el = document.all.tags("P").item(0);

    if (document.body.contains(el))

        alert("True!");

                    else

        alert("False!");

}

</SCRIPT>

</HEAD>

<BODY onload="showContains()">

<P>Это очень простой документ.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_09.htm

Примечание. В предыдущем примере свойство body объекта document используется для получения объекта body.

Свойство parentElement всегда идентифицирует следующий элемент в иерархии, который содержит данный элемент. Метод contains и свойство parentElement можно объединить в более сложный скрипт, чтобы определить иерархию элементов в документе. В следующем примере они используются для определения иерархии, а затем отображается сообщение, показывающее эту иерархию.

<HTML>

<HEAD><TITLE>Элементы: Иерархия</TITLE>

<SCRIPT LANGUAGE="JScript">

function showHierarchy() {

    var depth = 0;

    var msg = document.all(0).tagName;

    for (i=1; i<document.all.length; i++) {

        if (document.all(i-1).contains(document.all(i))==true) {

            depth = depth + 1;

        } else {

            var elParent = document.all(i-1).parentElement;

            for ( ; depth>0; depth--) {

                if (elParent.contains(document.all(i))==true)

                            break;

                elParent = elParent.parentElement;

            }

        }

        msg = msg + "\n";

        for (j=1; j<=depth; j++)

            msg = msg + "  ";

        msg = msg + document.all(i).tagName;

    }

    alert("Этот документ содержит:\n" + msg);

}

</SCRIPT>

</HEAD>

<BODY onload="showHierarchy()">

<H1>Привет!</H1>

<P>Этот документ <B>очень</B> короткий.

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_10.htm

Получение положения и размеров элемента

Расположение, ширину и высоту элемента можно определить с помощью свойств offsetLeft, offsetTop, offsetHeight и offsetWidth. Эти числовые свойства задают физические координаты и размеры элемента относительно смещения его offsetParent. Ниже представлен пример простых часов, размер показаний которых подгоняется под текущую ширину и высоту основного текста документа.

<HTML>

<HEAD><TITLE>Простые часы</TITLE>

<SCRIPT LANGUAGE="JScript">

function startClock() {

    window.setInterval("Clock_Tick()", 1000);

    Clock_Tick();

}

var ratio = 4;

function Clock_Tick()

{

    var s = Date();

    var t = s.substring(11,19);

    var doc_height = document.body.offsetHeight;

    var doc_width = document.body.offsetWidth;

    if ((doc_height*ratio)>doc_width)

        doc_height = doc_width / ratio;

    MyTime.innerText = t;

    MyTime.style.fontSize = doc_height;

}

</SCRIPT>

</HEAD>

<BODY onload="startClock()">

<P ID="MyTime"> </P>

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_11.htm

Значения свойств offsetLeft и offsetTop задаются относительно элемента, заданного свойством offsetParent для элемента. Чаще всего это свойство возвращает body. В следующем примере, хотя элемент td и появляется в документе далеко справа, его позиция (0,0), так как его offsetParent — это элемент tr, а не основной текст документа.

<HTML>

<HEAD><TITLE>Элементы: Положения</TITLE>

<SCRIPT LANGUAGE="JScript">

function showPosition() {

    var el = MyID;

    alert("Элемент TD в позиции (" + el.offsetLeft + "," + el.offsetTop + ")\n" +

        "offsetParent — это " + el.offsetParent.tagName );

}

</SCRIPT>

</HEAD>

<BODY onload="showPosition()">

<P>Этот документ содержит таблицу, выровненную по правому краю.

<TABLE BORDER=1 ALIGN=right>

<TR><TD ID=MyID>Это маленькая таблица.

</TABLE>

</BODY>

</HTML>

Пример кода: http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/overview/elem_12.htm

Прокрутка элементов в представлении

Еще одним полезным методом является scrollIntoView. Этот метод прокручивает элемент в представлении в пределах окна, помещая его либо наверх, либо вниз окна. Этот метод полезен для моментального показа пользователю результата какого-то действия, чтобы пользователю не нужно было вручную прокручивать документ в поисках результата. В следующем примере содержимое пятого параграфа подчеркивается и прокручивается наверх окна.

var coll = document.all.tags("P");

if (coll.length>=5) {

    coll(4).style.textDecoration = "underline";

    coll(4).scrollIntoView(true);

}