Текст
                    JavaScript
Библия
пользователя
5-е издание
Дэнни Гудман, Майкл Моррисон
Предисловие Брендана Эйха, создателя JavaScript
В
дшкластика
Москва ♦ Санкт-Петербург ♦ Киев
2006


ББК 32.973.26-018.2.75 Г93 УДК 681.3.07 Компьютерное издательство "Диалектика" # Главный редактор С.Н. Тригуб Зав. редакцией В.Р. Гинзбург Перевод с английского и редакция И.В. Василенко По общим вопросам обращайтесь в издательство "Диалектика" по адресу: info@dialektika.com, http://www.dialektika.com 115419, Москва, а/я 783; 03150, Киев, а/я 152 Гудман, Дэнни, Моррисон, Майкл. Г93 JavaScript. Библия пользователя, 5-е издание. : Пер. с англ. — М. : ООО "И.Д. Вильяме", 2006. — 1184 с. : ил. — Парал. тит. англ. ISBN 5-8459-1027-7 (рус.) Эта книга адресована широкому кругу читателей Web-дизайнеров, которые решили детально изучить язык JavaScript. Она имеет все шансы завоевать титул полного справочного руководства по JavaScript не только в глазах его разработчиков, но и в сердцах пользователей. В издании подробно описаны практически все средства разработки сценариев JavaScript, используемые в современных и уже устаревших браузерах. Изложение материала начинается с истории и особенностей языка JavaScript и заканчивается описанием сложных приложений, используемых для решения таких задач, как создание формы заказа, обработка XML-данных и др. Особое внимание в книге уделено созданию межбраузерных сценариев, которые максимально эффективно выполняются в подавляющем большинстве используемых в настоящее время браузеров. На прилагаемом к книге компакт-диске предоставлены дополнительные 22 главы на русском языке, все листинги, описанные в книге, некоторые вспомогательные материалы и программы, которые помогут читателю изучить сложные темы и практические примеры. ББК 32,973.26-018.2.75 Все названия программных продуктов являются зарегистрированными торговыми марками соответствующих фирм. Никакая часть настоящего издания ни в каких целях не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами, будь то электронные или механические, включая фотокопирование и запись на магнитный носитель, если на это нет письменного разрешения издательства JOHN WILEY&Sons, Inc. Copyright © 2006 by Dialektika Computer Publishing. Original English language edition Copyright © 2004 by Danny Goodman. All rights reserved including the right of reproduction in whole or in part in any form. This translation is published by arrangement with Wiley Publishing, Inc. ISBN 5-8459-1027-7 (рус.) © Компьютерное изд-во "Диалектика", 2006, перевод, оформление, макетирование ISBN 0-7645-5743-2 (англ.) © Danny Goodman, 2004
Оглавление Предисловие 24 Введение 27 ЧАСТЬ L ЗНАКОМСТВО С JAVASCRIPT 35 ГЛАВА 1. Роль JavaScript в World Wide Web 36 ГЛАВА 2. Творческие изыскания в сложных полевых условиях 44 ГЛАВА 3. Первый собственный сценарий 52 ЧАСТЬ II. РУКОВОДСТВО ПО JAVASCRIPT 61 ГЛАВА 4. Объекты документа и браузера 62 ГЛАВА 5. Сценарии и документы HTML 83 ГЛАВА 6. Основы программирования. Часть 1 94 ГЛАВА 7. Основы программирования. Часть 2 105 ГЛАВА 8. Объекты документа и окна 118 ГЛАВА 9. Формы и их элементы 131 ГЛАВА 10. Строки, математические выражения и даты 145 ГЛАВА 11. Работа с окнами и фреймами 155 ГЛАВА 12. Изображения и динамический HTML 165 ЧАСТЬ III. ОБЪЕКТЫ ДОКУМЕНТА * 175 ГЛАВА 13. Основы JavaScript 176 ГЛАВА 14. Основы объектной модели документа 196 ГЛАВА 15. Основные объекты HTML-элементов 235 ГЛАВА 16. Объекты window и frame 392 ГЛАВА 17. Объекты history и location 512 ГЛАВА 18. Объекты document и body 535 ГЛАВА 19. Объекты ссылки и анкера 613 ГЛАВА 20. Объекты изображения, области и карты изображений 622 ГЛАВА 21. Объект form и вложенные в него объекты 650 ГЛАВА 22. Объект кнопки 671 ГЛАВА 23. Текстовые объекты формы 692 ГЛАВА 24. Объекты select, option и fileupload 713
ГЛАВА 25. Объекты событий 737 ГЛАВА 26. Таблица стилей и объекты стилей 810 ЧАСТЬ IV. ОБЪЕКТЫ ЯЗЫКА JAVASCRIPT 867 ГЛАВА 27. Объект string 868 ГЛАВА 28. Объекты Math, Number и Boolean 895 ГЛАВА 29. Объект Date 908 ГЛАВА 30. Объект Array 924 ГЛАВА 31. Управляющие структуры и обработка исключительных ситуаций 945 ГЛАВА 32. Операторы JavaScript 975 ГЛАВА 33. Функции и пользовательские объекты 996 ГЛАВА 34. Глобальные функции и выражения 1024 ГЛАВА 35. Текстовые объекты тела страницы 1039 ЧАСТЬ V. ПРИЛОЖЕНИЯ 1121 ПРИЛОЖЕНИЕ А. Справочник по объектам браузера и JavaScript 1122 ПРИЛОЖЕНИЕ Б. Зарезервированные слова JavaScript 1135 ПРИЛОЖЕНИЕ В. Ответы к упражнениям 1136 ПРИЛОЖЕНИЕ Г. Internet-ресурсы, посвященные JavaScript и DOM 1150 ПРИЛОЖЕНИЕ Д. Содержимое компакт-диска 1153 ЧАСТЬ VI. ДОПОЛНИТЕЛЬНЫЕ ГЛАВЫ НА КОМПАКТ-ДИСКЕ 1157 Предметный указатель 1159 5 Оглавление
Содержание Об авторах Предисловие Введение Структура и особенности этого издания Благодарности Ждем ваших отзывов! ЧАСТЬ I. ЗНАКОМСТВО С JAVASCRIPT ГЛАВА 1. Роль JavaScript в World Wide Web Конкуренция в Web Другие Web-технологии Что такое HTML Серверные сценарии Вспомогательные приложения и надстройки JavaScript: язык для всех Как LiveScript стал JavaScript В мире Microsoft JavaScript: правильное средство для правильной работы ГЛАВА 2. Творческие изыскания в сложных полевых условиях Полная неразбериха Тенденции Проблема совместимости сегодня Базовый язык и объекты Стандарт базового языка Объектная модель документа Каскадные таблицы стилей Динамический HTML Создание межбраузерных сценариев ГЛАВА 3. Первый собственный сценарий Программное обеспечение Выбор текстового редактора" Выбор браузера Настройка среды разработки Система Windows Система MacOS X Особенности перезагрузки Что будет делать первый сценарий
Создание первого сценария Исследование сценария Дескриптор <script> Сценарий для всех браузеров Отображение текста Улыбнемоя вместе ЧАСТЬ II. РУКОВОДСТВО ПО JAVASCRIPT ГЛАВА 4. Объекты документа и браузера Сценарии, которые творят чудеса JavaScript в действии Интерактивный интерфейс Поиск данных Проверка правильности введенных данных Интерактивные данные Многофреймовые документы Динамический HTML Принципы использования JavaScript Объектная модель документа Структура HTML и DOM Объектная модель окна документа Загрузка документа Простой документ Добавление элемента абзаца Добавление в абзац текста Создание нового элемента Связывание объектов Именование объектов Ссылка на объект Терминология, используемая при управлении узлами Что такое узел Отцы и дети Понятия, определяющие объект Свойства Методы Обработчики событий Упражнения ГЛАВА 5. Сценарии и документы HTML Размещение сценариев в документах Дескрипторы сценария <script> Размещение дескрипторов Особенности использования старых браузеров Операторы JavaScript Выполнение операторов сценария Немедленное выполнение операторов в процессе загрузки документа Отсроченные сценарии Просмотр ошибок сценария 56 58 58 58 59 60 61 62 62 63 63 64 65 65 66 67 68 69 70 71 72 72 72 73 74 74 75 75 76 76 76 77 78 79 80 81 83 83 83 84 86 87 87 88 88 90 8 Содержание
Различие между написанием сценариев и программированием 91 Упражнения 92 ГЛАВА 6. Основы программирования. Часть 1 94 Язык программирования 94 Способы управления информацией 95 Переменные 95 Создание переменной 96 Названия переменных 97 Выражения и их вычисление 97 Выражения в сценарии script 1 .htm 98 Выражения и переменные > 99 Преобразование типов данных 100 Преобразование строк в числа 101 Преобразование чисел в строки 101 Операторы 102 Арифметические операторы 102 Операторы сравнения 102 Упражнения 103 ГЛАВА 7. Основы программирования. Часть 2 105 Решения и циклы 105 Управляющие структуры 106 Условный оператор if 106 Условный оператор if.. .else 107 Циклы 108 Функции 109 Параметры функций 109 Диапазон действия переменных 110 Использование фигурных скобок 112 Массивы ИЗ Создание массива 113 Получение доступа к данным массива 114 Параллельные массивы 114 Объекты документа в массиве 116 Упражнения 117 ГЛАВА 8. Объекты документа и окна 118 Объекты окна документа 118 Объект окна 118 Получение доступа к свойствам и методам окна 119 Создание окна 120 Свойства и методы окна 121 Свойство window, status 122 Метод window.alert() 122 Метод window.confirm() 123 Метод window.prompt() 123 Обработчик события onload * 124 Объект location 124 Объект navigator 125 Содержание 9
Объект документа 125 Свойство document.forms[] 126 Свойство document.images[] 126 Метод document. write() 127 Методы document.createElementO и document.createNode() 129 Метод document.getElementById() 129 Упражнения 130 ГЛАВА 9. Формы и их элементы 131 Объект form 131 Форма как объект и контейнер 132 Доступ к свойствам формы 132 Свойство form.elements[] 133 Элементы формы — это тоже объекты 133 Текстовые объекты 134 Объект кнопки 136 Объект флажка 136 Объект переключателя 137 Объект элемента select 139 Передача функциям данных форм и элементов 140 Отправка данных форм и проверка их правильности 142 Упражнения , 144 ГЛАВА 10. Строки, математические выражения и даты 145 Объекты базового языка 145 Строковые объекты 146 Объединение строк 146 Методы строковых объектов 147 Объект Math 149 Объект Date 150 Определение даты 152 Упражнения 153 ГЛАВА 11. Работа с окнами и фреймами 155 Окна: отцы и дети 155 Ссылки на другие объекты 157 Ссылки из родительского фрейма на дочерний 157 Ссылки из дочернего фрейма на родительское окно 157 Ссылка из дочернего фрейма на дочерний фрейм 158 Полезные советы 158 Элемент iframe 159 Способы управления многофреймовыми документами 159 Дополнительные сведения о ссылках 162 Упражнения 163 ГЛАВА 12. Изображения и динамический HTML 165 Объект изображения 165 Изменяемые изображения 166 Предварительная загрузка изображений 166 Создание ролловеров 168 Оператор javascript: псевдо-URL 171 10 Содержание
Больше динамизма в HTML 172 Изменение настроек таблицы стилей 172 Динамическое содержимое узлов W3C DOM 173 Свойство innerHTML 173 Упражнения 174 ЧАСТЬ III. ОБЪЕКТЫ ДОКУМЕНТА 175 ГЛАВА 13. Основы JavaScript 176 Версии JavaScript 176 Стандарт базового языка — ECMAScript 177 Встроенные в HTML-документы сценарии 177 Дескриптор сценария <script> 178 Дескриптор <script fог> 179 Особенности написания кода при работе со старыми типами браузеров 179 Что значит "спрятать" сценарий 180 Библиотеки сценариев (файлы .js) 181 Определение версии браузера 182 Проверка поддержки JavaScript 182 Написание сценариев для разных браузеров 184 Обеспечение совместимости 189 Использование экспериментальных версий браузеров 190 Приложение The Evaluator Sr. 191 Принципы совместимости 192 Особенности языка JavaScript 192 Вперед, к объектным моделям документов! 195 ГЛАВА 14. Основы объектной модели документа 196 Иерархическая структура объектной модели 196 Иерархия и структурная схема объектов 197 Структура объектной модели документа 198 Создание объектов в документе 199 Свойства объектов 199 Методы объекта 200 Обработчики событий объектов 201 Обработчики событий как методы 201 Обработчики событий как свойства 202 Разнообразие объектных моделей 203 Базовая объектная модель 203 Базовая объектная модель, поддерживающая изображения 204 Расширенная модель NN4 205 Модель перехвата событий 205 Объект Layer 206 Расширенная модель Ш4+ 207 Объекты элементоэ HTML 207 Иерархия содержимого элементов 208 Каскадные таблицы стилей * 209 И еще о событиях 210 События и сценарии 211 Расширенная модель ГЕ5+ 211 Содержание 11
Модель W3C DOM 212 Поколения DOM 213 Неизменная часть 213 Недоступные элементы 214 "Новая" практика HTML 214 Новые концепции DOM 215 Фактический стандарт: innerHTML 223 Статичные объекты 224 Двунаправленная модель событий 225 Комбинирование объектных моделей 227 Консервативный подход 227 Умеренная концепция 228 Радикальный подход 231 Обработка событий 233 Режимы совместимости стандартов 233 Мы поедем, мы помчимся... 234 ГЛАВА 15. Основные объекты HTML-элементов 235 Общие объекты 236 Синтаксис 238 Описание объектов 238 Свойства 239 Методы 295 Обработчики событий 357 ГЛАВА 16. Объекты window и frame 392 Терминология 392 Фреймы 393 Создание фреймов 393 Объектная модель фрейма 393 Ссылки на фреймы 394 Объект top против объекта parent 395 Предотвращение использования фреймов 395 Проверка загрузки фреймов 396 Включение и отключение фреймов 396 Наследование 396 Синхронизация фреймов 397 Пустые фреймы 397 Просмотр исходного кода фрейма 398 Фреймы и элементы frame 398 Объект window 399 Синтаксис 400 Описание объекта 400 .Свойства 402 Методы 435 Обработчики событий 485 Элемент frame 490 Синтаксис 491 Описание объекта 491 Свойства 492 12 Содержание
Элемент frameset 497 Синтаксис 498 Описание объекта 498 Свойства 499 Элемент iframe 503 Синтаксис 503 Описание объекта 504 Свойства 504 Объект popup 508 Синтаксис 508 Описание объекта 508 Свойства 509 Методы 510 ГЛАВА 17. Объекты history и location 512 Объект location 513 Синтаксис 513 Описание объекта 513 Свойства 515 Методы 526 Объект history 529 Синтаксис 529 Описание объекта 529 Свойства 530 Методы 531 ГЛАВА 18. Объекты document и body 535 Объект document 536 Синтаксис 538 Описание объекта 538 Свойства 539 Методы 576 Обработчики событий 599 Элемент body 600 Синтаксис 601 Описание объекта 601 Свойства 602 Методы 607 Обработчики событий 608 Объект treewalker 609 Синтаксис 610 Описание объекта 610 Свойства 611 Методы 611 ГЛАВА 19. Объекты ссылки и анкера 613 Объекты элементов link, anchor и а , 614 Синтаксис 614 Описание объектов 615 Свойства 617 Содержание 13
ГЛАВА 20. Объекты изображения, области и карты изображений Изображения и элементы img Синтаксис Описание объекта Свойства Обработчики событий Объект элемента area Синтаксис Описание объекта Свойства Объект элемента тар Синтаксис Описание объекта Свойства ГЛАВА 21. Объект form и вложенные в него объекты Объект form в объектной модели Элемент form Синтаксис Описание объекта Ссылка на элементы управления формы Передача форм и элементов в функции Отправка форм по электронной почте Изменение атрибутов формы Кнопки на формах Перенаправление данных после отправки Массивы элементов формы Описание объекта элемента input Свойства Методы Обработчики событий Объекты элементов fieldset и legend Синтаксис Описание объектов Объект элемента label Синтаксис Описание объекта Свойства ГЛАВА 22. Объект кнопки Объект элемента button, объекты button, submit и reset Синтаксис Описание объектов Свойства Методы Обработчики события Объект checkbox Синтаксис Описание объекта Свойства 622 622 623 624 626 641 642 643 643 645 646 646 646 647 650 650 651 651 652 652 653 656 657 658 658 659 659 660 664 666 668 668 668 669 669 670 670 671 671 671 672 674 675 675 677 677 677 678 14 Содержание
Методы 681 Обработчики события 681 Объект radio 684 Синтаксис 684 Описание объекта 684 Свойства 685 Методы 688 Обработчики события 689 Объект image 690 Синтаксис 690 Описание объекта 691 Свойства 691 ГЛАВА 23. Текстовые объекты формы 692 Объект text 693 Синтаксис 693 Описание объекта 693 Текстовые поля и события 694 Свойства 696 Методы 702 Обработчики событий 705 Объект password 708 Синтаксис 708 Описание объекта 708 Скрытый объект input 708 Синтаксис 708 Описание объекта 709 Объект textarea 709 Синтаксис 710 Описание объекта 710 Возврат каретки в текстовых областях 711 Свойства 712 Методы 712 ГЛАВА 24. Объекты select, option и fileupload 713 Объект элемента select 713 Синтаксис 714 Описание объекта 714 Изменение опций объекта select (NN3+, ГЕ4+) 716 Изменение опций объекта select (Ш4+) 719 Изменение опций объекта select (W3C DOM) 721 Свойства 722 Методы 729 Обработчики событий 730 Объект элемента option 731 Синтаксис 731 Описание объекта * 732 Свойства 732 Объект элемента optgroup 733 Синтаксис 733 Содержание 15
Описание объекта 733 Свойства 733 Объект элемента ввода файла 735 Синтаксис 735 Описание объекта 736 ГЛАВА 25. Объекты событий 737 Понятие события 738 Свойства событий 738 Статичные объекты событий 739 Передача событий 739 Передача событий в NN4 740 Передача событий в ГЕ4 749 Передача событий в NN6+ 753 Ссылки на объект события 758 Ссылки на объект события в IE4+ 758 Ссылки на объект события в W3C 758 Совместимость объектов event 759 Сравнение моделей событий 761 Межплатформенное определение клавиш-модификаторов 761 Межплатформенное определение клавиш 762 Типы событий 763 Старые версии браузеров 764 Типы событий в Ш4+ и NN6+/W3C 765 Объект события в NN4 766 Синтаксис 766 Описание объекта 766 Свойства 766 Объект события в ГЕ4+ 771 Синтаксис 772 Описание объекта 772 Свойства 773 Объект события в NN6+ 790 Синтаксис 791 Описание объекта 791 Свойства 792 Методы 807 ГЛАВА 26. Таблица стилей и объекты стилей 810 Имена объектов 811 Импортированные таблицы стилей 812 Получение свойств стиля 813 Объект элемента style 814 Синтаксис 814 Описание объекта 814 Свойства 814 Объект stylesheet 815 Синтаксис 815 Описание объекта 815 18 Содержание
Свойства 816 Методы 822 Объекты cssrule и rule 824 Синтаксис 824 Описание объектов 824 Свойства 825 Объекты currentstyle, runtimestyle и style 827 Синтаксис 827 Описание объектов 827 Свойства стиля 828 Значения свойств 829 Свойства текста и шрифта 832 Свойства вида и макета документа 839 Свойства позиционирования 844 Свойства фона 846 Свойства границ и полей 847 Свойства списков 851 Свойства полосы прокрутки 852 Свойства таблиц 853 Свойства страницы и печати 854 Дополнительные свойства 855 Акустические свойства 855 Объект фильтра 856 Синтаксис 856 Описание объекта 857 Изменение синтаксиса фильтров в Ш5.5 862 ЧАСТЬ IV. ОБЪЕКТЫ ЯЗЫКА JAVASCRIPT 867 ГЛАВА 27. Объект string 868 Типы данных string и number 868 Простые строки 868 Создание длинных строковых переменных 869 Объединение строк и переменных 869 Специальные символы 870 Объект string 871 Синтаксис 872 Описание объекта 872 Свойства 873 Методы синтаксического анализа 875 Функции обработки строковых данных 891 Методы форматирования 892 Кодирование и декодирование строк URL 894 ГЛАВА 28. Объекты Math, Number и Boolean 895 Числа в JavaScript 895 Целые числа и числа с плавающей точкой ' 896 Шестнадцатеричные и восьмеричные целые числа 897 Преобразование строк в числа 898 Содержание 17
Преобразование чисел в строки 899 Когда число совсем не число 900 Объект Math 900 Синтаксис 900 Описание объекта 900 Свойства 901 Методы 901 Генерирование случайных чисел 902 Сокращенный вариант использования объекта Math 902 Объект Number 903 Синтаксис 903 Описание объекта 904 Свойства 904 Методы 905 Объект Boolean 907 Синтаксис 907 Описание объекта 907 ГЛАВА 29. Объект Date 908 Временные зоны и GMT 908 Объект Date 909 Создание объекта даты 910 Естественные свойства и методы объекта 911 Методы объекта Date 911 Учет временных зон 914 Строковые даты 914 Удобные форматы даты в ранних версиях браузеров 915 Еще раз о преобразованиях 916 Арифметика даты и времени 916 Подсчет дней 917 Ошибки, связанные с управлением датой 920 Проверка дат, вводимых в формы 920 ГЛАВА 30, Объект Array 924 Структурированные данные 924 Создание пустого массива 925 Заполнение массива данными 925 Расширенные возможности создания массивов в JavaScript 926 Удаление элементов массива 927 Параллельные массивы 927 Многомерные массивы 930 Свойства объекта Array 931 Методы объекта Array 932 ГЛАВА 31. Управляющие структуры и обработка исключительных ситуаций 945 Конструкции if и if.. .else 946 Простые решения 946 Условные выражения 947 Составные решения 947 Вложенные выражения if... else 948 18 Содержание
Условные выражения 950 Циклы повторения операций (for) 951 Использование счетчика цикла 952 Выход из цикла 954 Управление циклом с помощью оператора continue 954 Цикл while 955 Цикл do-while 956 Просмотр свойств (цикл for-in) 957 Оператор with 958 Маркированные операторы 958 Оператор switch 960 Обработка исключительных ситуаций 963 Исключительные ситуации и ошибки 963 Механизм обработки исключительных ситуаций 964 Использование конструкций try-catch-finally 965 Исключительные ситуации на примерах 967 Переход к исключительным ситуациям 968 Объект ошибки 972 Синтаксис 972 Описание объекта 972 Свойства 973 Методы 974 ГЛАВА 32. Операторы JavaScript 975 Категории операторов 975 Операторы сравнения 976 Равенство несоизмеримых типов данных 977 Арифметические операторы 979 Операторы присвоения 981 Булевы операторы 983 Булева математика 983 Применение булевых операторов 985 Побитовые (или поразрядные) операторы 986 Объектные операторы 987 Комплексные операторы 990 Приоритеты операторов 992 ГЛАВА 33. Функции и пользовательские объекты 996 Объект функции 996 Синтаксис 996 Описание объекта 997 Создание функций 997 Вложенные функции 998 Параметры функции 999 Свойства 999 Методы 1002 Замечания по применению функций ' 1004 Вызов функции 1004 Переменные: глобальные и локальные 1005 Переменные параметров 1007 Содержание 19
Рекурсия в функциях 1008 Преобразование функций в библиотеки 1008 Пользовательские объекты 1009 Пример "объектов планет" 1010 Создание массива объектов 1014 Добавление пользовательских методов 1015 Несколько дополнительных способов создания объектов 1016 Определение в объекте получателя и определителя свойства 1017 Применение пользовательских объектов 1019 Концепция объектно-ориентированного программирования 1019 Добавление прототипа 1019 Наследование прототипа 1020 Вложенные объекты и наследование прототипа 1020 Объект Object 1022 Синтаксис 1022 Описание объекта 1022 Методы 1023 ГЛАВА 34. Глобальные функции и выражения 1024 Функции 1025 Выражения 1032 ГЛАВА 35. Текстовые объекты тела страницы 1039 Объекты элементов blockuote и q 1040 Синтаксис 1040 Описание объектов 1040 Свойство 1040 Объект элемента Ьг 1040 Синтаксис 1041 Описание объекта 1041 Свойство 1041 Объект элемента font 1041 Синтаксис 1041 Описание объекта 1042 Свойства , 1042 Объекты элементов h 1 -пб 1044 Синтаксис 1045 Описание объектов 1045 Свойство 1045 Объект элемента hr 1045 Синтаксис 1046 Описание объектов 1046 Свойства 1046 Объект элемента label ^ 1049 Синтаксис 1049 Описание объекта 1050 Свойства 1050 Объект элемента marquee 1051 Синтаксис 1051 Описание объекта 1051 20 Содержание
Свойства 1051 Методы 1055 Обработчики событий 1055 Объект Range 1056 Синтаксис 1057 Описание объекта 1057 Управление выделениями 105 8 Свойства 1059 Методы 1062 Объект selection 107 8 Синтаксис 1078 Описание объекта 1078 Свойства 1079 Методы 1081 Объекты Text и TextNode 1084 Синтаксис 1084 Описание объектов 1084 Свойства 1085 Методы 1085 Объект TextRange 1089 Синтаксис 1090 Описание объекта 1090 Управление текстовыми областями 1091 Совместимость с браузерами 1092 Свойства 1093 Методы 1096 Объект TextRectangle 1118 Синтаксис ' 1118 Описание объекта 1118 Свойства 1119 ЧАСТЬ V. ПРИЛОЖЕНИЯ ii2i ПРИЛОЖЕНИЕ А. Справочник по объектам браузера и JavaScript 1122 ПРИЛОЖЕНИЕ Б. Зарезервированные слова JavaScript 1135 ПРИЛОЖЕНИЕ В. Ответы к упражнениям 1136 Глава 4 1136 Глава 5 1137 Глава 6 1139 Глава 7 1139 Глава 8 1143 Глава 9 1144 Глава 10 1147 Глава 11 1148 Глава 12 1149 * ПРИЛОЖЕНИЕ Г. Internet-ресурсы, посвященные JavaScript и DOM 1150 Узел поддержки и обновлений для книги 1150 Группы новостей 1151 Содержание 21
Наиболее часто задаваемые вопросы (FAQs) 1151 Документация 1151 World Wide Web 1152 ПРИЛОЖЕНИЕ Д. Содержимое компакт-диска 1153 Системные требования 1153 Содержимое диска 1153 Листинги JavaScript для текстовых редакторов 1154 Приложение А (в электронном формате) 1154 Электронная версия книги 1154 Устранение неполадок 1155 ЧАСТЬ VI. ДОПОЛНИТЕЛЬНЫЕ ГЛАВЫ НА КОМПАКТ-ДИСКЕ i is? Предметный указатель 1159 22 Содержание
Об авторах Дэнни Гудман — автор большого количества широко известных книг. Среди них такие популярные издания, как The Complete HyperCard Handbook, Danny Goodman's AppleScript Handbook, Dynamic HTML: The Definitive Reference и JavaScript & DHTML Cookbook. Дэнни также является общепризнанным экспертом и высококлассным преподавателем в области языков программирования. Талант писателя и опыт педагога приносят ему постоянные дивиденды со стороны как читателей, так и коллег по всему миру. Чтобы быть постоянно в форме и держать руку на пульсе событий, Дэнни частенько практикует как консультант по программированию и разработке сайтов в паутине World Wide Web и интранет. Делает он это прямо из своей штаб-квартиры в Сан-Франциско. Майкл Моррисон — писатель, разработчик, изобретатель игрушек и автор большого количества книг, посвященных языку Java, Web-сценариям, проектированию игр, ActiveX и карманным ПК. Ему принадлежат такие книги, как Faster Smarter HTML and XML, Teach Yourself XML in 24 Hours и The Complete Idiot's Guide to Java 2. Майкл также является основателем компании Stalefish Labs (www.stalefishlabs.com), занимающейся разработкой традиционных игр и игрушек.
Предисловие Как создатель JavaScript, я бы хотел сказать несколько слов о том, что такое JavaScript, как появился этот язык и для чего нужен. Книга, которую вы держите в руках, поможет вам освоить новые вершины программирования. JavaScript — это плод неуемного желания предоставить разработчикам HTML-документов средства динамического управления всеми его объектами, которые описывались бы исключительно в коде Web-страницы. Теперь такой подход кажется простым и очевидным, но весной 1995 года эта идея была весьма нестандартная. Она была связанна с серьезными несоответствиями между принятыми прописными истинами (принципы HTML предписывают создавать только документы со статической структурой) и принципами динамического изменения документов (речь идет об аплетах Java, признанных единственным реальным способом "оживить" и расширить возможности Web-страницы). Раз уж пришлось затронуть подобные вопросы развития среды Internet, то рассмотрим детальнее особенности языка JavaScript. ■ В первую очередь, он имеет облегченный синтаксис языка Java. Синтаксис "натурального языка" HyperTalk представлялся мне вполне приемлемым. Но после того, как один мой хороший знакомый одолжил мне книгу The Complete HyperCard Handbook, написанную Дэнни Гудманом, я все больше стал склоняться к мысли об использовании в качестве базиса для нового языка именно Java, особенно в свете бурного его развития. Если разрабатываемый язык синтаксически будет подобен Java, то с точки зрения тех программистов, которые переориентируются с одного языка на другой, такое совпадение будет только приветствоваться. Однако обязательность принципа декларирования классов и типов Java или использования точки с запятой после каждого оператора в месте окончания строки не вызвала у меня должного восторга. Ведь создание сценариев для большинства пользователей сродни написанию коротких отрывков кода — оно должно выполняться быстро и четко. ■ События для HTML-элементов. Кнопки должны управляться обработчиками события onClick. Документы загружаются в окна и выгружаются из них, так что в сценарии должны быть представлены еще и обработчики события onLoad и onUnload. Пользователи в сценарии используют различные формы — отсюда вытекает необходимость в обработчике события onSubmit. Хотя в принципе и не обходя по гибкости систему сообщений HyperCard (обработчики последнего ориентированы на использование системы обозначений типа onEvent), события в JavaScript позволяют разработчикам HTML- документов взаимодействовать с пользователями с помощью удаленных серверов и быстро реагировать на их действия и операции, выполняемые браузером. С использованием рекомендаций по обработке событий W3C DOM 2 в современных браузерах удалось посредством JavaScript полностью реализовать гибкий контроль над событиями. ■ Объекты без классов. Язык программирования Self оправдал идею использования основанного на прототипах принципа наследования. Для JavaScript я хотел использовать один прототип для одного объекта (для большей простоты и надежности), который основывается по умолчанию на функции, вызываемой с помощью оператора new (для
согласованности с Java). Чтобы обойтись без характерных для такой ситуации методов и функций, все функции задают объекты, вызывающие свойства с помощью ключевого слова this. Хотя свойства активно не использовались вплоть до версии NN3, их прототип уже был заложен во второй версии в виде заключаемого в кавычки текста, который интерпретировался как объект (прототип объекта String, к которому пользователь мог присоединять методы). ■ Генерирование HTML-кода. Внедрение JavaScript в HTML способствовало развитию следующей идеи. А что, если HTML-код будет генерироваться в результате загрузки обычного текста (задаваемого в сценарии) в ходе его выполнения? Возможности этого подхода вышли далеко за пределы простого управления датой или временем внесения последних изменений. Эта простая идея позволила создавать сложные программные конструкции, позволяющие отслеживать данные многоуровневой структуры таблиц, где все повторяемые элементы задаются в цикле сценария, в то время как вся информация, заносимая в таблицы, обрабатывается в JavaScript минимальным набором операторов и сохраняется в файлах каталогов или мини-базах данных. Вначале я полагал, что JavaScript найдет себе применение, прежде всего, в качестве средства ввода данных на HTML-формах. Но через некоторое время был удивлен, узнав, сколько дизайнеров, работающих с Web, используют его в своих проектах и применяют готовые JavaScript- приложения в HTML-документах для решения самых разнообразных задач. Web-дизайнеры давно искали способы быстрого и эффективного создания серьезных приложений с помощью минимального набора простых операторов. О популярности языка можно было судить по ответной реакции пользователей. В конечном счете разработчики (а также пользователи) настояли на реализации браузерной поддержки спецификации, известной под названием Dynamic HTML (презабавнейшим образом она описана по адресу: http: //www. j avascript -games. org/). В то время как армия Web-разработчиков примерялась к возможностям JavaScript, стало явным несомненное преимущество среды создания сценариев над старым программным достоянием. Это относится не только к большой относительной простоте языков HTML и JavaScript, но также и к минимальным требованиям к разработчику Web-страниц. Ему не нужно обладать опытом программирования, чтобы управлять изображениями, обрабатывать события и создавать красочные эффекты, что невозможно при создании больших приложений с помощью громоздких языков, программируемых традиционным способом. Превосходство JavaScript в Web сегодня подтверждает нашу безоглядную веру в ценность языка создания сценариев для разработчиков HTML-документов. Удерживая на низком уровне планку "требований", среда HTML (вместе с JavaScript) сделала дизайнерами миллионы обычных граждан. Позволяя "обрабатывать события", JavaScript помог тысячам дизайнеров стать настоящими программистами. Гарантом подобности Web-программирования и разработки сложных приложений является браузер Mozilla, в котором все элементы графического интерфейса и даже некоторые специальные элементы, а также программные модули полностью управляются средствами JavaScript, каскадных таблиц стилей (CSS), специальных языков, созданных на основе XML. JavaScript является общим языком, применимым даже вне среды HTML и XML. Он поддерживается многими серверами, инструментальными средствами автоматизации, надстройками браузеров, а также браузерами других типов (это касается даже таких, казалось бы, "отстраненных" концепций как, например, управление трехмерным текстом). Соответствующим международным стандартом является ЕСМА-262 (ISO 16262), он уже доработан до третьего издания. Но, по сравнению с такими язьпсами, как Perl или даже Java, он все еще относительно молодой. Работа в рамках технического комитета ЕСМА над четвертой версией, в которой должны поддерживаться типы, классы, а также средства организации разработки новых поколений программных Предисловие 25
средств, идет полным ходом (посмотрите документацию в разделе JS2 на узле технической поддержки комитетаЕСМА по адресу http: //www.mozilla. org/ j s/language/j s20/). Совершенно очевидно, по крайней мере для меня, что JavaScript не удержался бы на плаву без продуктивной, лояльной и терпеливой поддержки консорциума разработчиков. Должен выразить им свою искреннюю признательность. Те из них, кто тестировал бета-версию Netscape Navigator 2, распространял в виде почтовых сообщений и сообщений групп новостей жизненно важные доработки и затрагивал ключевые вопросы, по праву могут считаться крестными родителями языка. Поддержка разработчиков и постоянная обратная связь с конечными пользователями способствует заслуженному успеху JavaScript. Книга, которую читатель держит в своих руках, является результатом тех "бессонных ночей", через которые прошли разработчики языка, опытные эксперты и преподаватели. Дэнни не мог и предположить, какое впечатление произведет на меня его книга о HyperCard, Именно она была моим настольным пособием в процессе создания JavaScript в 1995 году. Его энергия, участие и легкость изложения материала помогли мне удержаться в русле создания языка "для всех". Поэтому чрезвычайно приятно писать предисловие к пятому изданию этой книги, которая стоит проведенных им "бессонных ночей". Настоятельно рекомендую всем, кто хочет освоить JavaScript, прочитать книгу Дэнни Гуд- мана JavaScript, Библия пользователя. Особенно это относится к тем, кто работает с HTML и успел "набросать" несколько сценариев или программ, — у вас есть уникальная возможность пройти по тернистой дороге создания сценариев вместе с опытным проводником и учителем. Брендан Эйх The Mozilla Organization (http: //www.mozilla.org) 26 Предисловие
Введение Примерно 20 лет назад я написал книгу, о которой давно думал и которая должна была помочь мне освоить новую технологию. Я всегда старался вникнуть в основы новых программных средств и средств разработки, почувствовать растущие достижения и разделить с читателями плоды своего труда. Пятое издание книги JavaScript Библия пользователя призвано донести до читателя те знания и опыт, которые были наработаны в течение пяти лет каждодневной работы в JavaScript и постоянного поиска в группах новостей каверзных вопросов, нерешенных проблем и другого, достойного внимания разработчика сценариев. Моя цель— помочь читателю избежать тех разочарований и мучительной головной боли, которые в свое время испытал не только я сам, но и многие другие, кто работал с различными поколениями браузеров. В то время как предыдущие издания этой книги были, в основном, ориентированы на доминирующие в то время браузеры Netscape Navigator, современные тенденции развития браузер- ных технологий все больше указывают на преобладание Microsoft Internet Explorer. В то же время, Netscape удалось завершить превосходную задачу по восстановлению собственного браузера в свете быстрого развития стандартов индустрии. Как результат этих тенденций, существенно пересмотренное и расширенное пятое издание книги в равной степени ориентировано на оба типа браузеров как на эквивалентные технологии, которые вполне соответствуют приоритетам пользователей. Читатель столкнется с моими положительными отзывами или критикой разных версий браузеров и поддерживаемых ими технологий. Но мое самое страстное желание, на самом деле, — это научить читателя создавать документы и разрабатывать производительные сценарии, эффективно выполняемые в любой версии браузера. Поэтому данная книга содержит детальное описание специальных и стандартных методов, позволяющих решать любые поставленные задачи. По моему мнению, это именно то, что больше всего волнует читателей. На случай, если вы усмотрите в этой книге спорные моменты, то не забывайте о том, что создаваемые сценарии должны выполняться в максимально возможном числе браузеров. Структура и особенности этого издания Подобно предыдущему изданию, настоящее пятое издание книги JavaScript. Библия пользователя содержит намного больше информации, чем можно поместить даже в самую толстую книгу по JavaScript. Полная версия приведена на компакт-диске (в электронном виде), прилагаемом к этой книге. Обновленное издание книги лучше структурировано (это в основном касается информации, представленной в бумажной части книги). В частности, все листинги кодов, которые ранее можно было найти только в виде материалов на компакт-диске, теперь вставлены в текст книги в местах его непосредственного описания. В бумажную часть книги вынесены все главы, в которых рассматриваются основы языка и фундаментальные принципы программирования на JavaScript. В электронных главах книги на компакт-диске описаны узкоспециализированные методы разработки сценариев на JavaScript. Ниже речь пойдет о структурных особенностях книги. '
Часть I. Знакомство с JavaScript Часть I этой книги начинается с главы, в которой продемонстрированы связи JavaScript с Java и определяется их роль в World Wide Web. С того момента, как на рынке Web-технологий впервые появился JavaScript, в браузерах Web и среде создания сценариев произошли существенные изменения. Поэтому глава 2 посвящена тем изменениям, которые наиболее существенным образом влияют на методы создания сценариев и в большей степени определяют быстро изменяющиеся стандарты приложений, поддерживаемые разными браузерами. В главе 3 вы совершите первое знакомство с основами JavaScript; после ее изучения вы сможете самостоятельно создать первый в своей жизни сценарий. Часть II. Руководство по JavaScript Часть П полностью посвящена наставлениям для начинающих программистов на JavaScript. В ней приведено девять уроков, позволяющих читателю последовательно изучить внутреннюю структуру браузера, освоить навыки программирования и ознакомиться с основными принципами JavaScript. С помощью всего нескольких явно описанных элементов языка в этих уроках на высоком профессиональном уровне рассматривается весь диапазон принципов создания сценариев, выполняемых во многих браузерах, которые поддерживают технологию JavaScript В конце каждого урока приведены упражнения, которые позволяют закрепить полученные знания и проверить качество их освоения читателем. Вы также сможете попрактиковаться в использовании изученных средств (ответы приведены в приложении В). Цель этого учебного пособия — научить читателя создавать простые страницы еще до того момента, как дело дойдет до подробного рассмотрения сложных примеров, приведенных в конце книги. В последнем уроке части вы узнаете, как управлять многофреймовыми документами и создавать эффекты ролловеров — изображений, изменяющихся при наведении на них указателя мыши. Часть III. Объекты документа Часть Ш — это наибольшая часть книги, которая посвящена всестороннему освещению объектных моделей документа, реализуемых в браузерах и обеспечивающих до настоящего времени средства создания динамических документов. Во всех справочных разделах совместимость описываемых средств JavaScript с разными версиями браузера задается в специальной таблице. В главе 15 приведен справочный материал, который используется практически во всех остальных главах части Ш. Часть IV. Объекты языка JavaScript В части IV приведена справочная информация по базовому языку JavaScript. Как и в части Ш, будут представлены таблицы совместимости браузеров с описываемыми средствами языка JavaScript. Ключевые слова в нижней части страниц помогут читателю быстро отыскать нужный термин, описываемый на странице. Часть V. Приложения Несколько приложений, приведенных в конце книги, предоставят довольно важный спра- вочйый материал. В них включена справка по JavaScript и объектам браузера (приложение А), список зарезервированных в JavaScript слов (приложение Б) и ответы на упражнения части П (приложение В). В приложении Г представлен список Internet-ресурсов, посвященных JavaScript, а в приложении Д описано содержимое компакт-диска и электронных глав книги. 28 Введение
Прилагаемый компакт-диск Прилагаемый к книге компакт-диск — это кладезь полезной информации. На диске вы найдете все главы дополнительной части VI, представленной только в электронном виде. В этих главах рассмотрены следующие вопросы. ■ Специальные объекты DOM, XML и JavaScript. ■ Возможности DHTML, методы проверки данных и защита сценариев. ■ Методы разработки и отладки профессиональных Web-приложений. ■ Девять полноценных приложений JavaScript, используемых в реальной жизни. Более того, на компакт-диске, прилагаемом к книге, содержится электронная версия настоящей книги (на английском языке, в формате PDF). Вы также найдете на нем огромное количество готовых к использованию HTML-документов, которые послужат примером создания Web-страниц в большинстве объектных моделей документа. Все они созданы с использованием зарезервированных слов JavaScript и методов, описанных в частях Ш и IV настоящей книги. Эти примеры можно запускать непосредственно в браузере, по умолчанию поддерживающем JavaScript. Однако обязательно убедитесь, что в папке листингов (как шлюз для их запуска) используется страница index.html. Эта страница определяет те браузеры, которые совместимы с приведенными в папке листингами. Она содержит немного информации, но ознакомиться с ней перед запуском остальных сценариев советуем всем пользователям. Просмотр полноценных HTML-документов (даже достаточно простых) просто необходим для полного усвоения всех описанных в книге принципов. Листинги из учебного раздела этой книги (часть П) умышленно опущены, чтобы привлечь читателя к самостоятельному написанию сценариев. Вы многому научитесь, даже просто вводя листинги, приведенные в книге, — стоит только начать. На компакт-диске представлены листинги из частей I и V. Не забудьте проверить палку с листингами для главы 13. Эта папка содержит весьма интересный файл evaluator. html, созданный специально для этой книги. Читатель может познакомиться с результатом использования этого приложения на практике, чтобы получить детальные сведения о его эффективности. Справочное руководство из приложения А также представлено на диске в формате . pdf. Это позволяет распечатать его и использовать в качестве настольного пособия. На диске также содержится программа Adobe Acrobat Reader, позволяющая просматривать содержимое файлов в формате . pdf. Наконец, для упрощенного поиска на диске в том же формате представлен текст всей книги. Что потребуется для изучения JavaScript Для чтения этой книги совсем не обязательно иметь опыт программирования, однако чем больше читатель создал с помощью HTML Web-страниц, тем легче ему будет понять, как JavaScript взаимодействует с разными программными элементами, размещенными на странице. Иногда, чтобы ощутить все прелести написания сценариев, придется несколько видоизменять HTML- дескрипторы. Если вам ранее приходилось работать с этими дескрипторами, то изучение новых особенностей, добавляемых JavaScript, не представит для вас особых сложностей. В большинстве стандартных разработок JavaScript формы и их элементы (текстовые поля, кнопки и списки выбора) играют особенно важную роль. Читателю стоит внимательно ознакомиться с этими элементами и их атрибутами в HTML. К счаствю, вам не потребуется разбираться в тонкостях составления серверных сценариев и способах отправки информации с формы на сервер. В данном случае основной акцент сделан на написании Введение 29
сценариев, выполняемых на стороне клиента (после полной загрузки браузером, поддерживающим JavaScript, в составе страницы они управляются независимо от сервера). Вам также потребуются знания основных стандартов HTML. Например, при описании основ управления фреймами, главный упор делается на написании сценариев для соответствующих структурных элементов, а не на методах оформления с их помощью готовых страниц. Более детально данная тема описана в документации от Microsoft, Netscape и т.п. Для тех, кому не приходилось программировать Если вы изучали азы работы в HTML несколько лет назад по тоненькому справочнику, то размеры этой книги могут вас просто испугать. Может быть, JavaScript далеко не самый простой для изучения язык в мире, но, вне всяких сомнений, он ни в какое сравнение не идет с такими фундаментальными средами программирования, как Java или С. В отличие от разработки завершенных приложений (которые практически каждому из вас приходилось приобретать на компакт-дисках), с помощью JavaScript можно экспериментально создавать небольшие фрагменты программного кода, используемые в качестве компонентов более сложных программ. Интерпретатор JavaScript, который встроен во все браузеры, поддерживающие сценарии, выполнит за вас большую часть черновой работы. Программирование заключается в создании серии инструкций для выполнения их компьютером. Если проводить аналогию с повседневной жизнью, то люди постоянно следуют инструкциям, даже если сами этого не подозревают. Путешествие к дому друга является примером следования последовательности несложных инструкций: пройти три квартала в одном направлении; возле аптеки повернуть налево; после прохождения ее повернуть направо. Выполняя эти инструкции, вам приходится принимать определенные решения: если на светофоре горит красный свет, то нужно остановиться; если — зеленый, то можно идти; если — желтый, то следует приготовиться к движению или остановке. Время от времени некоторые действия приходится повторять по несколько раз (как, например, хождение по улицам в поисках заветной аптеки). Программа для компьютера содержит не только последовательность основных действий, но и предопределяет, какие решения принимать или какова повторяемость действий (как, например, реагировать на сигналы светофора или как вести себя в случае, если рядом расположено две аптеки) для достижения целей, стоящих перед программой. Первым препятствием на пути к освоению азов программирования является та точность, с какой в языках программирования представлены в инструкциях слова и числа. Соответствующие правила (как и в обычных языках) определяют синтаксис языка программирования. Хотя современные компьютеры являются весьма производительными, по своей натуре они до безобразия точны. Поэтому они не очень-то прощают, когда с ними разговаривают на непонятном для них языке. Если вы, разговаривая с другим человеком, допускаете в предложении стилистические ошибки, то вы все же, рассчитываете, что собеседник вас полностью поймет. В большинстве случаев так и происходит. Совсем иначе дело обстоит с компьютерами. Если синтаксис не является идеальным (или, по крайней мере, не отклоняется от стандарта в пределах очевидной корректировки), компьютер самым нахальным образом заявит, что вами допущена синтаксическая ошибка. Оптимальным вариантом в такой ситуации является изучение допущенных синтаксических ошибок. Ведь даже самые опытные программисты делают ошибки. При таком подходе каждая допущенная синтаксическая ошибка добавляет знаний и опыта в программировании на используемом языке. Тем, кто уже немного программировал Наличие опыта работы с такими процедурными языками программирования, как BASIC или Pascal, может, скорее, вызвать головную боль, чем помочь в изучении JavaScript. Вы можете иметь достаточно полное представление о синтаксисе языка, однако важно и то, что зо Введение
общая концепция выполнения программ в этих языках радикально отличается от принятой в JavaScript. Частично это определяется обычными задачами, решаемыми с помощью сценариев (программирование действий в ответ на выполняемые пользователем манипуляции на странице Web). Однако большой объем работы реализуется посредством объектно-ориентированного программирования. В типичной программе с использованием процедур программист непосредственно несет ответственность как за то, что появляется на экране, так и за те действия, которые непосредственно выполняются программой. При первом запуске программы огромная часть кода предназначена для того, чтобы определить графическую среду. На экране при этом может располагаться несколько текстовых полей и кнопок. Чтобы определить, на какой кнопке щелкнул пользователь, программа должна знать координаты точки, на которой был выполнен щелчок, а затем сравнить эти координаты на совпадение с координатами одной из кнопок на экране. В зависимости от того, какая кнопка используется, выполняются заранее определенные для текущего случая инструкции. Объектно-ориентированное программирование представляет собой нечто совершенно противоположное. Кнопка интерпретируется как объект — вещь вполне реальная. Объект имеет свойства (надпись, размер, событие и т.п.). Объект также может содержать сценарий. В то же время, системные программы и браузеры могут посылать объекту сообщения — в зависимости от того, что делает пользователь, —1 для запуска сценария. Например, если пользователь щелкает мышкой на записи текстового поля, то система или браузер сообщает полю, что кто-то щелкает там (это значит, что данное поле активизируется), передавая полю полномочия по поводу принятия решения, что ему следует делать в ответ на такое действие. Именно здесь в силу вступают сценарии. Сценарий связан с полем и содержит инструкции, которые выполняются при активизации поля. Другой набор инструкций может использоваться для контроля данных, вводимых пользователем в поле, или на вкладке, или в результате щелчка на опции. Некоторые из создаваемых сценариев по своей структуре могут напоминать процедуры: они содержат простые инструкции, которые поочередно выполняются. Однако когда вы перейдете к управлению данными формы, то поймете, что инструкции JavaScript выполняются исключительно как объектно-ориентированные. Каждая форма является объектом. Это же относится ко всякому элементу управления (например, переключателю или текстовому полю). В этом случае для выполнения запланированной работы сценарий вызывает свойства соответствующих объектов. Переход от процедурного к объектно-ориентированному программированию может быть самым трудным моментом в обучении пользователя. Когда несколько лет назад мне самому пришлось столкнуться с объектно-ориентированным программированием, не могу сказать, что у меня все получилось. Но когда я во всем разобрался (а в этом мне помог напряженный и ответственный труд), в моей голове появилось столько "грандиозных" идей, что, я уверен, буду реализовывать их еще много лет. С тех пор я полностью уверен, что объектно-ориентированное программирование является единственным целесообразным способом написания программ. Тем, кто программировал на С По причине занудности синтаксиса Java (который, кстати сказать, походит от С и C++), в JavaScript можно найти много синтаксических характеристик С. Поэтому знакомые с языком С программисты будут чувствовать себя, как рыба в воде. Символы операторов, условные конструкции и циклы выдержаны исключительно в традициях С. При этом в JavaScript, по сравнению с С, можно меньше беспокоиться о типах данных. В JavaScript задаваемые переменные не ограничены конкретным типом данных. Поскольку очень многое в синтаксисе JavaScript будет вам знакомо, тд сконцентрируйтесь на концепциях объектной модели документа, что является абсолютно новым понятием для С-программиста. Кроме того, для реализации своих навыков в JavaScript на практике советуем основательно изучить HTML (особенно это касается дескрипторов элементов форм). Введение 31
Для тех, кто работал в Java Несмотря на очень похожие названия, данные языки имеют только поверхностное сходство. Это касается организации циклов и условных конструкций, обращения к объектам с использованием точки (как это делается в С), фигурных скобок для выделения групп, некоторых ключевых слов и ряда других атрибутов. Что же касается объявления переменных, то они совершенно различны. Такая ситуация имеет место по той причине, что JavaScript в этом смысле является достаточно прогрессивным языком. Переменная может содержать целочисленное значение с одной стороны оператора сравнения и строчные данные — с другой (хотя это и не всегда хорошо). В тех случаях, когда Java обращается к чему-то как к методу, JavaScript вызывает методы (когда они связаны с предопределенным объектом) или функции (для определенных в сценарии действий). Методы и функции JavaScript могут возвращать значения любых типов без предварительного их объявления. Возможно, при работе с JavaScript наиболее важным наследием Java является объектно- ориентированное представление о классах, наследовании, экземплярах и передаче сообщений. Эти понятия при написании сценариев просто неактуальны. Тем не менее, JavaScript-дизайнеры хорошо знают, что всегда нужно подстраховываться. Например, хотя в JavaScript и не требуется в конце каждой строки ставить точку с запятой, однако, если в исходном коде JavaScript пароч- ка-другая их все же 'тфоскакивает", то интерпретатор JavaScript от этого хуже работать не станет. Тем, кто писал сценарии и макросы Опыт создания сценариев с помощью других средств программирования или макросов в прикладных программах является хорошей основой при освоении всевозможных концепций JavaScript. Наиболее важной из них, пожалуй, является концепция комбинирования действий или обработки данных определенного типа с помощью нескольких операторов. Например, в Microsoft Excel можно написать макрос, который будет выполнять преобразование данных финансовых отчетов, поступающих из другого компьютера, для отображения в виде диаграмм. Макрос встраивается в меню Макрос, и запускать его нужно, выбрав соответствующую опцию меню, независимо от того, когда поступают новые показатели. Более сложные сценарии, который можно создать с помощью Toolbook или HyperCard, максимально соответствуют объектно-ориентированной концепции JavaScript. В этих средах объекты экрана содержат сценарии, которые выполняются при взаимодействии пользователя с этими объектами. Большое число создаваемых в JavaScript сценариев будут выдержаны в рамках описанной ниже концепции. Фактически, эти среды напоминают оболочку выполняющего сценарии браузера, обеспечивая использование набора предопределенных объектов, которые имеют фиксированные свойства и атрибуты. Эта предопределенность применяется для строгого определения характеристик всей среды, а потому способствует более эффективному и производительному выполнению приложений. Соглашение о представлении данных и имен Листинги сценариев и их фрагменты представлены в этой книге специальным шрифтом. Это сделано для того, чтобы облегчить их поиск на фоне остального текста. По причине ограниченности ширины страниц строки в листингах иногда будут неестественным образом прерываться. В этих случаях разорванная строка продолжается на следующей строке, как это делается в текстовом редакторе при переносе слов. Если при введении сценария из-за этого у вас возникают проблемы, можно воспользоваться этим же сценарием, размещенным на компакт-диске, прилагаемом к книге. Когда читатель доберется до части Ш книги, может оказаться, что дальше, чем на одну страницу после описания объектных моделей или средств языка, требующих определенной 32 Введение
версии браузеров, ему продвинуться не удается. Чтобы указать, какой же в данном случае необходим браузер и его версия, используется двухсимвольная система аббревиатур с указанием числовой версии. Например, ГЕ5 означает Internet Explorer 5 для всех операционных систем, a NN6 означает Netscape Navigator 6, опять же, для всех операционных систем. Если сценарий или отдельное средство поддерживается определенной версией браузера и всеми последующими версиями, то после номера версии стоит знак (+). Например, если средство помечено как ГЕ4+, то это означает, что для его поддержки вам потребуется как минимум Internet Explorer 4, но средство совместимо и с ГЕ5, и с ГЕ5.5 и т.д. Случается, что средство или некоторый атрибут применим только в определенной операционной системе. К примеру, если для средства использована пометка WinIE4+, то это значит, что оно выполняется в Internet Explorer версии 4 и выше, но только в Windows. Как пример ссылок, первыми работающими со сценариями браузерами были NN2, WinIE3 и МасГЕЗ.01. Эти условные обозначения в первую очередь можно увидеть на сравнительных диаграммах в справочных разделах. / Пиктограммы "На заметку", "Совет" и "Внимание" время от времени появляются в книге для отображения наиболее важных моментов. Благодарности Конечно, такую толстенную книгу, которую вы держите в своих руках, мне никогда не удались бы написать самостоятельно за те короткие сроки, которые устанавливаются конъюнктурой рынка печатных изданий. JJ процессе изучения терминологии и подготовки обучающих примеров к этой книге мне приходилось неоднократно консультироваться с Майклом Моррисоном — таким же автором, как и я сам. С его помощью проект приобрел тот вид, который имеет сейчас. Технический редактор Дэвид Уолл на протяжении многих лет занимается подготовкой книги JavaScript. Библия пользователя к изданию, на что у него уходит очень много сил и почти все рабочее время. Хотелось бы также отметить и многих других сотрудников Wiley Publishing, принимавших участие в написании и подготовке к печати этой книги. Среди них Дебра Вильяме Коли, Мэри Бет Уэйкфилд и Анжела Смит. И наконец, я искренне признателен всем тем читателям предыдущих изданий книги, которые принимали активное участие в ее обсуждении: присылали электронные письма, в которых выражали свои замечания и пожелания. Ваш опыт работы с JavaScript оказался просто неоценим! Введение 33
Ждем ваших отзывов! Вы, читатель этой книги, и есть главный ее критик и комментатор. Мы ценим ваше мнение и хотим знать, что было сделано нами правильно, что можно было сделать лучше и что еще вы хотели бы увидеть изданным нами. Нам интересно услышать и любые другие замечания, которые вам хотелось бы высказать в наш адрес. Мы ждем ваших комментариев и надеемся на них. Вы можете прислать нам бумажное или электронное письмо либо просто посетить наш Web-сервер и оставить свои замечания там. Одним словом, любым удобным для вас способом дайте нам знать, нравится вам эта книга или нет, а также выскажите свое мнение о том, как сделать наши книги более интересными для вас. Посылая письмо или сообщение, не забудьте указать название книги и ее авторов, а также ваш обратный адрес. Мы внимательно ознакомимся с вашим мнением и обязательно учтем его при отборе и подготовке к изданию последующих книг. Наши координаты: E-mail: info@dialektika.com WWW: http://www.dialektika.com Адреса для писем: из России: 115419, Москва, а/я 783 из Украины: 03150, Киев, а/я 152
Знакомство с JavaScript
Роль JavaScript в World Wide Web llmJ/ll ногие современные технологии, которые сделали И V И возможным само существование World Wide Web, давно превзошли возлагавшиеся на них первоначально надежды. Вначале Web разрабатывалась как сетевая среда управления статическими текстами и изображениями. Она постоянно улучшается, изменяется и популяризируется разработчиками Web-технологий. Ради достижения поставленных целей разработчики идут на любые ухищрения, берутся за выполнение самой "грязной работы" по установке соединений и перекачке битов данных между серверами и компьютерами клиентов, а в минуты отчаяния, вместе с пользователями, по-доброму мечтают о тех временах, когда возможности соединений позволят, наконец, поддерживать новые приложения с системно- независимой платформой, которые не будут иметь ограничений на расширение и использование ресурсов Web. He является удивительным и тот факт, что сообщество разработчиков взяло под серьезный контроль права собственности на новые технологии и использует их для создания поистине удивительных вещей. Паутина Web обладает огромной популярностью. Кроме того, к высоким технологиям имеет доступ каждый обычный, даже начинающий, пользователь. Среди обычных пользователей есть немало таких, чьи интригующие и беспрецедентные выдумки способствуют превращению Web из слабой издательской среды в высоко интерактивную, системно- независимую среду разработки программных средств. Примером современных технологий в Web является язык JavaScript. После внедрения в компьютер клиента этот язык может превратить страницу со статическим содержимым в привлекательный, интерактивный и весьма разумный документ. Приложения (они же сценарии) JavaScript при этом могут быть настолько вежливыми, что будут приветствовать новых посетителей узла словами "Доброе утро!", если в часовом поясе, в котором расположен компьютер клиента, сейчас утро (даже несмотря на то, что в часовом поясе, в котором расположен сервер, полдень или полночь). Приложения JavaScript позволяют сделать Web-страницы нагляднее. Например, при
создании презентации, которая отображается в виде слайд-шоу, JavaScript управляет последовательностью транзакций по скрытию, отображению отдельных слайдов и другими динамическими эффектами. Конечно, JavaScript не единственный способ вдохнуть жизнь в безжизненные статические объекты в Web. Поэтому важно понимать, на каком именно уровне происходит взаимодействие JavaScript с различными стандартами, программными средствами и другими технологиями. Альтернативными технологиями, описываемыми в этой главе, являются HTML, серверные приложения, надстройки и программные модули, а также аплеты Java. В большинстве случаев JavaScript совместим со всеми перечисленными технологиями на самом высоком уровне. Уповать на абсолютность совместимости JavaScript с другими средствами все же не стоит, хотя случаи сбоев наблюдаются весьма редко. В этой книге вы узнаете об истоках развития JavaScript и той роли, которую он играет в среде современных браузерных технологий. Конкуренция в Web Нет большего счастья для создателей Web-страниц, чем увеличивающееся количество посетителей их узла. Независимо от качества содержимого Web-страницы, можно, безо всякого сомнения, утверждать, что узел, который в течение недели регулярно посещают порядка 10 000 раз, популярнее, чем тот, который за это же время посетили всего 1000 раз. Даже если точное число посетителей неизвестно, относительную популярность при желании всегда можно установить. Заинтересовать посетителей к частому посещению узла — это первейшая задача Web-разработчика. Примеров жесткой конкуренции в Web можно привести огромное количество. Речь идет не только о конкуренции в Web, подобной той, что имеет место на телевидении (где количество каналов достаточно велико, поэтому даже при всем своем желании и технических возможностях ни один из телезрителей не сможет просмотреть их все за всю свою жизнь). Пользователи развлекательных программ, мультимедийных энциклопедий, экзотических представлений, которые исходно создаются максимально привлекательными, уже привыкли к высококачественным эффектам и первокласснейшим презентациям. Чаще всего описанные выше проекты не обходятся без насыщенных графических изображений, анимации, потоковых видеоклипов и загружаемых звуковых эффектов. В отличие от описанного выше, стандартные HTML-страницы мало чем могут порадовать пользователя, избалованного качественным представлением информации. Даже с учетом последних достижений и разработок в области динамического HTML и каскадных таблиц стилей, размещение статических рисунков даже на форматированном тексте предоставляет ограниченное количество возможностей дизайнерам, по сравнению с тем, что предлагают настольные издательские системы, с которыми вам, возможно, уже приходилось сталкиваться. Независимо от качества содержимого документов, созданных в издательских системах, они красочнее и представительнее даже самых качественных "старомодных" HTML-документов. Интерактивность последних, в лучшем случае, обеспечивается ограниченным набором ссылок и формами, содержимое которых после заполнения данными все равно исчезает в пучинах Web-серверов. Другие Web-технологии При наличии такого большого набора возможностей для внесения разнообразия на Web- страницы конкуренты, пытающиеся "отбить" потенциальных посетителей, во что бы то ни стало пытаются перещеголять чужой узел. Даже те организации, которые поставляют эксклюзивную информацию высокого уровня востребованности, находятся в постоянном напряжении, изобретая новые методы, позволяющие привлечь как можно большую часть аудитории. Для Глава I Роль JavaScript в World Wide Web 37
тех, кто обеспечивает Web-структуру корпоративных локальных сетей, это соперничество выражается в постоянном повышении продуктивности и качества работы по сравнению с теми коллегами, которые используют для выполнения этих же задач внешние Web-узлы. Все описанные выше причины должны побудить вас к стремлению использования максимального количества Web-технологий для создания привлекательных Web-страниц, качественна и информативно выделяющихся на фоне остальных проектов. Теперь самое время обратиться к основным положениям, которые следует знать каждому Web-дизайнеру. Что такое HTML Язык HTML (Hypertext Markup Language — язык гипертекстовой разметки), который происходит от SGML (Standard Generalized Markup Language — стандартный обобщенный язык разметки), рассматривается, в основном, исключительно как язык форматирования или разметки документов (заключения данных в дескрипторы). Дескрипторы (это то, что находится внутри символов <>) используются для задания инструкций программе просмотра документов (браузеру или клиентской программе), в которых детально описывается способ отображения текстовых фрагментов и рисунков на экране. Низведение HTML к категории языков разметки позволяет с его помощью не только оформлять высококачественные Web-страниц, но и обеспечивать интерактивное взаимодействие с пользователями. Согласно некогда популярной точке зрения, все наборы команд и другие синтаксические правила, предназначенные для организации управления цифровыми данными, относятся исключительно к программированию. При использовании HTML автор Web-страницы задает сферу влияния пользователя на данные (содержимое страницы) точно так же, как программисты, создавшие Microsoft Excel, позволяют пользователям процессора баз данных изменять содержимое таблиц и выполнять функции обработки числовых данных. В последних усовершенствованиях стандартов HTML (HTML 4 и выше) сделана попытка сузить область абсолютного влияния HTML на содержимое документов и передать форматирование внешним подключаемым средствам, например, таблицам стилей. Другими словами, HTML не должен определять, какой текстовый фрагмент выделить курсивным начертанием, — следует указать фактор, определяющий фрагменты, которые необходимо выделить курсивом. Например, с помощью дескрипторов можно задать подчеркивание фрагмента текста, независимо от того, что задает такое начертание, — таблица стилей или используемый браузер. XHTML— это самая совершенная версия языка HTML, которая включает в себя поддержку стилистических соглашений, принятых в XML (extensible Markup Language — расширяемый язык разметки документов). В HTML вы найдете новые дескрипторы, хотя основные принципы их применения для задания форматирования документов остаются прежними. Серверные сценарии Один из способов повышения эффективности работы по управлению пользователем содержимым страницы — это установление соединения с Web-сервером, который обслуживает страницу. Предназначение серверных сценариев — самое широкое, начиная с проверки введенного имени пользователя и пароля и до задержки выполнения определенного действия. Написание специальных серверных сценариев обычно требует навыков программирования. Ряд таких сценариев создается с использованием фундаментальных языков программирования — Perl, Python, Java, С или C++. Вам не удастся самостоятельно создать серверные приложения, если вы не знакомы с такими технологиями, как PHP, ASP, .Net, JSP и Coldfusion. Очень немногие серверы позволяют выполнять серверные сценарии, написанные на JavaScript. Независимо от того, какой язык используется для написания серверного сценария, решение поставленной перед ним задачи требует обязательного вмешательства разработчика Web- 38 Часть I. Знакомство с JavaScript
страницы или администратора Web-сервера, которые настраивают вспомогательные программы (подобные базам данных), применяемые для обработки поступающей информации и сохранения готовых данных. Даже при наличии новых средств разработки, ориентированных на поддержку Web-сервера, создание CGI-сценариев для привыкших к стилю простого форматирования документов с помощью HTML-дизайнеров — это сложнейшее задание, для решения которого потребуется опыт профессионального программиста. Настолько же интересной и полезной, как написание сервером сценариев, является задача обработки сервером запросов. Полностью загруженный сервер может обрабатывать одновременно сотни сценариев. При этом компьютеры клиентов (персональные компьютеры, в которых запускаются браузеры) откровенно "ггоостаивают", отображая простенькую анимацию или даже статическое изображение в ожидании обработанных данных. Это негативно сказывается на эффективности работы конечного компьютера, особенно если запущенный на сервере процесс не требует получения доступа к большим базам данных или другим внешним ресурсам. Вспомогательные приложения и надстройки На ранних этапах развития World Wide Web перед браузером ставилась задача отображать только небольшое количество типов данных. Вся система по форматированию текста (заключенного в дескрипторы HTML) и рисунков (представленных в таких популярных форматах, как GIF и JPEG) была встроена в браузер и предназначалась для управления исключительно операционной системой настольного компьютера. Ограниченные числом используемых типов данных разработчики приложили немало усилий, чтобы добиться расширения возможностей браузеров клиентов по обработке данных, представленных в других форматах. Тогда казалось несбыточной мечтой, что когда-нибудь удастся создать браузер, которьш сможет загружать и обрабатывать, скажем, звуковые файлы хотя бы в одном из существующих форматов. Одним из способов решения данной проблемы было разрешение на использование в браузере системы определения типа данных входящего файла и запуска в компьютере клиента специальных приложений, обеспечивающих обработку его содержимого. Если такое вспомогательное приложение установлено на компьютере клиента (а в браузере указано использовать его для открытия файлов определенного типа данных), то браузер сможет запустить нужную программу и переслать ей входящий файл. В этом случае можно для воспроизведения звуковых МШ1- файлов использовать одно вспомогательное приложение, а для файлов в формате WAV — другое. Начиная с Netscape Navigator 2 (начало 1996 года), применение в браузерах программных надстроек позволило разработчикам расширить возможности браузеров без всякой необходимости внесения существенных изменений в их исходный код. В отличие от вспомогательных приложений, с помощью надстройки (или внедряемого модуля) можно реализовать плавное перемещение содержимого файла в HTML-документ. Наиболее распространенный пример надстройки — это программные модули, которые используются для воспроизведения звуковых и видеоклипов, расположенных на сервере. Музыка теперь повсеместно включается на страницы для фонового воспроизведения в процессе загрузки и отображения документа. Это же относится и к воспроизведению потокового звука, который чем-то сродни радиотрансляции. Видеоклипы и анимация тоже вполне могут отображаться на странице. При их воспроизведении с помощью надстроек браузер принимает минимальное участие. В современных браузерах отмечается тенденция к массовому использованию надстроек, позволяющих производить декодирование звуковых файлов большинства существующих типов. Разработчики надстроек для Internet Explorer, запускаемого в Windows, обычно реализуют программные модули в виде средств управления ActiveX. Хотя разница в реализации надстройки важна с точки зрения поддержки операционной системой, для конечного пользователя она несущественна Глава 1. Роль JavaScript в World Wide Web 39
Надстройки и вспомогательные приложения могут использоваться не только для воспроизведения звука и видеоклипов. Популярное вспомогательное приложение — Adobe Acrobat Reader, которое отображает файлы, отформатированные в таком виде, в каком они выводятся на печать, — стало незаменимым помощником не только дизайнеров, но и рядовых пользователей. Для обеспечения красочности и интерактивности разработчики все чаще обращаются, к надстройке Flash компании Macromedia. Созданные с использованием специализированной программной среды Macromedia Flash документы в формате Flash могут содержать интерактивные области, реагирующие на щелчки мышью, а также перемещаемые элементы. Некоторым авторам даже удается реализовать во Flash художественные видеоигры и мультфильмы. Браузеры, оснащенные надстройками Flash, отображают данные в прямоугольной области, вставленной на страницу. Один из недостатков создания интерактивных объектов разработок во Rash или другой подобной среде заключается в невозможности отображения их в браузере, в котором не установлена соответствующая надстройка. Кроме того, на загрузку анимации тратится больше времени, чем на загрузку других объектов, вставленных на страницу. В результате после установки надстройки загрузка клиентом высококачественной анимационной графики и других данных (особенно при автоматическом соединении) может занять намного больше времени, чем рассчитывали пользователи. Это один из тех случаев, когда приходится выбирать между художественными изысканиями и стремлением предоставить пользователю максимум интерактивности. Еще одна технология, запускаемая на стороне клиента, — аплеты Java — была весьма популярна в начале 1990-х годов, но по многим причинам (техническим, экономическим, внутрикорпоративным и т.д.) она утратила свою привлекательность. Но это никоим образом не сказалось на популярности языка Java при написании серверных приложений и даже программ, запускаемых в современных мобильных телефонах. Этот язык уже давно перестал быть достоянием разработавшей ее компании — Sun Microsystems. JavaScript: язык для всех Истоки языка Java — в С и C++, полностью завершенной среде программирования. Используют его, в основном, опытные программисты. Когда я впервые обратился к изучению спецификации Java, это вызвало просто недоумение. Мне больше бы подошел язык, который легко мог освоить каждый — от программиста-любителя до создателя сценариев, свободно владеющего графическими программными средствами (например, Apple HyperCard и Microsoft Visual Basic). Появление подобных средств для разработчика способствовало бы тому, что армия непрофессиональных и неопытных программистов сразу же создала бы немало незамысловатых, но чрезвычайно действенных приложений, решающих узконаправленные, специфические задачи, над которыми профессионалы не станут ломать себе голову. Большие дела часто начинаются с решения очень частных нужд. И начинаются они в классной комнате, офисе, чулане или даже гараже. Однако все это не относится к Java. Подобные размышления повторно возникли в моей памяти несколькими месяцами позже, в ноябре 1995 года, когда я услышал о проекте создания языка написания сценариев для браузеров Netscape. Этот язык, вначале названный LiveScript, разрабатывался параллельно с программным обеспечением для Web-сервера Netscape. Язык имел единый синтаксис и должен был служить двум целям. Первой целью было создание такой среды разработки сценариев, которую администраторы Web-серверов могли бы использовать для управления работой сервера и подключения к другим службам — удаленным базам данных и средствам поиска информации. Расширив марку "действенного" (т.е. "Live") в названии, Netscape стала использовать термин LiveWire для обозначения среды JavaScript, применяемой сервером для подключения к базам данных. С точки зрения клиента (в рамках HTML-документов), разработчики для улучшения Web- страниц теперь могли самыми различными способами использовать сценарии, написанные 40 Часть I. Знакомство с JavaScript
с использованием этого нового языка. Например, с помощью LiveScript разработчик мог проконтролировать, соответствует ли вводимая пользователем на форме информация необходимому типу данных. Сервер или база данных не будет преобразовывать данные к приемлемому виду (происходит обязательный обмен данными между браузером клиента и сервером) — все необходимые расчеты выполняет компьютер пользователя, уменьшая тем самым загруженность ресурсов. В сущности, LiveScript способен обеспечить пользователя тем же уровнем взаимодействия, что и HTML. Как LiveScript стал JavaScript В начале декабря 1995 года в преддверии формального выхода в свет NN2 компании Netscape и Sun любезно объявили, что язык создания сценариев в дальнейшем будет именоваться как JavaScript. И хотя у компании Netscape были некоторые причины маркетингового характера для такого изменения названия, столь резкий шаг вызвал намного большее замешательство в рядах сторонников Java и HTML, чем кто-либо ожидал. Уже перед самым этим заявлением язык был в некотором смысле ориентирован на Java. Многие базовые элементы синтаксиса языка создания сценариев напоминали стиль Java, берущий свое начало от С и C++. С точки зрения использования клиентом, область применения языка существенно отличалось от таковой в Java. Особенно это касается программных кодов, которые интерпретировались непосредственно в HTML, а не в виде отдельного аплета, которому на странице отводилась фиксированная прямоугольная область. В отличие от полного и развитого программного словаря языка Java (и концептуально более трудного для изучения принципов объектно-ориентированного программирования), JavaScript имел ограниченный словарь зарезервированных терминов и легче усваиваемую программную модель. Как выяснилось, намного труднее оказалось ясно показать широкому кругу интересующихся разницу между Java и JavaScript. Очень многие компьютерные журналисты, прямо или косвенно заявив, что JavaScript обеспечивает более простой способ создания аплетов Java, сделали грубую ошибку. И до сих пор многие программисты думают, что JavaScript является синонимом Java— ведь они отправляют запросы Java в группу новостей Internet и списки рассылки, созданные с помощью JavaScript. На сегодня фактом остается то, что Java и JavaScript имеют больше отличий, чем сходств. Эти два языка используют для выполнения строк кода совершенно различные интерпретаторы. В мире Microsoft Несмотря на то, что язык JavaScript ориентирован, в основном, на Netscape, Microsoft все же признала его потенциальные возможности и обеспечила популярность JavaScript, включив его (под именем JScript) в Internet Explorer 3. Даже если Microsoft будет продолжать использовать язык VBScript (Visual Basic Script) намного больше, чем это принято во всем мире (как в версии Ш для Windows), несомненным остается факт, что JavaScript доступен большему числу браузеров и операционных систем. Это способствует тому, что именно на него падает выбор всех, кому приходится заниматься Web-дизайном, потребляемым массовым пользователем. Придерживаясь традиций соперничества на рынке браузеров Web, Netscape и Microsoft продолжают созывать под свои знамена разработчиков, опираясь при этом на разные концепции. На момент написания этой книги Netscape выдвинула лозунг в поддержку общепризнанных стандартов Web. Microsoft же, со своей стороны, обеспечивает только частичную поддержку стандартов и делает упор на разработке многих собственных направлений, что весьма актуально особенно для клиентов, которые используют исключительно операционные системы серии Win32. Если вам потребуется разрабатывать страницы для тех, кто использует оба Глава 1. Роль JavaScript в World Wide Web 41
типа браузеров, запускаемых в разных операционных системах, это только будет способствовать дальнейшим исследованиям. Разговор на данную тему пойдет далее, поэтому сейчас мы не будем останавливаться на этом вопросе. JavaScript: правильное средство для правильной работы Умение правильно подобрать средство разработки для решения поставленных задач является важным моментом для каждого грамотного разработчика Web-страниц. Дизайнер Web- страниц, который игнорирует в своей работе JavaScript, похож на того водопроводчика, который расшибает свои пальцы, мучаясь с плоскогубцами, вместо того, чтобы порыться в своей сумке и найти более подходящий инструмент. Проще говоря, JavaScript не в состоянии воплотить в жизнь абсолютно любую мечту. Чем больше понимаешь замысел создания JavaScript и границы его применения, тем чаще к нему обращаешься даже в тех случаях, когда он кажется неприменим. В частности, к помощи JavaScript имеет смысл обратиться в следующих случаях. ■ Если нужно реализовать прямую или ответную реакцию Web-страницы на действия пользователя при управлении элементами формы (полями, текстовыми областями, кнопками, переключателями, элементами списка, списками меню) и гиперссылками. Этот класс приложений можно назвать бессерверными сценариями. ■ Если необходимо организовать небольшие наборы данных в определенные структуры (например, базы данных) и предоставить для управления ими дружественный интерфейс. ■ Для управления многофреймовыми документами, надстройками или аплетами Java в зависимости от предпочтений пользователя и настроек браузера. ■ Для организации предварительной обработки данных перед отправкой их на сервер. ■ Для внесения динамических изменений в содержимое документа и стили, применяемые в браузерах, в ответ на действия пользователя. В то же время, следует помнить, какие задачи JavaScript выполнить не может. Создатели сценариев, используя JavaScript, тратят много времени на решение задач, для которых этот язык не предназначен в принципе. Большинство ограничений связано с попытками защиты посетителей от покушений на интеллектуальную собственность и несанкционированного доступа к компьютерам. Поэтому, если только посетитель не использует современный браузер и недвусмысленно дает разрешение на доступ к защищенным данным на диске компьютера, JavaScript не сможет выполнить ни одну из перечисленных ниже операций. ■ Установить или настроить предпочтительные параметры браузера, значения свойств, параметры командных кнопок и печати. ■ Запустить приложения на компьютере клиента. ■ Считать или записать файлы и папки на компьютере клиента или на сервере. ■ Перехватить потоки данных с сервера. ■ Отправить себе почтовые скрытые сообщения от посетителей Web-узла. Создатели Web-узлов постоянно находятся в поисках средств повышения привлекательности результатов своего труда. При этом планируется тратить на работу минимум усилий. Более реальной является ситуация, когда эту задачу приходится решать людям, больше знакомым 42 Часть I. Знакомство с JavaScript
с графическим дизайном и оформлением документов, чем когда за дело берутся профессиональные программисты. Не каждый Web-мастер может привлечь опытных программистов для решения проблемы внесения очень специфических изменений в данные узла. Точно так же не каждый Web-разработчик может контролировать Web-сервер, который содержит много коллекций графических и HTML-файлов, разобраться в которых порой очень сложно. JavaScript позволяет реализовать страсть к программированию каждому, кто знаком с HTML, даже если сервер на другом конце телефонной линии представляется ему черным ящиком. Глава 1. Роль JavaScript в World Wide Web 43
Творческие изыскания в сложных полевых условиях стория развития поддерживающих сценарии браузеров достаточно коротка. Поэтому те, кто начинает знакомиться с JavaScript именно с этого момента, имеет по сравнению с остальными и ряд преимуществ, и ряд недостатков. Преимуществом является то, что в распоряжении пользователя сейчас под рукой оказались уникальные средства, поддерживаемые последними версиями браузеров от Netscape и Microsoft. С другой стороны, необходимо знать о процессе развития средств разработки Web-страниц от самых ранних версий (весьма простых, несовершенных и постоянно несовместимых с другими средствами ввиду отсутствия единых стандартов). Вам еще только предстоит изучить основы создания универсальных сценариев, работающих в браузерах самых различных типов. Если вы не обеспечите совместимость сценария с разными версиями браузеров, то вам гарантированно придется сталкиваться с жалобами, приходящими в виде почтовых сообщений от посетителей, в которых будут явно (и гневно) указаны все неполадки, возникающие при выполнении ваших приложений в браузерах других типов и поколений или операционных системах. Таков реальный мир создания сценариев JavaScript для Web-страниц. На тот случай, если конечные пользователи приложения используют разные типы браузеров, чтобы избавить себя от головной боли, следуйте простым, но действенным советам, приведенным в этой книге. В настоящей главе вы познакомитесь с основными методами правильного написания сценариев (это необходимо сделать перед тем, как в собственном сценарии вы введете первый символ кода JavaScript). Единственное, чего я опасаюсь, — это то, что после такого лихого начала вы можете передумать и оставите изучение JavaScript. Но с точки зрения разработчика, начавшего и
работу с JavaScript "с осложнениями" еще на ранних этапах его развития и становления, мне не хочется с самого начала предоставлять вам некорректные сведения. Более того, хотелось бы подчеркнуть значимость для дальнейшего изучения языка материала, который изложен в самом начале книги. Верю, если читателю удастся прочувствовать сложность ситуации, сложившейся в среде Web-дизайна к концу 2004 года, то ему не составит труда овладеть навыками использования JavaScript при создании собственных приложений для Web. Полная неразбериха Проблема совместимости браузеров встала перед Web-дизайнерами еще на ранних этапах развития Web, задолго до появления JavaScript. Несмотря на то, что разработчики браузеров и другие заинтересованные стороны высказывали свои пожелания еще на стадии формирования стандартов, авторы HTML не смогли добиться идентичного отображения HTML-документа на всех клиентских компьютерах. Ведь одно дело утвердить набор стандартных дескрипторов для определения заголовков разных уровней, задания разрывов строк и т.д., и совершенно другое — добиться совпадения содержимого этих дескрипторов в разных типах браузеров. Когда страсти накалились и разработка браузеров для Web превратилась из дела добровольного в весьма прибыльный бизнес, появились умельцы, которые разработали новые характеристики и новые дескрипторы, с помощью которых авторы смогли разрабатывать более гибкие и прекрасно оформленные страницы. Как это часто случается в любой отрасли компьютерной индустрии, темпы развития коммерчески выгодных технологий быстро опередили темпы эволюционирования всесторонне продуманных стандартов. В среде создателей браузера стало привычным сначала встроить новое средство HTML в браузер и только после этого предлагать данное средство для включения в систему стандартов. Web-дизайнеры могли использовать (и повсеместно использовали) это средство (иногда даже в бета-версиях браузера) еще до того, как оно официально включалось в стандарты. Как только вид содержимого документа стал в большинстве своем зависеть от интерпретатора, который установлен в браузере клиента, получающего данные, Web-дизайнеры сразу столкнулись с серьезными проблемами. В отличие от отдельного компьютера, где функциональность программы можно расширять и даже вносить в нее новые возможности, Web- сервер, на котором размещаются данные Web-страниц, полностью отвечает за их содержимое, а также обеспечивает его соответствие с функциональными возможностями браузера. Если Web-сервер не обеспечивает совместимость своего содержимого с браузерами, у разработчиков возникают жалобы, подобные следующим: "Если не все браузеры, отображающие определенную страницу, поддерживают новое средство HTML, то следует ли в данном случае это злополучное средство "исключить'' из HTML?" и "Если в браузере реализуется новое средство, то как поступать со старыми версиями документов и браузеров?". Web-дизайнеры, разрабатывавшие страницы на ранних этапах становления Web, борются с проблемами внедрения новых свойств HTML не один год, поэтому подобные трудности воспринимаются ими как нечто вполне естественное. Сразу же вспоминаются таблицы и фреймы, которые так болезненно внедрялись на Web-страницы. В конечном счете стандарты определяют только направление развития HTML, хотя не для всех дизайнеров подобный путь по душе. Несмотря на бесспорное лидерство Microsoft на рынке браузеров, многие пользователи отдают свое предпочтение программным решениям сторонних производителей. Некоторые последние версии независимых разработчиков (NN7 и Forebird) основываются на открытом коде браузера с громким названием Mozilla. В операционные системы платформ Macintosh отныне встраивается собственный браузер — Safari (представлен в 2003 году). Независимый браузер Opera лишь отдаленно можно считать альтернативой указанным двум. Для этих компаний ставки высоки как никогда ранее — разделение рынка, привлечение инвесторов и т.п. Глава 2. Творческие изыскания в сложных полевых условиях 45
Нетрудно понять и причины подобной конкуренции. То, что началось много лет назад с обычной неразберихи (задолго до признания Microsoft прогрессивности Web), сегодня обернулось самой настоящей войной браузерных технологий. Тенденции Иногда трудно даже сказать, в какой именно технологии Web на этой неделе происходит самое жаркое сражение, и где оно будет проходить на следующей. Новости от противоборствующих сторон, поступающие с рынка продаж, не всегда и не всеми трактуются однозначно. Трудно сказать, когда статистические сведения станут способствовать развитию по-настоящему новой корпоративной стратегии, а когда это просто уловка в ответ на действия конкурента. С одной стороны пользователи выдвигают собственные требования к конечному программному продукту, а с другой— разработчику приходится реализовывать программные решения, поддерживая огромное количество технологий, без которых современный браузер будет просто лишен всякой возможности на существование. В результате простая задача (все, что необходимо пользователям) загрузки данных Web-страницы оборачивается головной болью для разработчика и неразберихой на рынке программного обеспечения. Индустриальные стандарты хотя и несколько упорядочили технологии, однако никоим образом не облегчили жизнь разработчиков браузеров. С одной стороны без поддержки стандартов просто не обойтись, а с другой — далеко не все браузеры совместимы с различными технологиями. Если же учесть то, что в сами стандарты далеко не всегда включаются технологии, чаще всего используемые на рынке, то легко понять, что до полного контроля над ситуацией в данной отрасли еще далеко. В данном случае выигрывает тот, кто первым успел представить в своем браузере средства, востребованные конечными пользователями. Вскоре используемые этим разработчиком технологии становятся стандартными де-факто, что приводит к полному перераспределению сфер влияния на рынке браузеров. Как это случается на войне, когда в ход идет тяжелая артиллерия, жертвы среди мирных жителей растут. Линия фронта в течение нескольких лет изменилась самым драматическим образом. Огромный сегмент рынка, принадлежавший ранее команде Netscape, теперь попал в руки Microsoft (без сомнения, поддержанной миллионами американских пользователей, получивших Ш как составную часть программного пакета AOL). В то время, когда между старыми версиями обеих браузеров можно обнаружить определенное сходство, их новые версии вызывают серьезные опасения у тех разработчиков, которые пытаются создавать продукты, совместимые с каждым из двух типов браузеров. Проблема совместимости сегодня Всегда необходимо учитывать текущее состояние дел в области совместимости Netscape Navigator и Microsoft Explorer. Материал, представленный в следующих нескольких разделах, умышленно не затрагивает глубокого анализа специфики технологических особенностей составления сценариев, поскольку он рассчитан на тех пользователей, которые не очень сильны в программировании. Во многих главах частей Ш и IV можно найти решения, позволяющие использовать сценарии в обоих типах браузеров. Базовый язык и объекты Поскольку первые разработчики, создающие приложения на JavaScript, воспринимали задачу составления клиентского сценария как нечто подобное программированию элементов страницы, основное внимание уделялось усовершенствованию браузеров. На сегодняшний 46 Часть I. Знакомство с JavaScript
день существует четкое разграничение между спецификацией базового языка JavaScript и описываемыми в сценарии операторами (например, задающими кнопки и поля формы). С одной стороны, такое разграничение нужно приветствовать. Это значит, что для базовой программной концепции существует одна спецификация и синтаксис, позволяющий применять язык в любых средах, даже тех, которые пока еще не существуют. Базовый язык можно сравнить с электропроводкой. Если известно, как устроена проводка электрической сетиу то к ней можно подключить электрические приборы всех типов и любой мощности, включая и те, которые пока еще не изобретены. Точно так же JavaScript сегодня используется для того, чтобы связывать вместе элементы страницы в документе HTML. Вполне может быть, что завтра операционные системы будут использовать базовый язык для соединения приложений, запускаемых в компьютерах конечных пользователей, которые будут автоматически обмениваться информацией. В настоящее время JavaScript используется для внедрения на Web-страницы и обеспечения функциональности разрозненных ее элементов. На жаргоне программистов эти элементы называются объектами документа. Если разъединить объекты документа на отдельные составляющие, то впоследствии на их основе можно будет создавать другие типы приложения (это подобно применению телефонных аппаратов с разными типами наборов, включая и те, которые пока еще не разработаны). В настоящее время в телефонных аппаратах используется тональный или импульсный набор. Хорошим примером такого разделения особенностей языка является Internet Explorer, набор объектов документа которого допускает использование как JavaScript, так и VBScript. Объекты, по сути, одни и те же, а способы их объединения в работающие структуры — разные. Разграничение базового языка и моделей объектов документа способствует тому, что каждая спецификация имеет свои собственные стандарты и пути развития. Но даже при наличии рекомендаций по использованию стандартов в каждом из случаев любой разработчик браузеров в состоянии эти стандарты нарушить или даже видоизменить. Более того, может оказаться, что дизайнеры будут тратить больше усилий на создание версии страницы или сценария, работающих в обоих браузерах, по сравнению с созданием разных сценариев для каждого из случаев. Стандарт базового языка Относительно короткая история развития языка JavaScript охватывает три версии, разработанные Netscape. Политика касается версии Microsoft и попыток согласования стандартов. Первая версия JavaScript (в NN2) — это 1.0, однако номер не был включен в название языка. JavaScript 1.0 был просто JavaScript. Нумерация версий установилась после выхода в свет NN3. С этой версией NN связан JavaScript 1.1. Как вы в дальнейшем узнаете в этой книге, в некоторых случаях в дескрипторах HTML, используемых в сценарии, следует указывать номер версии. Смена поколения браузеров на NN4.jc привела к изменению версии языка на JavaScript 1.2. Деятельность Microsoft у начинающих программистов JavaScript вызывает некоторое замешательство. Первая версия Internet Explorer, в которую была включена поддержка сценариев,— это Internet Explorer 3. Время появления Internet Explorer 3 совпало с появлением Netscape Navigator 3. Но, как в этом очень скоро смогли убедиться разработчики, уровень поддержки сценариев в Microsoft оказался на порядок ниже. Microsoft не лицензировала название JavaScript. Как результат, компания назвала свой язык JScript. Тем не менее, атрибуты дескрипторов HTML в Internet Explorer, требующих указания название языка, допускают использование как JScript, так и JavaScript. В любом случае Internet Explorer 3 поймет сценарий, написанный на JavaScript для Netscape Navigator 2. Во время царствования Netscape Navigator 3 и Internet Explorer 3 многие разработчики сценариев испытывали недоумение, поскольку полагали, что язык должен быть один и тот же. К огромному их сожалению, в версии JavaScript 1.1 представлены средства, которые недоступны в более поздних версиях JavaScript для Internet Explorer 3. Спустя некоторое время Глава 2. Творческие изыскания в сложных полевых условиях 47
компания Microsoft улучшила JavaScript в ШЗ, модернизировав файл .dll, определяющий синтаксис языка. Тем не менее, иногда трудно определить, какой именно файл . dll установлен в ГЕЗ в конечном компьютере. Ситуация улучшилась при появлении Internet Explorer 4. Синтаксис его базового языка был максимально приближен к версии JavaScript 1.2 в NN4. При этом Microsoft продолжает называть свой язык JScript. Почти все средства, которые были впервые представлены в NN4 (включая атрибуты дескрипторов, идентифицирующих JavaScript 1.2), прекрасно воспринимались при загрузке в Internet Explorer 4. Пока неразбериха со стандартами и версиями JavaScript продолжалась, Netscape, Microsoft и другие заинтересованные стороны встретились для того, чтобы определиться со стандартом базового языка. В Швейцарии уже давно зарегистрирована организация ЕСМА (European Computer Manufacturer's Association — Европейская ассоциация производителей компьютеров), которая занимается разработкой и внедрением стандартов. В середине 1997 года была одобрена и обнародована первая формальная спецификация языка (ЕСМА-262). С целью обеспечения прав уже лицензированного названия JavaScript было решено использовать для нового стандарта название ECMAScript. Если не считать незначительных, понятных лишь узкому кругу специалистов различий, ECMAScript представлял собой копию JavaScript 1.1 в варианте NN3. Как NN4, так и ТЕЛ поддерживали стандарт ECMAScript. Более того, как это часто бывает, когда коммерческие интересы пересекаются с необходимостью поддержки стандартов, оба браузера разрослись далеко за пределы стандарта ECMAScript. К счастью, базис обоих языков имеет много общего, что несколько упрощает работу разработчиков, их использующих. Браузеры Netscape Navigator 4.06-7 jc тяготеют к использованию JavaScript 1.3, что также справедливо и для браузеров Ш5, 5.5 и 6. В это же время многие новые средства языка, представленные в JavaScript 1.5, были полностью реализованы только в браузерах, основанных на коде Mozilla (включая NN6 и выше). Большинство современных браузеров поддерживают практически все новые средства языка JavaScript, за исключением некоторых малоиспользуемых технологий. Это упрощает работу в современных версиях браузеров, однако абсолютно не влияет на старые версии браузеров, которые "страдают" недостаточной поддержкой любых новых технологий. Объектная модель документа Насколько близки базовые версии языка JavaScript в NN и ГЕ, настолько же далеки объекты документа. В Internet Explorer 3 объектная модель документа (DOM — Document Object Model) совпадает с той, что используется в NN2. Именно эта версия стала базовой для создания стандарта языка. Когда компания Netscape добавила несколько новых объектов в NN3, эти новшества вызвали недовольство неопытных создателей сценариев, которые полагали, что эти же объекты появятся и в Internet Explorer 3. Пожалуй, самыми востребованными объектами в Internet Explorer 3 были элементы управления изображениями, которые позволяют сценариям изменять изображения в ответ на проведение пользователем определенных действий. В браузерах четвертого поколения, тем не менее, объектная модель документа Microsoft ушла намного вперед по сравнению с объектной моделью Netscape, реализованной в NN4. Наиболее революционными достижениями в Ш4 является это возможность виртуального описания в сценарии каждого элемента HTML-документа и переформатирование страницы при выполнении пользователем определенных действий. Таким образом, для HTML был открыт путь к уникальной на то время динамичности, не требующей перезагрузки текущей страницы в окне браузера. В NN4 была реализована только малая доля функции динамизма, без предоставления доступа в сценарии ко всем элементам и возможности изменения страниц в режиме реального времени. Содержимое документов в NN6 не могло так изменяться, как в ГЕ4. Можно сказать, что ГЕ4 стал недостижим для NN. 48 Часть I. Знакомство с JavaScript
В то же время стандарт DOM попал под покровительство консорциума World Wide Web Consortium (W3C). У разработчиков появилась надежда, что стандарт вскоре оформится как завершенная единая спецификация, позволяющая проще программировать динамические элементы для разных браузеров, поддерживающих ее. Компания Netscape серьезно отнеслась к новой тенденции развития технологии и создала практически новый браузер — NN6. В него вошли все наработки W3C DOM 1 и большая часть из уровня 2. Несмотря на то, что Microsoft участвовала в разработке стандарта W3C DOM, в Ш5 были реализованы только некоторые из его положений, в объеме, который делает возможным создание межбраузерных сценариев только в рамках спецификации. Конечно, этот стандарт не является идеальным, тем не менее, вместе с ним в DOM появилось несколько концептуально новых средств создания сценариев. Если все это принять во внимание, а также учесть, какое количество старых браузеров все еще продолжает использоваться, то окажется, что создание сценариев для объектов HTML— дело достаточно непростое. При этом нужно хорошо понимать, как обеспечивается совместимость сценариев с браузерами (именно в этом вам поможет данная книга). Несмотря на то, что компания Microsoft и принимала активное участие в разработке стандарта W3C DOM, в Ш5 и Ш5.5 реализована поддержка далеко не всех ее возможностей. Если быть до конца честным, то в браузерах Microsoft объектная модель W3C DOM реализована только до того уровня, начиная с которого эти браузеры можно назвать соответствующими стандартам — не больше и не меньше. Впоследствии W3C DOM была включена в Ш6, хотя тоже не в том объеме, как того требовал современных рынок. При всем этом объектная модель документа в таком браузере, как Safari, представляет собой нечто среднее из того, что можно найти в Ш6 и Mozilla. Конечно, и данном случае нельзя говорить о полной поддержке, поскольку было упущено даже то, что представлено в Ш4. Каскадные таблицы стилей Netscape Navigator 4 и Internet Explorer 4 были первыми браузерами, претендующими на совместимость с технологией W3C, называемой Cascading Style Sheets 1 (CSSl — каскадные таблицы стилей уровня 1). Эта технология подразумевает специальную организацию содержимого во всем документе (а поэтому минимизирует количество атрибутов, используемых в каждом дескрипторе). Также в ней предпринята попытка расширить традицию использования стандартного HTML для управления статичным содержимым страницы. В конечном итоге оказалось, что в NN4 есть много недоработок. Особенно это становится заметным при попытке совместного использования каскадных таблиц стилей с таблицами других типов. Конечно, Ш4 тоже не отличался особой надежностью, особенно это относится к сравнительным результатам применения таблицы стилей в Windows и Macintosh. В CSS2 функциональные возможности, заложенные в стандарт, значительно расширены. Именно поэтому Ш5 и NN6, в основном, поддерживают только ее. Одни и те же стили теперь более подобны в обоих браузерах, что достигалось за счет строгого соблюдения правил применения стилей. Поскольку объектные модели браузеров ГЕ4+, Mozilla и Safari разрешают проводить динамическое изменение стилей, примененных к любому типу содержимого, то совершенно очевидно, что это изменение реализуется с помощью JavaScript. Информация, содержащаяся в таблицах стилей, является частью объектной модели и поэтому доступна и полностью управляема с помощью JavaScript. Глава 2. Творческие изыскания в сложных полевых условиях 49
Динамический HTML Пожалуй, самым существенным усовершенствованием в поколении HTML 4, на основе которого в той или иной степени построены объектные модели Netscape и Microsoft, является концепция динамического HTML (Dynamic HTML или DHTML). Первоначальная задача использования DHTML заключалась в предоставлении сценариям возможности управления содержимым документов, их расположением и отображением в ответ на действия пользователя. С этой целью организацией W3C (как расширение стандарта CSS) был разработан другой стандарт, обеспечивающий точное позиционирование элементов HTML на странице. Такие рекомендации по позиционированию были совмещены со стандартом CSS, а затем оба они вошли во второе поколение CSS. Благодаря позиционированию стало возможным задавать точное расположение элементов на странице, указывать, какие элементы должны отображаться, а какие скрываться, а также определять порядок наложения и перекрывания всех элементов. Браузер IE4+ больше ориентирован на использование стандарта позиционирования, он предоставляет сценарию возможность управления позиционируемыми элементами. NN4 также следует этому стандарту, однако в нем реализована альтернативная методика с использованием совершенно нового и в конечном счете не утвержденного дескриптора описания слоев. Позиционируемые элементы в NN4 также остаются доступными для сценариев, хотя сам синтаксис сценария при этом во многом отличается от того, что используется в Ш4. К счастью тех, кто работает с DHTML, Mozilla, благодаря поддержке стандарта CSS, понимает синтаксис дескрипторов стилей DHTML, применяемых в Ш4+. Создание межбраузерных сценариев с помощью единого синтаксиса все еще остается нелегкой задачей, хотя вполне возможной. После выпуска компанией Microsoft браузера Ш6 многое изменилось, хотя на рынке появилось несколько независимых игроков (Mozilla и Safari), в которых поддержка DHTML и JavaScript реализована на столь же высоком уровне, как и у "законодателя моды". Главное — это четко осознавать возможности каждой спецификации и использовать только те средства, которые поддерживаются в большинстве браузеров. Создание межбраузерных сценариев Браузеры последнего поколения объединяют все то, что досталось им в наследство от предыдущих версий, стандартов и собственных наработок компаний-производителей. Если вы попытаетесь создать сценарий, рассчитанный на самые общие средства языка, то используемый код, скорее всего, не будет поддерживаться ни ранними версиями базового языка JavaScript, ни объектными моделями документов новых браузеров. Поэтому наиболее важным заданием для тех, кто сегодня старается создавать межбрау- зерные сценарии, является определение круга пользователей, на который будет рассчитано создаваемое приложение. В главе 13 описан набор методов, позволяющих производить перенаправление пользователей по структуре своего Web-узда с целью отображения нужной версии страницы в их браузере. В главе 14 показан ряд альтернативных решений, зависящих от используемой версии (или версий) объектной модели и специфических характеристик, для которых необходимо реализовывать поддержку. Каждое новое поколение браузеров приносит в этот мир набор новых удивительных средств языка, которые используются при создании страниц. К сожалению, это приводит к фрагментации аудитории посетителей узла. После выхода каждого нового пакета обновления браузера далеко не все пользователи захотят загружать мегабайты данных просто для того, чтобы иметь самую последнюю версию браузера. Для большинства первопроходцев (и уж точно неспециалистов) причины, побуждающие обновить версию браузера, довольно примитивны. Разве что такое обновление может связываться с покупкой нового компьютера или обновлением операционной системы. so Часть I. Знакомство с JavaScript
На данном этапе можно считать, что подавляющее большинство пользователей склоняется к установке современных версий браузеров, в которых в полной мере реализована поддержка W3C DOM и DHTML. He факт, что это так на самом деле, но ведь вам никогда не удастся удовлетворить запросы конечной аудитории на все 100%. Буквально это означает следующее: вам достаточно разработать Web-страницы, которые будут открываться у подавляющего большинства пользователей и по мере возможностей у всех остальных. В идеальном случае Web-документы будут доступны всем, а вот специальные их средства — только счастливым обладателям браузеров с поддержкой JavaScript-сценариев и других современных технологий. Таким образом, в ваши задачи входит намного больше, чем создание красочных Web-страниц. Вам придется изрядно потрудиться, чтобы сделать свои приложения полностью интерактивными, максимально производительными, информационно востребованными и, конечно же, поддерживаемыми большинством современных браузеров. Глава 2. Творческие изыскания в сложных полевых условиях 51
Первый собственный сценарий этой главе речь пойдет об установке на компьютер программных продуктов, позволяющих с высокой производительностью создавать сценарии, а также выполнять их. Мы также постараемся написать простой сценарий, результат выполнения которого можно просмотреть в любом совместимом с JavaScript браузере. Благодаря отличиям в работе разных операционных систем, основные настройки среды будут ориентированы на использование двух наиболее популярных систем: Win32 (Windows 95-ХР) и MacOS X. В большинстве случаев изменение операционной системы, вплоть до выбора Linux и UNIX, никак не повлияет на решение и результат поставленных задач. Безусловно, для разных браузеров и операционных систем могут наблюдаться некоторые незначительные различия в структуре представления параметров, однако базисные положения останутся неизменными. Большинство рисунков, а также графически иллюстрируемые результаты, полученные в браузере, в этой книге выполнены для Internet Explorer 6 в Windows XP. Поэтому, если вы используете другой браузер и результаты его в окне не соответствуют приведенным в книге, то это не должно вас тревожить. Программное обеспечение Лучший способ изучения JavaScript — введение кода сценария непосредственно в текстовом редакторе. Выбор самого редактора остается всецело за вами, хотя в следующем разделе представлены некоторые соображения по этому поводу. Выбор текстового редактора С точки зрения материала данной книги, читателю пока следует избегать графических программных средств создания Web- страниц типа WYSIWYG (What You See Is What You Get — Что видишь, то и получаешь) — FrontPage или Dreamweaver,
Эти средства определенно понадобятся вам в будущем, когда у вас будет опыт представления элементов страницы в виде кода. Тогда для формирования основного содержимого документа и макета они вам особо пригодятся. Примеры, приводимые в данном издании, основаны на создании сценариев, которые в любом случае придется вводить вручную, поэтому у знатоков кода HTML в этом смысле проблем возникать не должно. Файлы листингов готовых Web-страниц, описанных в этой книге (кроме учебных глав), вы найдете на прилагаемом компакт-диске. Важным фактором при выборе текстового редактора является удобство, с каким он позволяет вводить и сохранять стандартные текстовые файлы с расширением . html. В случае использования Windows любая программа, если только она сохраняет текстовые файлы, по умолчанию позволяет добавлять к ним расширение . htm или . html, т.е. способна избавить вас от проблемы выбора специального редактора. Если, к примеру, выбрать программу Microsoft Word, то при сохранении текстовых файлов она попытается представить их в двоичном виде—такой файл не в состоянии загрузить ни один браузер Web. Чтобы первоначально сохранить файл как текстовый с расширением . html, вам придется провести некоторые настройки в диалоговом окне Save As (Сохранить как). А это раздражает. Нет ничего страшного в использовании обычного текстового редактора. В той же Windows, предлагающей редактор WordPad, можно установить и более совершенные продукты для введения кодов листингов (например, испытательную версию программы TextPad). Для системы MacOS X вполне подойдет TextEdit, хотя отсутствие функции поиска и замены может привести к ряду трудностей при управлении кодами Web-страниц. Наиболее популярной среди разработчиков HTML и создателей сценариев, использующих Мае, является программа BBEdit (от Ваге Bones Software), в состав которой входит большое количество вспомогательных средств для составления сценариев (например, опции нумерации строк, которые помогают при отладке кода JavaScript). Выбор браузера Другим компонентом, необходимым при изучении JavaScript, является браузер. Для того чтобы протестировать собственные сценарии с помощью браузера, совсем необязательно быть подключенным к Internet. Все тестирование можно вполне выполнить и в автономном режиме. А это значит, что изучать JavaScript и создавать с использованием сценариев по- настоящему привлекательные Web-страницы можно с помощью небольшого портативного компьютера — прямо хоть в лодке посреди океана. Тип используемого браузера и его версия целиком определяются вкусами читателя. При разработке страниц советуем устанавливать максимально современный браузер (ГЕ5 и выше для Windows и Macintosh, любой Mozilla-браузер, включая NN7 и выше, и Apple Safari). # В примерах листингов в этой книге используются свойства языка или объектные /Ншыюту модели документа (DOM), которые доступны только в определенных браузерах * **>*' и их версиях. Поэтому проверяйте совместимость введенного кода с используемой версией языка или моделью DOM, чтобы убедиться, что для загрузки страницы был применен подходящий браузер. Настройка среды разработки Чтобы облегчить себе задачу по тестированию сценариев, убедитесь, что в компьютере установлено достаточно памяти для одновременного запуска браузера и текстового редактора. При экспериментировании и устранении всевозможных ошибок, которые могут быть допущены в сценарии и, вам нужно будет быстро переключаться между редактором и браузером. В обычном рабочем режиме вам придется выполнить такие действия. Глава 3. Первый собственный сценарий S3
1. Ввести в текстовом редакторе документа исходный HTML-код и код сценария. 2. Сохранить последнюю версию кода на диске. 3, Переключиться на браузер. 4, Дальше можно поступить несколькими способами. Если это новый документ, то откройте его с помощью команды Open (Открыть) браузера. Если же этот файл уже загружен, перезагрузите его в окне браузера. Последовательность действий, описанную в пп. 2-4, придется повторять довольно часто. Так и хочется назвать эту трехэтапную последовательность сохрани-перключись-перезагрузи. Такую последовательность действий при создании сценариев придется выполнять столь часто, что в конце концов эта физическая процедура будет выполняться вами подсознательно. Как именно организовывать окна приложений на экране и выполнять последовательность действий сохрани-переключись-перезагрузи, зависит от конкретной используемой операционной системы. Система Windows В этом случае для "получения полного эффекта" не следует постоянно держать развернутыми на весь экран окна редактора или браузера. Работать будет удобнее, если настроить размеры и расположение окон так, чтобы они имели достаточно большой размер, но при этом оставалась возможность щелкать мышью на заголовках окон. В любом случае можно обратиться за помощью к панели задач и щелкнуть на кнопке соответствующего приложения, чтобы перейти к необходимому окну (рис. 3.1). Если выставить разрешение монитора большим, чем 800x600 пикселей, то это добавит места для окон и панели задач. function *mlkChlldVodaa(ob:)ftaf, n) { var obj If <ob)Haf) < if (typeof objtaf -- "scrlng") { obj - document.g«tEl«amnt»yId(objft«f) ) «la* { obj - objRef > ) iIn < onj - (document.body.paxantKlament) 7 document.body.parentllament i document.body.parentModa ) vmr output ■ "" vex indent - "" таг i, group, tut If (в> < for (l-O» i < n; i++) < indent +- «4 ■ ) ) also ( n ■ 0 output ♦- "Child Nodea of <" + obj.cmojfame output ♦- »>\a——•—•—•••••—\n* ) Рис. 3.1. Расположение окон редактора и браузера при использовании Windows На практике, тем не менее, наличие используемой в Windows для переключения между выполняемыми приложениями комбинации клавиш <Alt+Tab> приводит к тому, что реализовать последовательность сохрани-переключись-перезагрузи становится очень просто. Если вами используется система Windows, в которой запущен совместимый с ней текстовый редактор (в котором, скорее всего, для сохранения документа используется комбинация клавиш <Ctrl+S>), то выполнить последовательность сохрани-переключись-перезагрузи будет очень 54 Часть I. Знакомство с JavaScript
просто, даже без использования мыши: для сохранения исходного файла нужно нажать <Ctrl+S>, затем переключиться на браузер с помощью комбинации <Alt+Tab> и после этого перезагрузить сохраненный файл, нажав <Ctrl+R>. Чтобы обратно переключиться из окна браузера к окну текстового редактора, еще раз нажмите <Alt+Tab>. Система MacOS X В MacOS X для переключения между программами вам придется использовать средство Dock или комбинацию клавиш <3€+ТаЬ>. Если одновременно запущено только два приложения, то для перехода от одной из них к другой нажмите <Х+ТаЬ> (рис. 3.2). Рис. 3.2. Расположение окон редактора и браузера на экране Macintosh В таком случае последовательность сохрани-переключись-перезагрузи потребует уже некоторых усилий. 1. Нажмите <3€+S>, сохранив тем самым исходный файл. 2. Щелкните мышью на окне браузера. 3. Нажмите <8€+R> и перезагрузите сохраненный исходный файл. Для того чтобы вернуться к редактированию исходного файла, нажмите <3€+ТаЬ>. Особенности перезагрузки В большинстве случаев простой перезагрузки страницы вполне достаточно для тестирования измененного сценария. Но в некоторых случаях в кэш-памяти браузера (с используемыми по умолчанию настройками) могут при перезагрузке сохраниться некоторые из предыдущих атрибутов страницы, даже если ее исходный код изменен. Для выполнения более основательной перезагрузки при использовании кнопки перезагрузки браузера Reload/Refresh Глава 3. Первый собственный сценарий 55
(Перезагрузить/Обновить) удерживайте нажатой клавишу <Shift>. Альтернативой является отключение кэш-памяти браузера в разделе установок. Однако такие изменения могут негативно сказаться на общем характере функционирования браузера в сеансах работы в Web. Что будет делать первый сценарий Сценарий, который будет рассматриваться в следующем разделе, относится к тем, которые запускаются автоматически при загрузке браузером HTML-страницы. Поскольку в данном случае вся работа, связанная со сценарием и загрузкой, выполняется в автономном режиме, то поведение страницы будет таким же, как если бы исходный файл был размещен на сервере и кто-то получал к нему доступ с помощью Web. На рис. 3.3 показано, как будет выглядеть готовая страница. Правда, если используется операционная система, отличная от Windows XP, или в качестве браузера задействован не Internet Explorer, то некоторые несущественные детали могут слегка отличаться. Та часть страницы, что в HTML определяется обычным способом, не содержит ничего особенного: заголовок уровня <Ы> с горизонтальным разделителем под ним. Если используется браузер, не поддерживающий JavaScript, то все, что можно будет увидеть, так это указанные заголовок и горизонтальный разделитель. Если вами используется совсем уж старомодный браузер, то в этом случае на странице могут появиться еще и некоторые операторы сценария. ■*-~'"""«-**,-*~-"'"~ Let's Script... Tbu browicr if vemon 4.0 (compatible; MSIE 6.0. Wwlowi NT 5.1. Q312461) of Nficrnefl BkSSm ..Л^.1,^лЯ Рис. 3.3. Завершенная страница первого сценария JavaScript Под разделителем сценарий отобразит текстовую информацию, состоящую из неформатированных данных сведений о браузере, используемом для загрузки документа. Сценарий записывает поток данных HTML в браузер, включая дескрипторы для отображения некоторых фрагментов текста полужирным начертанием. Хотя на странице текстовая информация разбита на две строки, передается она как одна строка — ситуация, подобная той, что имеет место при жестком форматировании текста в HTML. Создание первого сценария Итак, пришло время начать работу над первым собственным сценарием JavaScript. Для этого сначала запустите текстовый редактор и браузер. Если браузер предлагает соединиться с провайдером Internet (Internet Service Provider или ISP) или начинает делать это автоматически, 56 Часть I. Знакомство с JavaScript
то операцию следует отменить и выйтииз программы установки соединения. Если в браузере активна кнопка Stop (Остановить), то для пресечения возможных попыток браузера установить соединение следует незамедлительно ею воспользоваться. При этом может появиться диалоговое окно с сообщением о том, что адрес URL для начальной страницы браузера (обычно такая страница является страницей издателя браузера, если только пользователем не были внесены изменения в настройки) не определен. Это нормально. Ведь вам нужно было всего-навсего запустить браузер, а не соединиться с ISP. Если вы используете автоматическое соединение через местную локальную сеть, то ничего страшного. Более того, пока что сетевое соединение вам не потребуется. Ниже приведена последовательность операций, позволяющих создать и просмотреть первый собственный сценарий JavaScript. 1. Запустите текстовый редактор и создайте новый пустой документ. 2. Введите в окне документа сценарий, как это показано в листинге 3.1. <html> <head> <title>My First Script</title> <style type="text/ess"> .highlight {font-weight: bold} </style> </head> <body> <hl>Let's Script...</hl> <hr> <script type="text/javascript"> <!-- скрытие сценария от старых браузеров document.write("This browser is version " + navigator.appVersion); document.write(" of <span class='highlight■>" + navigator.appName + "</span>. ") ; // завершение кода скрытия сценария от старых браузеров --> </script> </body> </html> 3. Сохраните документ под именем script 1. htm. 4. Перейдите в браузер. 5. В меню File (Файл) браузера воспользуйтесь опцией Open (Открыть). В некоторых браузерах этот пункт называется Open File (Открыть файл). Затем необходимо выбрать файл script 1. htm. В некоторых браузерах для отображения диалогового окна открытия файла нужно сначала щелкнуть на кнопке Browse (Обзор). Если все строки были введены согласно приведенному выше образцу, то документ в окне браузера должен выглядеть так, как показано на рис. 3.3 (с учетом небольших поправок на разные версии используемой операционной системы и браузера). Если же браузер выдает сообщение о том, что при загрузке документа имеет место ошибка, то на данном этапе ничего предпринимать по этому поводу не нужно. Если появилось диалоговое окно ошибки, просто щелкните на кнопке ОК. Сначала лучше разобраться с тем, как устроен весь документ, понять особенности его выполнения и только после этого переходить к отладке. Глава 3. Первый собственный сценарий 57
Исследование сценария Сразу следует предупредить: не старайтесь запомнить все команды или тот синтаксис, которые будут описываться в этом разделе. Напротив, немного расслабьтесь и посмотрите, как строки кода превращаются в то, что отображается в окне браузера. В листинге 3.1 все строки вплоть до дескриптора <script > являются примером кода обычного HTML. К нестандартному дескриптору относится только <style>, который входит в спецификацию CSS. Дескриптор <script> Каждый раз при включении в документ HTML переменных JavaScript соответствующие строки кода потребуется заключить между парой <script>. . </script>. Эти дескрипторы сообщают программе браузера, что содержащийся между ними текст нужно интерпретировать как сценарий. Поскольку другие языки составления сценариев (такие, как VBScript компании Microsoft) также могут в полной мере использовать преимущества данных дескрипторов, то вам обязательно необходимо указать точное название того языка, который использован для создания кода. Поэтому, когда браузер получает сообщение о том, что в сценарии используется язык JavaScript, он использует для обработки кода встроенный интерпретатор JavaScript. Проведем такую аналогию с реальной жизнью: если у вас под рукой есть разговорник французского языка, то нужно, чтобы ваш собеседник тоже говорил по-французски. Если попутчик, • скажем, из Испании, то французский разговорник вряд ли будет полезен. Точно так же: если используемый браузер имеет только интерпретатор JavaScript, он не сможет понять код, написанный на VBScript. Далее мы остановимся на еще одном аспекте использования JavaScript, который важен при работе со сценариями. JavaScript чувствителен к регистру (различает большие и маленькие символы). Поэтому необходимо при вводе кода сценария JavaScript следить не только за самими терминами, но и за состоянием регистра, т.е. не путать прописные и строчные литеры. В дескрипторах HTML (включая и < script >) могут использоваться оба регистра по усмотрению разработчика, но все, что является кодом JavaScript, чувствительно к регистру. Если строка кода JavaScript не выполняется, сначала следует проверить, правильный ли регистр был использован для ее представления1. Всегда следует сравнивать введенный вручную код с теми листингами, которые приведены в книге или других источниках. Сценарий для всех браузеров Следующая после дескриптора <script > строка в листинге 3.1 напоминает HTML-дескриптор начала комментария. Так оно и есть, только интерпретатор JavaScript трактует дескрипторы комментариев особым образом. Хотя JavaScript послушно игнорирует строки, начинающиеся с дескриптора начала комментария HTML, он воспринимает следующую строку как полноправную строку сценария. Если нужно в код JavaScript вставить комментарий, то этот комментарий должен начинаться с двойной косой черты (//). Такой комментарий может располагаться в конце строки (например, после оператора JavaScript, который должен интерпретироваться браузером) или занимать отдельную строку. Как легко заметить, в конце сценария используется последний вариант. Строка комментария начинается с двух косых черт. Если теперь внимательно присмотреться, то можно заметить, что внутри дескрипторов комментария стандартного HTML-кода (< ! - -комментарий- - >) размещен целый сценарий 1 Стили XHTML, если вы планируете использовать их в своих приложениях, требуют введения имен дескрипторов и имен атрибутов в нижнем регистре. Это соглашение вы встретите повсеместно в настоящей книге. 58 Часть I. Знакомство с JavaScript
(с собственными комментариями). Смысл такой организации сценария сразу не совсем понятен. Но это до тех пор, пока вы не столкнетесь с браузером, который не поддерживает язык JavaScript. В этом случае браузер игнорирует дескриптор <script > как новый непонятный для него элемент. А вот текст сценария он интерпретирует как обычный текст, который нужно отображать на странице. Если заключить этот текст в дескрипторы комментария HTML, то большинство устаревших браузеров не отобразит строки сценария на странице. Однако некоторые старые браузеры (далеко не все могут себе позволить обновлять программное обеспечение вовремя) иногда не реагируют на такое развитие событий, но выводят на экран непонятные сведения. Это происходит потому, что они интерпретируют отдельный символ > (а не весь символ - - > как целое) в качестве символа окончания комментария. Следует, кроме того, помнить, что некоторые пользователи просто не имеют доступа к современным браузерам (если, например, используют текстовые браузеры Lynx для UNIX или аналогичные Lynx-браузеры в переносных компьютерах). Если выделить строки сценария в качестве комментария, то при использовании относительно современных, но не совместимых с JavaScript браузеров, страница, все же, не будет выглядеть как некорректная. # Обратите внимание на то, что строки комментария, содержащие операторы, ко- /назмМсу торые предотвращают выполнение сценариев в старых браузерах, расположены ' ^*<^ внутри дескрипторов <script>. .</script>. Нельзя строки комментария выносить за пределы этих дескрипторов. Иначе этот метод не сработает. И еще несколько замечаний о способах скрытия комментариев, описанных в этой книге. Чтобы сэкономить место, в большинстве примеров не были приведены комментарии. Но, как в этом можно убедиться на примере реальных приложений (главы 48-57, приведенные на прилагаемом к книге компакт-диске), комментарии в них присутствуют. Если же сценарий создается для общих нужд, следует всегда добавлять комментарии в код сценария. Отображение текста В сценарии листинга 3.1 есть две строки одного типа, которые используются для отображения текста в данном документе. Это строки document. write 0.0 самом же объекте document речь пойдет в главе 18. Когда бы ни запрашивался объект (в данном случае это document) с целью выполнения определенного задания; после названия задания обязательно поставьте круглые скобки. В качестве примера можно привести оператор write () — JavaScript должен знать, с какими данным его нужно применять. После имени задания указываются эти данные, называемые также параметрами. Поэтому если в документе нужно отобразить имя первого президента Соединенных Штатов, то сделать это можно так. document.write("George Washington") Строка текста, которую сценарий выводит на экран, начинается с некоторого предопределенного фрагмента "This browser is version" (Это браузер версии), в который впоследствии добавляется версия браузера. Далее на экран снова выводится статический текст, содержащий дескриптор HTML ("of <span с lass = 'highlight ■ >"), затем более значимый текст (название приложения), после чего — закрывающий дескриптор HTML и точка в конце предложения ("</span>."). В JavaScript символ "плюс" (+) используется для объединения (конкатенации) фрагментов текста в одну большую строку текстовых символов, которые отображаются в документе. Ни JavaScript, ни тем более символ + ничего не знают об используемых словах и пробелах, поэтому сценарий полностью отвечает за выделение нужного места, что и отражается в параметрах. Обратите внимание, что после слова "version" в параметре первого оператора document ♦ write () оставлено свободное место. Также свободное место вы увидите с обеих сторон от "of" во втором операторе document. write О . Глава 3. Первый собственный сценарий 59
Для получения информации о версии браузера и названии, которые используются в параметрах, укажите JavaScript извлечь соответствующие свойства объекта navigator. Извлечь свойство можно, если добавить его через точку после имени объекта (в данном случае это navigator). Извлекаемые имена в приведенном примере разделены пробелом. Если вам тяжело сориентироваться в записи, то попробуйте прочитать ее справа налево. В этом случае то, что находится справа, является свойством расположенного слева. В нашем случае appVers ion является свойством объекта navigator. Этот "точечный" синтаксис во многом напоминает вызов операторов действий (к примеру, document .write О), но только после имени свойства не нужно ставить круглые скобки. В любом случае, ссылка на свойство в сценарии дает указание JavaScript вставить значение этого свойства туда, откуда сделан запрос. При первом обращении JavaScript-сценарий запросит информацию о браузере, представит ее в виде текстовой строки и отобразит в документе. Наконец, обратите внимание на точку с запятой в конце каждого оператора JavaScript. На самом деле вводить ее совсем не обязательно. Ничего плохого в последнем случае не произойдет. Тем не менее, если вы планируете изучать более серьезные языки программирования, например, C++, то использование точек с запятой в конце операторов будет обязательным требованием. Улыбнемся вместе Если при первой попытке загрузить в браузер данный документ произошла ошибка, следует вернуться в текстовый редактор и проверить строчка за строчкой сценарий, сравнив его с листингом 3.1. При этом помните о том, что было рассказано выше. Может оказаться, что один из символов расположен не на своем месте или вместо символа верхнего регистра введен символ нижнего регистра, или наоборот. В листинге могут отсутствовать кавычки или скобки. Чтобы увидеть, насколько динамичен сценарий scriptl.htm, вернитесь в текстовый редактор и замените слово "browser" на "client software". Теперь для отображения изменения в тексте документа нужно все сохранить, перейти в браузер и перезагрузить страницу. Вы можете смело заменять любой текст, приведенный в кавычках в виде параметра в операторе document .write О . Параметры оператора document .write О являются текстом HTML, поэтому в нем можно использовать дескриптор "<br>" для разрыва строк. При этом помните, что для отображения на экране любых внесенных изменений нужно сохранить документ, перейти в браузер, а затем перезагрузить сохраненную страницу. 60 Часть I. Знакомство с JavaScript
Руководство по JavaScript
Объекты документа и браузера та глава является первой из девяти учебных глав (которые составляют часть П) и предназначена для тех, кто имеет, по крайней мере, базовые представления о HTML, их атрибутах и CSS. В данной главе можно будет найти несколько полезных приложений JavaScript, а также выяснить, как браузер, поддерживающий JavaScript, интерпретирует в качестве объектов, которыми можно управлять с помощью сценариев, старые добрые элементы HTML. Все, что изложено в этом руководстве, может непосредственно использоваться в поддерживающих сценарии браузерах Internet Explorer 5 и выше (Windows и Macintosh), а также Mozilla и Apple Safari. Сценарии, которые творят чудеса Тот, кто уже создавал с помощью HTML документы, должен знать, что именно дескрипторы HTML влияют на способ отображения данных, интерпретируемых браузером. При загрузке страницы браузер производит опознание дескрипторов по угловым скобкам, которые содержат инструкции относительно выполнения требуемого форматирования. Инструкции эти считываются последовательно от начала документа, а элементы, определяемые в документе HTML, появляются на экране в том порядке, в каком они расположены в исходном коде документа. Создатель документа только заносит в документ дескрипторы; на этом его задача заканчивается. Браузер выполняет намного больший объем работы при отображении данных, причем делает это при каждой загрузке страницы. Представим себе, что один из элементов на странице является полем формы для ввода текста. Предполагается, что пользователь должен ввести в это поле некоторый текст, после этого щелкнуть не кнопке Submit (Отправить) для отправки информации на Web-сервер. Если этой информацией должен быть почтовый адрес в Internet, возникает вопрос: как убедиться в том, что пользователь использовал в записи адреса символ @?
Одним из способов решения является использование CGI-программы (Common Gateway Interface — общий шлюзовой интерфейс). Эта программа проводит проверку формата предоставляемых серверу данных. Если пользователь, по неизвестным причинам, не применил символ @, то CGI-программа отправит запрос назад браузеру, но на этот раз уже с требованием включить указанный символ в адрес. В этом "обмене любезностями", в принципе, нет ничего страшного, но для пользователя это означает существенную задержку во времени. Она вызвана необходимостью проверки наличия в адресе злополучного символа. Более того, для выполнения такой проверки и отправки ответа Web-серверу нужно задействовать дополнительные ресурсы. Web-узлы, как правило, достаточно загружены, поэтому процесс получения пользователем ответа занимает определенное время. Представим также, что после ввода текста (перед предоставлением его серверу) введенная пользователем запись может проверяться на наличие символа @ на стороне клиента. Соответствующая программа должна быть реализована непосредственно в документе. Браузер должен знать, как запускать эту программу. Например, она может запускаться в ответ на определенные действия пользователя (скажем, когда пользователь щелкает мышью на кнопке Submit). Если программа запускается средствами браузера и при этом обнаруживается отсутствие символа @, на экране должно появиться предупреждающее сообщение, адресованное пользователю. Та же программа должна определять, можно ли продолжать процесс предоставления текущих данных, или следует подождать, пока в поле будет введен корректный почтовый адрес. Такой способ предварительной проверки корректности вводимых данных является только одним из практических методов, часто реализуемых с помощью JavaScript. Рассматривая этот пример, можно прийти к выводу, что в сценарии должна предусматриваться возможность просмотра содержимого текстового поля и управления процессом ввода данных. Браузер, способный запускать программы JavaScript, без труда интерпретирует такие элементы, как текстовые поля, в качестве объектов. Сценарий JavaScript управляет поведением и функциональными возможностями объектов. Большинство из них можно увидеть на экране в окне браузера. JavaScript в действии Объектами на экране можно управлять. Для этого достаточно добавить несколько строк кода JavaScript в документ HTML. Чтобы у вас сложилось правильное представление о возможностях JavaScript по созданию приложений, обязательно изучите приложения, представленные на прилагаемом к книге компакт-диске (в папках для глав 48-57). Запустите эти приложения (откройте с помощью браузера) и проанализируйте, как они работают. Ссылки на файлы приложений, расположенные на компакт-диске, можно найти на странице tutorl. htm в папке с листингами программ. Интерактивный интерфейс Гиперссылки HTML вам пригодятся при исследовании Web, но их использование далеко не всегда позволяет наиболее удачным образом составить оглавление для узла или документа. Если привлечь к выполнению этой задачи JavaScript, то можно создать интерактивное разворачиваемое оглавление, отображающее иерархическую структуру большого объема данных (рис. 4.1). Подобно текстовым листингам (или деревьям просмотра), отображающимся в окнах менеджеров файлов операционных систем, разворачиваемое оглавление позволяет пользователю видеть ровно столько структурных элементов, сколько нужно. Для того чтобы просмотреть опции меню, следует щелкнуть на серой кнопке. Конечная опция меню помечена специальной пиктограммой. Опции на схеме структуры могут содержать ссылки на другие страницы или информацию описательного характера. Шрифты отдельных записей можно изменять по своему усмотрению. Это обычная процедура в HTML. В прошлом Глава 4. Объекты документа и браузера 63
такие структуры обрабатывались сервером. Поэтому ответная реакция на щелчок мышью на опции реализовывалась со значительной задержкой. Если вы используете описанный выше способ предварительной обработки информации и разместите нужную программу на странице, то после первой загрузки все на странице будет открываться и закрываться очень быстро. Competition of Selected Foods I Рем I Pickles ■ Freth И Sour Ш!»tJHTHflmliiMi mrtid tana '■" Pickle Hekles-CHeumber-Dffl Water (percent) 93.3 Food energy (calories) 11 Protein (grams) 0.7 Fat (grams) 0.2 Fickle s—Cucumber-Fresh Water (percent) 78.7 Food energy (calories) 73 Protein (grams) 0.9 Fat (grams) П2 Ш,Г,,1, ШШж& Рис. 4.1. Так выглядит развернутое оглавление Поиск данных Стандартное приложение в Web, использующее CGI-программы, предоставляет в распоряжение пользователей окно, с помощью которого они получают доступ к базам данных на сервере. Большие хранилища данных рекомендуется размещать на сервере, где расположены специальные поисковые системы и другие вспомогательные средства управления, соответствующие наиболее часто решаемым задачам. Бели страница используется как внешний интерфейс для поиска небольшого объема данных, можно рассмотреть целесообразность внедрения подобных средств в документ (на странице они явно отображаться не будут) и задействовать JavaScript в качестве посредника между пользователем и этими данными. Такой подход реализован в префиксной системе поиска Social Security (Социальное страхование) — рис. 4.2. В этом случае данные распечатанной таблицы, состоящей примерно из 55 записей, конвертированы в список JavaScript, который занял всего несколько сотен байт. Когда посетитель узла вводит в соответствующее поле трехеимвольный префикс номера собственного страхового полиса, сценарий, расположенный "за сценой", сравнивает его с теми 55 (или около того) записями, которые представлены в таблице. Когда сценарий обнаруживает совпадение, то во втором поле выводится соответствующая регистрационная информация. Если приложение находится на сервере, и там же, в базе данных сервера, хранится нужная информация, то каждый щелчок на кнопке поиска — Search (Поиск) — означает задержку в несколько (а может и больше) секунд, которые уходят на обработку сервером запроса, получение информации из базы данных и внесения изменений на страницу. Конечный результат 64 Часть II. Руководство по JavaScript
предоставляется пользователю спустя довольно длительное время. Если вместо всего этого использовать приложение JavaScript, то после первой загрузки страницы сценарии мгновенно выполнят все необходимые операции по поиску данных. Ffc ЕЛ Vto* Favorites Tods ?■«!• ■■"о- --vi -1 Step Refresh* Hoe» Search Favorite Med* Where Were You Born? According to an article in the Wall Street Journal, the first three digits of a TJ. S. Social Security number is a code that may indicate die state or territory in which your application stated you were born (because the code reveals the state in which you registered). For recent immigrants, the number is supposed to match up with the state or territory in which you were living when you received proper working papers. Note: The database in this document is not 100 percent complete. Populous states have added numeric ranges not contained here. Instructions: 1. Enter the first three digits of a U S. Social Security number in question. 2 Click on the Search buttoa 3. See the corresp onding state or territory in the field. For die paranoid: No information you enter here is recorded or monitored—it stays entirely within your browser. Enter me first three digits of a Social Security numberiM j [ Search j The Feds bnk. mis number to (West Virginia Рис. 4.2. Поиск данных в небольшой таблице Проверка правильности введенных данных О проверке правильности введенных данных на форме мы уже говорили как об удачном использовании JavaScript. Поле ввода данных на странице поиска Social Security (см. рис. 4.2) создается в сценарии системой проверки корректности вводимых значений. Точно так же, как CGI-программа для каждого случая должна выполнять проверку равенства полученного значения трехзначному числу, программа JavaScript обязана выполнить соответствующую проверку любых поступающих извне сведений. Если в записи обнаруживается ошибка (палец мог соскользнуть с нужной клавиши и нажать другой символ), посетитель будет уведомлен об ошибке и ему предложат ввести данные еще раз. Сценарий проверки правильности данных может даже удалить в тексте ненужный или неправильный символ, поэтому посетителю узла останется лишь часть от исходно запрашиваемой комбинации символов. Интерактивные данные JavaScript предоставляет средства превращения статичных данных в интерактивную информацию. На рис. 4.3 показан графический калькулятор определения параметров электрического элемента (называемого резистор) в том случае, если известна только его цветовая маркировка. Глава 4. Объекты документа и браузера 65
Back...... Forwejd ..0-0-9 Ш & \ P J&4*- -. ■ ЯФоФ... . .Hen»... j ;j5fMi*ti..„favorite* Me, . Pfht Edt Calculate Resistor Values from Color Codes И ! Resistance1 Yellow ~jjj Block Brown Red Green Blue IViolet [Blue " jg[ JG^j§§ 24Mohms,*/-5°/, ^■Violet ^^^^^B^ Illustration Copyright 1996 Danny Goodman. All Rights Reserved 1122. Чфюыуъкш Рис. 4.3. Интерактивный графический калькулятор Изображение в нижней части страницы состоит из семи изображений, расположенных рядом друг с другом на вертикальных ломтиках. Четыре ломтика представляют собой разноцветные полосы, в то время как остальные три фрагмента — это выводы резистора и разделители между полосами. После того как пользователь выберет цвет из выпадающего списка в верхней части окна, для определенного изображения указанный ломтик изменит свою окраску. При этом значение сопротивления рассчитывается в соответствии с новой маркировкой, а результат выводится на экран. После загрузки страницы ответная реакция на действия пользователя следует незамедлительно. Если же вами используется размещенная на сервере версия приложения-калькулятора, то на изменение цвета уйдет не одна секунда. Более того, JavaScript обладает средствами предварительной загрузки всех используемых вариантов изображений в кэш-память браузера. Данная задача выполняется при загрузке основной страницы. Впоследствии это приводит к незначительному увеличению времени, отведенного на загрузку дополнительных изображений. Однако в дальнейшем при выборе посетителем нового цвета изменения вступят в силу незамедлительно. С таким приложением можно решать определенный круг задач, на которые оно непосредственно рассчитано. Многофреймовые документы Как известно, фреймы попадают в сферу управления HTML, однако они позволяют выполнить намного больше задач, когда за их управление берется JavaScript. Приложение Decision Helper (Помощник принятия решений), представленное на рис. 4.4, в полной мере реализует предоставляемые JavaScript возможности. ев Часть II. Руководство по JavaScript
Fie Ed* View Favorites Took о . © а ш & ■! p & Back . f-orward .Sap Refresh Home. A Seech . Feyartee ',. На».■,«;.,.Я**,.л Ь* ..-■■ Buying a FAX machine i Remit» Far-O-Matic 1000 47 2 InkyFax300 J5R6 LajyFaxLX J72~ Looie Cannon M-200 JJ72.4 _J Step 5: Viewing Results Results are calculated based on the various weights and rankings you entered In previous screens. The specific numbers are not particularly important: their relative positions, however, are what youYe looking for. The highest number represents the alternative rating the highest based on your input. Values are shown to four decimal places In case of close races. Unfortunately, this results screen cam* be printed or saved IT you want to preserve this Information take a screen shot using your operating system's screen capture utility (e.g>, Windows 95: Press PrtSc; MacOS. Press Cmd-8hift-3). Rgvtew "mis pecistan II start i New pgciaton,,, № ШШ m Рис. 4.4. Окно приложения Decision Helper Приложение Decision Helper содержит вполне профессиональный сценарий, использующий четыре вложенных окна (или фрейма) для ввода данных и одно вложенное окно, которое отображает результаты некоторых сложных вычислений, которые основываются на данных, вводимых в остальные четыре фрейма. Результат отображается как в числовом, так и в графическом виде (в качестве диаграмм) — рис. 4.4. Взаимодействие между тремя фреймами основного окна реализуется с помощью JavaScript. Предположим, что пользователь щелкает мышью на кнопке со стрелкой в левом верхнем фрейме. При этом изменится не только документ, отображаемый в правом верхнем фрейме, но и инструкция, расположенная в нижнем фрейме. В нижнем фрейме отображается область анкера, определяемая в соответствии с содержимым фрейма, в который вводятся исходные данные. При составлении сценариев для документов, размещаемых в правом верхнем фрейме, используются различные технические приемы, позволяющие сохранить данные записей в процессе навигации. Такой подход напоминает путешествие по универсаму с корзинкой для выбора товаров. Только в данном случае используется диалоговый подход — сначала обрабатываются данные о заказанных на нескольких страницах каталогах товаров, а затем они суммируются вместе в структурированной и упорядоченной форме. В принципе, работая с подобными приложениями, можно отказаться от использования программ, запускаемых на сервере. Однако помните, что уровень взаимодействия и расчетов, который необходимо обеспечивать при обмене данными между пользователем и приложением, может в определенном случае привести к выполнению сценария с леденящей душу медлительностью. Динамический HTML Начиная с четвертой версии, браузеры Netscape и Microsoft предоставляют все больше и больше возможностей для изменения с помощью клиентских сценариев содержимого страниц. На рис. 4.5, например, показано, как с помощью сценариев реализовано перемещение областей карты Глава 4. Объекты документа и браузера 67
на рисунке. При выборе определенного штата его область подсвечивается соответствующим образом. Панель управления в окне приложения расположена справа, дополнительные элементы появятся только в том случае, если все области карты расположены в необходимых местах. Fta Ь* Vtew Favortas Took Help о ©.a.a#,p#tre0' 3-Э'> Foe- Рис. 4.5. С помощью сценариев и динамического HTML можно создать такую игру Такой высокий уровень взаимодействия браузера со сценариями удается поддерживать благодаря использованию динамического HTML {Dynamic HTML или просто DHTML). При этом JavaScript становится соединительным мостиком между пользователем и используемыми в динамическом режиме элементами на экране. В подобных ситуациях нецелесообразно обращаться к программам, запускаемым на сервере, поскольку приложение должно мгновенно реагировать на манипуляции пользователя с мышью и элементами страницы. И делать это нужно на высоком программном уровне. Принципы использования JavaScript Приведенные выше примеры продемонстрировали широкий диапазон функций JavaScript. Однако JavaScript может выполнить не все задачи. Управлять элементами HTML в Web с помощью JavaScript имеет смысл в таких случаях. ■ Проверка корректности данных, введенных на форме. Если в поле формы нужно ввести данные для дальнейшей обработки сервером, поручите сценариям клиента провести предварительную проверку соответствия введенных на форме данных установленному для такого случая формату. ■ Не использующие сервер CGI-программы. В данном случае нужно либо использовать JavaScript для создания приложения, любо применить CGI-программы, запускаемые на сервере. В последнем случае скорость выполнения операций низкая, поскольку необходимо поддерживать интерактивный режим между программой и пользователем. В него входят такие задачи, как поиск данных небольших объемов, внесение изменений Часть //. Руководство по JavaScript
в изображения, а также генерирование HTML-кода на основе введенных пользователем данных в других окнах и фреймах. ■ Интерактивная работа в динамическом HTML. Если элементы на странице имеют жесткую привязку, то использовать средства DHTML и создавать сценарии для их управления не стоит. Если предполагается, что содержимое будет двигаться по странице произвольным образом, то хороший сценарий будет просто необходим. ■ Создание прототипов CGI-сценариев. Иногда необходимо, чтобы CGI-программа была внедрена в приложение, поскольку это потенциально устраняет проблемы несовместимости между типами и версиями браузеров. Еще проще создать с помощью JavaScript прототип CGI-программы. Эту возможность следует использовать для того, чтобы довести "до ума" пользовательский интерфейс перед тем, как реализовать приложение в качестве серверного CGI-сценария. ■ Разгрузка сервера. Если вами используется очень загруженный Web-узел, то следует отказаться от частого обращения к CGI-программе в пользу применения сценариев JavaScript, выполняющих те же действия. После того как страница загружена, сервер освобождается для обслуживания других посетителей узла. Это снимает загруженность не только сервера, но также позволяет пользователям остальных CGI-программ быстрее получить ответ на введенные ранее данные. ■ Обеспечение динамизма в "мертвых" страницах. Сам по себе язык HTML очень незатейливый. Выделение цветом фрагментов текста удивляет только вначале. Использование анимации с изображениями в формате GIF скорее отвлекает и редко вызвано конкретной необходимостью представления данных. Но если обеспечить страницу пусть даже небольшими интерактивными средствами, то это поможет привлечь пользователей и дать им повод посетить страницу снова или порекомендовать своим друзьям сделать то же самое. ■ Создание "интеллектуальных" Web-страниц. Если позволить воображению разгуляться, то можно разработать новые, интригующие способы обучения своих страниц V "интеллектуально" обрабатывать данные. Например, в приложении главы 54 можно увидеть, как (без использования серверной CGI-программы или баз данных) страница HTML "запоминает" последние посещения страницы пользователем. При этом все элементы, которые были изменены после последнего посещения (независимо от их количества), будут восстановлены в первоначальном виде. Это пример "интеллектуальной" HTML-страницы, который наглядно демонстрирует возможности JavaScript. Объектная модель документа Перед тем как приступить к созданию серьезных сценариев, составьте правильное представление о тех объектах, непосредственно для которых и будут писаться сценарии. Работающий со сценариями браузер выполняет огромную работу по программному созданию объектов, которые потом, в основном, и реализуются в качестве отображаемых на HTML- странице элементов. Объектами являются элементы управления форм (текстовые окна и кнопки), а также (в последних версиях браузеров) изображения. Тем не менее, в модели представлены и другие объекты, которые не столь наглядны с точки зрения внешнего вида страницы и его программной основы. Их назначение, однако, становится вполне понятным, если рассматривать дескрипторы, которые используют в HTML элементы, предназначенные для генерирования содержимого страницы (примером может служить многофреймовая страница). Для того чтобы позволить сценарию управлять всеми этими объектами, а также помочь разработчикам страниц как-то упорядочить огромное количество объектов на страницах, Глава 4. Объекты документа и браузера 69
создатели браузеров придумали объектную модель документа (document object model или DOM). Эта модель является прототипом или структурой организации объектов на странице. Недостаточный уровень совместимости браузеров разных типов и версий повергает создателей сценариев в отчаяние, особенно если (с самого начала) они изучают объектную модель только для последней версии одного типа браузеров — не принимая во внимание ограниченные возможности ранних версий браузеров и браузеров других производителей. Усилия всевозможных организаций по разработке стандартов (вспомните только W3C) привели к созданию спецификаций для синтаксиса и набора свойств объектных моделей, что обеспечило, по сравнению с оригинальными разработками, большую гибкость. Концепция DOM, построенная на основе стандартной объектной модели, с которой можно познакомиться в данном руководстве, реализована с разной степенью поддержки во всех современных браузерах. Если бы на рынке доминировали исключительно браузеры, которые поддерживают стандарт W3C DOM (о том, что это не так, вы узнаете в главе 9), то это бы значительно упростило процесс создания межбраузерных решений и высокодинамичных документов. Однако в любом случае, чтобы иметь достаточный багаж знаний, предстоит многому научиться. Структура HTML и DOM Главное предназначение языка HTML состоит в определении форматирования и структуры документа на уровне составляющих его элементов. Те дни, когда HTML применялся исключительно для определения вида текстовых строк на экране, давно ушли. Сейчас сложно представить себе ситуацию, когда для отображения текстового фрагмента шрифтом большого размера нужно применять только дескриптор <hl> и никакой другой. Дескриптор <hl> имеет специальное назначение в браузере— он определяет в HTML-документе заголовки первого уровня. К счастью, в настоящий момент вам не обязательно для отображения текста абзаца шрифтом большого размера обозначать его как заголовок определенного уровня. Вы всегда можете заключить текст в дескриптор абзаца (<р>), а затем определить форматирование текста этого абзаца с помощью стиля CSS. Подобная практика также распространяется на дескрипторы <Ь> и <i>, с помощью которых задается полужирное и курсивное начертание. Вместо того чтобы заключать форматируемый текст в соответствующий дескриптор, вы можете спокойно применять стили CSS, указывающие все необходимое форматирование. Результатом структурированности HTML является вложение отдельных элементов документа соответственно заранее определенной иерархической таблице. Например, пустой HTML-документ имеет следующую иерархическую структуру. <html> <head></head> <body></body> </html> Как видите, элемент html содержит два вложенных элемента: head и body. Иерархическую структуру подобного документа можно представить в более наглядном виде с помощью организационной диаграммы, как показано на рис. 4.6. Подобно семейному фамильному дереву, в такой иерархической структуре можно легко продемонстрировать родительско-дочер- ние отношения. В случае HTML-документа элемент html является родителем двух вложенных в него дочерних элементов head и body. document html head body Рис. 4.6. Иерархическая структура пустого HTML-документа 70 Часть II. Руководство по JavaScript
Объектная модель окна документа Как и предполагает название, формальная DOM описывает, в основном, HTML-документ и его содержимое. Но уже вскоре вам придется в своих приложениях обращаться не только к элементам документа, но и к элементам среды — окнам браузера. На самом высоком уровне окна браузера располагается объект window. Общая иерархическая структура объектной модели современных браузеров выглядит так, как показано на рис. 4.7. window navigator screen history location document Рис. 4.7. Базовая объектная модель современных браузеров На данном этапе ознакомления с JavaScript нет необходимости запоминать модель. Вам необходимо проанализировать общие методы представления объектов. Ниже описаны некоторые ключевые объекты, показанные на рис. 4.7, и описаны их связи с другими объектами. ■ Объект окна (window). Вверху иерархической структуры находится окно (window). Этот объект представляет ту часть окна браузера, в которой отображается содержимое HTML-документа. В многофреймовой среде каждый фрейм (или кадр) также является окном (детально это пока рассматривать не будем). Поскольку все события, относящиеся к документу, происходят именно в окне, то оно и является самым общим элементом в иерархической структуре объектов. В нем, в буквальном смысле, размещен документ. ■ Объект navigator. С помощью этого объекта определяется браузер, в котором выполняется сценарий. Он содержит сведения о производителе и версии браузера. Этот объект имеет атрибут только чтения (чтобы "зловредные" сценарии не могли получить доступ к свойствам браузера). ■ Объект экрана (screen). Это еще один объект с атрибутом только чтения. Объект screen позволяет определить физическую среду, в которой запускается браузер. Например, с его помощью определяется разрешение экрана. ■ Объект history. Каждый браузер сохраняет сведения об уже посещенных страницах (кнопка Back (Назад) на панели инструментов) в специальном стеке, представленном объектом history. Как и следовало ожидать, этот объект функционально дублирует кнопки Back (Назад) и Forward (Вперед). ■ Объект location. С помощью этого объекта проще всего загрузить в текущее окно целевую страницу или фрейм. Сведения об URL-адресе документа представлены таким образом, чтобы в сценарии нельзя было отследить защищенные Web-узлы. ■ Объект документа (document). Каждый HTML-документ, загружаемый в окно браузера, становится объектом document (документ). В иерархической структуре положение объекта документа (рис. 4.7) является весьма важным. В объекте document содержится большинство остальных типов объектов модели. Со стороны это выглядит просто здорово: в документе находится то, что используется в сценарии. Глава 4. Объекты документа и браузера 71
Загрузка документа Языки программирования (например, JavaScript) являются прекрасными посредниками между представлениями пользователя о том, как работают программы, и тем, что происходит при этом в компьютере на самом деле. Внутри компьютера каждый оператор в листинге программного кода приводит к записыванию и перемещению битов данных (этих легендарных нулей и единиц компьютерного двоичного мира) из одного раздела оперативной памяти в другой. Языки и объектные модели, с точки зрения использования их в самом компьютере (или, в случае использования JavaScript, в области памяти, выделяемой в компьютере для браузера) нужны для того, чтобы программистам было легче представить, как программа работает, и каков будет результат ее выполнения. Ситуация очень похожа на ту, когда нужно проехать автомобилем из пункта А в пункт Б. При этом можно и не знать, как работает двигатель внутреннего сгорания, рулевой привод и вся остальная начинка автомобиля. Вояж можно осуществить, управляя автомобилем с помощью одних только основных элементов: ключа зажигания, рычага переключения передач, педалей газа, сцепления и тормоза, а также руля управления. Конечно, программирование существенно отличается от управления автомобилем с автоматической трансмиссией. Даже для написания сценария нужно (продолжим проводить аналогию) уметь открыть капот и проверить ту же трансмиссию или заменить масло. Поэтому сейчас самое время открыть капот и разобраться, что же происходит с объектной моделью документа при загрузке страницы в браузер. Простой документ На рис. 4.8 приведен код HTML и соответствующая ему объектная модель для очень простого документа. Когда происходит загрузка соответствующей страницы, в памяти браузера реализуется поддержка структуры объектов, сгенерированных согласно использованным в документе дескрипторам HTML. На рисунке показана только часть иерархической структуры окна документа, начиная с объекта document. Этот объект детально будет описан позже, а сейчас просто имейте в виду, что он существует, поскольку это часть объектной модели в памяти браузера. На диаграмме он выделен полужирным начертанием. В приведенном примере в объект document вложено три объекта, один из которых, html, расположен на более высоком уровне. <html> <head></head> <body></body> </html> document html head body Рис. 4.8. Простой документ и структура его объектов Добавление элемента абзаца Теперь можно переделать файл HTML так, чтобы он содержал пустой элемент абзаца. На рис. 4.9 показано, как при этом изменится документ HTML (изменения выделены полужирным начертанием) и соответствующая ему структура объектов, создаваемая браузером. Даже если 72 Часть //. Руководство по JavaScript
между дескрипторами формы <р> ничего не введено, одного их наличия достаточно для того, чтобы браузер создал объект абзаца в объекте body. Обратите внимание также на то, что объект body, согласно текущей иерархической структуре, является дочерним для объекта документа. <html> <headx/head> <body> <Р></Р> </body> </html> document html i head 1 body 1 P Рис. 4.9. Если добавить абзац, то получится такая структура объектов Добавление в абзац текста Продолжаем вносить изменения в файл — на этот раз добавим в абзац текст и разместим его между открывающим и закрывающим дескрипторами. Результат выполнения этой процедуры можно увидеть на рис. 4.10. Добавление текста между дескрипторами приводит к добавлению в DOM специального типа объектов, называемого текстовым узлом (node). Для текстового узла всегда определяется объект, в котором содержится текст, — контейнер. Применяя стандартную терминологию, можно сказать, что текстовый узел является дочерним по отношению к контейнеру р. <html> <headx/head> <body> <p>This is the one and only paragraph.</p> </body> </html> document html head body "This Is the one and only paragraph.' Рис. 4.10. Добавление в абзац текста Глава 4. Объекты документа и браузера 73
Создание нового элемента Последнее изменение файла состоит в добавлении в текст абзаца дескриптора <ет>, с помощью которого фрагмент абзаца выделяется другим начертанием (рис. 4.11). Даже такая простая операция вызывает изменение в иерархической структуре документа. Обратите внимание, что теперь объект р имеет три вложенных объекта: два текстовых узла и элемент между ними. В W3C DOM текстовый узел не может иметь дочерних объектов, а потому не содержит других элементов. Наряду с этим текст, заключенный в дескриптор <етп>, не является дочерним по отношению к объекту р, а вкладывается в объект em. Таким образом, текстовый узел элемента em расположен на два уровня ниже элемента абзаца. <html> <headx/head> <body> <p>This is the <em>one and only</em> paragraph.</p> </body> </html> document html head body X "This is the" em "paragraph." "one and only" Рис. 4.Л. Добавление в текстовый узел элемента Надеемся, у вас уже сложилось определенное представление о том, как в соответствии с дескрипторами HTML создаются объекты в памяти браузера. Далее мы перейдем к рассмотрению способов взаимодействия сценария с этими объектами. Отметим, что создание сценариев является одним из основных методов управления объектами. Связывание объектов Если документ загружен в браузер, все его объекты надежно размещены в памяти согласно той внутренней иерархии, которая определяется объектной моделью документа браузера. Чтобы сценарий мог управлять любым из этих объектов, должен существовать способ получения доступа к объекту и взаимодействия с ним. Примерно так: "Привет, мистер Текстовое Поле! Что там ввел пользователь?". Если в сценарии необходимо определить расположение одного из этих объектов, то сценарий должен указать тот путь, по которому следует двигаться для установления контакта с нужным объектом. Это именно то, что называется в сценарии ссылкой на объект, которая задается браузером. 74 Часть //. Руководство по JavaScript
Именование объектов Наилучший способ создания в сценариях ссылок на объекты заключается в том, чтобы присвоить каждому управляемому в документе HTML-объекту в сценарии собственное имя. В W3C DOM (и текущей спецификации HTML) для определения элементу имени применяют атрибут id (идентификатор). Этот атрибут необязательный, но он позволяет однозначно присвоить каждому объекту собственное имя. Если вы планируете получать в сценарии доступ к элементам страницы, то без него вам не обойтись. Ниже приведен пример использования атрибута id вместе с обычными дескрипторами. <р id=nfirstParagraphn > <img ids"logo" src="images/logo.jpg" alt="Corp Logo"> <div class="draggable" id«"puzzlePiecen> При присвоении имен (названий, идентификаторов) придерживаются следующих правил. ■ Имена не могут содержать пробелы. ■ В именах не должны использоваться символы пунктуации, за исключением символов подчеркивания. ■ При их присвоении в качестве значения атрибуту name они должны заключаться в кавычки. ■ Имена не должны начинаться с цифры. Процесс присвоения имен можно сравнить с ситуацией, когда на конференции всем ее участникам выдают бейджи с именами. Чтобы найти необходимого вам человека, вам нужно встать у входа и быстро просмотреть бейджи каждого входящего. Вы также можете поискать в зале в надежде найти того, кто вам нужен. Ссылка на объект В W3C DOM вы быстро получите доступ к любому именованному элементу документа. Если вы ранее не занимались программированием, то ссылка на объект может вас обескуражить своей сложностью. Как бы там ни было, вам придется смириться с предложенным в W3C синтаксисом — вы будете использовать его в JavaScript повсеместно. Ниже приведен пример используемой в JavaScript ссылки на объект. window.document.getElementByld("ИдентификаторОбъекта") В этом коде элемент определяется по идентификатору, задаваемому выражением ИдентификаторОбъекта. Например, если вы хотите обратиться в сценарии к элементу абзаца с идентификатором first Paragraph, то используйте следующую ссылку. window.document.getElementByld(иfirstParagraph") Обратите внимание на то, что имена ключевых слов в JavaScript чувствительны к регистру. В методе getElementByld () используется три буквы в верхнем регистре (хотя так и хочется написать не Id, a ID). Метод getElementByld () относится к объекту document. Таким образом, с его помощью вы можете найти любой элемент документа, идентификатор которого вам известен. В JavaScript для разделения элементов иерархической ссылки используется точка. Каждая ссылка обычно начинается с наиболее глобального уровня (здесь объект document) и дальше с использованием точки (.) в качестве разделителя выполняется все большая конкретизация ссылки. Каждый объект имеет свой набор вложенных объектов (детально с ними.вы можете ознакомиться в приложении А). Глава 4. Объекты документа и браузера 75
Атрибут name и идентификатор id До спецификации HTML 4.0, в которой впервые был представлен атрибут id, доступ к объектам в сценарии реализовался с помощью атрибута name. Элементы, которые поддерживают атрибут name, обычно предназначены для управления изображениями, формами и фреймами. Детально с атрибутом name объектов вы ознакомитесь в главе 9. На самом деле большинство браузеров по-прежнему распознают этот атрибут. Более того, только с его помощью во многих системах можно передать на сервер данные, которые введены в текстовые поля, выбранные в списках пользовательской формы. Исходя из этого, настоятельно рекомендуется одному и тому же объекту назначать одинаковые атрибуты id и name. Терминология, используемая при управлении узлами В терминологии W3C DOM для описания иерархической структуры объектов применяют некоторые метафорические приемы. С одним из них вы должны ознакомиться на самых первых этапах изучения языка JavaScript. Речь идет об узлах. Еще одним важным понятием являются родительско-дочерние отношения между объектами. Что такое узел Словарь английского языка фиксирует несколько значений слова узел. Одно из них (наиболее близкое к используемому в W3C DOM) — нарост, почка на ветке дерева. Обычно такое образование на ветке впоследствии приводит к возникновению нового листика или побега. Если говорить о листике, то мы получаем тупиковую ситуацию, в которой дальнейшее развитие узла невозможно (из листа не вырастет другая ветка). А вот из побега мы имеем шанс получить другие ветки или листья, т.е. дочерние узлы. При определении структуры HTML- документа вы также определяете его узлы (создаете так назьшаемое дерево узлов, расположение веток и листьев на котором полностью зависит от используемых в документе элементов). В W3C DOM основным элементом является простой узел. В документе HTML нам придется работать преимущественно с двумя специальными типами узлов — узлами элементов и текстовыми узлами. В первом случае узел соответствует элементу документа, а во втором — тексту, введенному между открывающим и закрывающим дескрипторами элемента. Зачастую вы будете управлять узлами обоих типов, даже не догадываясь об этом. Предлагаем вернуться к уже рассмотренной ранее модели, иерархическая структура которой отображена на диаграмме (рис. 4.12). Каждый блок диаграммы представляет отдельный объект документа. К узлам элементов относятся document, html, head, body, p и em. Три текстовых узла представлены блоками на нижних уровнях структуры: они содержат текст, заключенный в кавычки. Как вы видели ранее, после добавления в длинную текстовую строку нового элемента (em) один текстовый узел был разделен на три небольших текстовых узла. Два текстовых узла остались на том же уровне иерархической структуры, и только один сместился на уровень ниже — тот, который помещается в добавленный элемент em. Отцы и дети Внимательно изучите элемент р на рис. 4.12 — он имеет три дочерних узла. Первый и последний представлены текстовыми узлами, а второй — узлом элемента. Если элемент имеет несколько дочерних (вложенных) узлов, то их порядок перечисления определяется исключительно 76 Часть II. Руководство по JavaScript
порядком их представления в HTML-коде. Таким образом, первый дочерний объект элемента р — это текстовый узел, содержащий фразу "This is the ". В случае элемента em долго гадать не приходится — он имеет только один дочерний узел. <html> <headx/head> <body> <p>This is the <em>one and only</em> paragraph. </p> </body> </html> document html head body "This is the" em "paragraph." "one and only" Рис. 4. 12. Дерево узлов документа HTML Дочерними объектами элемента далеко не всегда выступают текстовые узлы. На рис. 4.12 объект html имеет два дочерних узла элементов body и head. Первый из них содержит всего один вложенный узел — р. Несмотря на то, что объект head является тупиковой ветвью, он представляет узел элемента, а потому может включать в себя другие узлы элементов и текстовые узлы (например, элемент title). Как нетрудно заметить, дескриптор HTML представляет узел элемента, независимо от того, имеет ли он дочерние узлы. Наряду с этим, текстовый узел — это всегда тупиковая ветвь иерархической структуры. Обратите также внимание, что дочерний узел всегда содержится в узле элемента. Этот контейнер представляет собой родительский узел. Таким образом, в рассмотренной выше иерархической структуре элемент em имеет один дочерний текстовый узел и родительский узел элемента р. Чтобы детально разобраться в терминологии W3C (см. главу 14), вам необходимо хорошо ориентироваться в иерархической структуре создаваемого документа. Например, в DHTML для редактирования текста, добавленного в элемент em (рис. 4.12), ссылка на необходимый фрагмент будет начинаться с обращения к контейнеру текстового узла: document. getElementByld (). При этом предполагается, что элементу em уже назначен атрибут Id. Если вы этого eine не поняли, то я попробую удивить вас тем, что объект document в начале ссылки также является узлом элемента. Как правило, его называют узлом документа. Каждый документ имеет только один узел документа, и именно этот узел предоставляет программисту доступ к остальным узлам документа. Поэтому нет ничего удивительного в том, что ссылка на объекты в документе по атрибуту id начинается именно с указания узла document. Понятия, определяющие объект Если при загрузке страницы браузер обнаруживает в исходном коде дескриптор HTML, который определяет объект, то для этого объекта в памяти будет выделена специальная область. Однако понятно, что объект — это нечто более сложное, чем, скажем, обычное число, Глава 4. Объекты документа и браузера 77
записанное в память. Объект должен представить некоторую "структуру". Поскольку в JavaScript приходится иметь дело с элементами, которые появляются в окне браузера, то объектами могут быть текстовые поля для ввода данных, кнопки или даже весь документ HTML. Выходя за рамки ограниченного мира браузера, поддерживающего JavaScript, важно отметить, что объект может представлять и довольно абстрактные понятия (например, записи в программе электронного календаря или слой графических изображений в графическом редакторе). Каждый объект неповторим в своем роде, даже если в браузере такие объекты выглядят очень похоже. Существует три основных фактора, которые непосредственно определяют объект. Они дают представление о том, чем является данный объект, как он выглядит и как с помощью сценариев им можно управлять. Этими тремя определителями являются свойства, методы и обработчики событий. С точки зрения работы в JavaScript, они очень важны. В приложении А приведены полные данные о свойствах, методах и обработчиках событий для каждого элемента объектных моделей, используемых в различных поколениях браузеров. Свойства Каждый реальный физический объект, который читателю приходилось когда-либо держать в руках, обладает особыми характеристиками, которые определяют его поведение. Монета, например, имеет определенную форму, диаметр, толщину, цвет, вес, чеканное изображение на каждой стороне и огромное количество других атрибутов, которые отличают ее, скажем, от пера птицы. Каждая такая характеристика называется свойством. Каждому свойству соответствует определенное значение (даже если это значение не определено, то свойство равно null). Например, свойством для формы монеты можно определить "круглая" — в этом случае оно принимает текстовое значение. В качестве значения свойства, определяющего достоинство монеты, скорее всего будет использована числовая величина. При написании кода HTML (для использования в поддерживающих сценарии браузерах) свойства объектов устанавливаются даже без явного использования кода JavaScript. Наиболее общий способ начальной установки свойств объектов HTML состоит в использовании атрибутов дескрипторов. Например, следующий дескриптор HTML применяется для того, чтобы определить объект кнопки button. Здесь же присваиваются значения для двух свойств. <input type="button" id=Mclicker" name="clicker" value="Hit Me..."> В JavaScript свойства id и name имеют значение clicker, в то время как для свойства value определено текстовое значение Hit Me..., которое будет отображено на кнопке. На самом деле кнопка имеет более двух свойств, однако необходимости устанавливать сразу все свойства для каждого объекта нет. Для большинства свойств предусмотрены используемые по умолчанию значения, которые им автоматически и присваиваются, если ничего другого в коде HTML или в сценарии им не назначено. Значение некоторых свойств может быть изменено в процессе загрузки документа и взаимодействия пользователя со страницей. Рассмотрим такой пример с использованием дескриптора описания текстового поля. <input type="text" id="entry" name=" entry" value="User Name?"> Свойства id и name данного объекта имеют значение entry. Когда происходит загрузка страницы, текстовое значение атрибута value будет выведено в текстовом поле. Это пример поведения текстового поля в HTML с использованием атрибута value. Но если пользователь введет в текстовое поле что-то другое, то значение свойства value изменится — однако не в HTML, а в поддерживаемой браузером копии объектной модели, хранящейся в памяти. Поэтому, если сценарий обращается к текстовому полю с целью получения значения свойства value, браузер выдаст текущее значение свойства. В случае если пользователем вносились изменения в текст, то это будет далеко не то значение, что указано в коде HTML. 78 Часть II. Руководство по JavaScript
Для получения доступа к свойству объекта используется тот же тип синтаксиса с исполь-1 зованием точек, что и в иерархической структуре, описанной ранее для объектов. Каждое свойство принадлежит своему объекту, а ссылка на свойство состоит из ссылки на данный объект плюс еще одно дополнительное расширение, указывающее на нужное свойство. Поэтому для описанных выше дескрипторов кнопок и текстовых объектов ссылки на различные их свойства выглядят так. document.getElementById("clicker").name document.getElementById("clicker").value document.getElementById("entry").value Отсутствие в ссылке указателя на window может вызвать удивление. Как уже отмечалось, одно окно может содержать только один документ. Поэтому при ссылке на объект внутри документа вы можете не использовать указатель window в ссылке — начинайте сразу с document. Тем не менее, пропустить в ссылке указатель на document нельзя. Ссылки в Internet Explorer В W3C DOM Microsoft предложила ссылку на элемент объекта заменить простым указанием атрибута id для данного элемента (если такой элементу присвоен). В таком случае код будет легче читать и понимать даже спустя некоторое время после его написания. Такой поход, тем не менее, уместен только в Internet Explorer 4 и выше. Чаще всего ссылка на объект по атрибуту id начинается с выражения document.all. Вы можете встретить и другие варианты, но все они будут справедливы только для последних версий браузеров Microsoft. Например, если элемент абзаца имеет идентификатор myParagraph, то в коде к нему можно обратиться с помощью следующего выражения. document.all.myParagraph Вы всегда вправе опустить первую часть выражения и оставить только значение атрибута id. myParagraph Как ни странно, но ни один из вариантов синтаксиса не соответствует стандарту W3C DOM. Только в IE5 и выше реализована полная поддержка обоих вариантов ссылок. Забегая наперед, скажу, что вам придется "подгонять" подобный синтаксис под стандарты W3C, чтобы он корректно выполнялся в большинстве браузеров. Методы Если свойство объекта можно сравнить с прилагательным, то метод будет соответствовать глаголу. Под методом понимают все, что имеет отношение к действиям объекта. Метод может, скорее, выполнить что-то для объекта или с объектом, чем воздействовать на другие компоненты сценария или документа. По своей сути это команды, но способ и характер их выполнения связаны с конкретным объектом. С объектом можно связать любое количество методов (или их может не быть вообще). Чтобы задействовать метод (обычно это называется вызовом метода), в операторе JavaScript нужно сделать на него ссылку— через соответствующий объект с использованием после имени метода пары скобок (см. следующий пример). document.getElementByld("orderForm").submit() document.getElementByld("entry").focus() В первом случае сценарий используется для того, чтобы по щелчку на кнопке Submit (Отправить) отправить форму (которая называется orderForm) на сервер. Во втором случае производится выделение текста в текстовом поле с именем entry. В некоторых случаях для выполнения поставленной задачи, методу необходимо сообщить дополнительную информацию. Каждая порция такого рода данных, передаваемых методу, называется параметром или аргументом (можно использовать эти термины параллельно). Глава 4. Объекты документа и браузера 79
Пример использования параметров можно найти в первом сценарии, описанном в предыдущей главе, где был задействован метод write () объекта document. document.write("This browser is version " + navigator.appVersion) document.write(" of <b>" + navigator.appName + "</b>.") Когда страница загружается в браузер, каждый метод document .write () отправляет в текущий документ весь содержащийся в скобках текст. В обоих приведенных примерах содержимое будет отправлено как параметр, состоящий из обычного текста (заключенного в кавычки) и значения двух свойств объекта: это свойства appVersion и appName объекта navigator. Некоторым методам нужно указать больше одного параметра. В таком случае параметры следует отделять друг от друга запятыми. Например, в версиях браузеров, начиная с четвертой, объектом window поддерживается метод, который перемещает окно к определенной точке на экране. Эта точка задается двумя числами (координатами), которые указывают количество пикселей от левого и верхнего краев экрана, соответственно, до точки, где должен располагаться левый верхний угол окна. Для перемещения окна браузера на 50 пикселей влево и на 100 пикселей вниз можно использовать такой код. window.moveTo(50,100) , При изучении особенностей работы в JavaScript и описываемых объектов документа следует обращать особое внимание на те методы, которые применяются для каждого подобного объекта. Это поможет определить функции объекта и способы управления им в сценариях. Обработчики событий Еще одной важной характеристикой объектов в JavaScript являются обработчики событий. Событиями называется все, что происходит в документе. Как правило, это результат действий пользователя. Общим примером действий пользователя, продуцирующих события, является щелчок мышью на кнопке или введение в текстовое поле символа. Другие события (например, процесс загрузки документа в окно браузера или появление ошибки при загрузке изображения) столь очевидными не являются. В документе практически все объекты JavaScript получают сообщения того или иного рода (см. приложение А, раздел справочных сведений). Чтобы определить, как должен реагировать объект на событие, воспользуйтесь дополнительным атрибутом, который вводится в HTML при описании объекта. Этот атрибут состоит из имени события, знака равенства (как и любой атрибут в HTML), после которого следует инструкция, указывающая на то, что же нужно делать при наступлении конкретного события. В листинге 4.1 приведен пример очень простого документа, где отображается всего одна кнопка, для которой определен единственный обработчик события. <html> <body> <form> <input type="button" value="click me" onclick="window.alert ('ouch!')"> </form> </body> </html> Описание формы внешне ничем не отличается. Однако стоит обратить внимание на последний атрибут onclick="window.alert ('OuchI •) ". Объекты кнопок (как в этом можно будет убедиться в главе 22) реагируют на щелчки мышью. Когда пользователь щелкает 80 Часть II. Руководство по JavaScript
на кнопке, браузер отправляет кнопке сообщение о щелчке. В описании этой кнопки с помощью специального атрибута указано следующее: когда бы кнопка ни получила такое сообщение, она должна задействовать один из методов объекта окна window с именем alert (). Метод alert () отображает обычное диалоговое окно предупреждения, содержимым которого является текст, указанный в качестве параметра данного метода. Как и большинство аргументов атрибутов HTML, значения в правой части после знака равенства заключаются в кавычки. Если при этом нужно еще раз использовать кавычки (как в данном случае, когда в качестве параметра передается еще и текст), то в качестве таких внутренних разделителей используются одинарные кавычки. В принципе, для JavaScript особой разницы нет, какие кавычки используются — одинарные или двойные. Просто нужно придерживаться принципа соответствия типов кавычек. Это значит, что можно описать атрибут таким образом. onclick='alert("Ouch!") » Упражнения 1. Какую из приведенных далее задач с точки зрения клиента можно выполнить с помощью JavaScript? Ответ объясните. а) Воспроизведение музыки. б) Средство подсчета посетителей Web-узла. в) Комната бесед. г) Графическое средство переведения показаний градусника из градусов Фаренгейта в градусы Цельсия. д) Все из вышеперечисленного. е) Ни одно из вышеперечисленных. 2. Какие имена являются корректными в JavaScript? Ответ объясните. а) last Name. б) company_name. в) IstLineAddress. г) zip code. д) today' s__date. 3. Используя диаграмму на рис. 4.12 в качестве основы, нарисуйте диаграмму иерархической структуры, представляющей следующий HTML-код. Напишите ссылку на элемент второго абзаца в стандарте W3C DOM. <html> <head> <title>Search Form</title> </head> <body> <p id="logoPar"><img src="images/logo.jpg" height="90" width="300" alt="Logo" /></p> <p id="formParM> <forra name="searchForm" action="cgi-bin/search.pl" method="POST"> Search for: <input type="text" name="searchText" /> <input type="submit" value="Search" /> </form> Глава 4. Объекты документа и браузера 81
</р> </body> </html> 4. Приведите две общие характеристики для текстового узла и узла элемента. Назовите две разные характеристики этих типов узлов. 5. Напишите дескриптор HTML для элемента кнопки с именем Hi, на которой отображается надпись Howdy (Привет), а обработчик события onclick вызывает диалоговое окно предупреждения, содержащее строку Hello to you, too! (Привет и тебе!). 82 Часть II. Руководство по JavaScript
Сценарии и документы HTML этой главе вы узнаете, как сценарии встраиваются в HTML-документы и из чего состоит код сценариев. Речь также пойдет о том, как при загрузке документа или в ответ на действия пользователя эти операторы выполняются. Кроме того, будут описаны способы поиска ошибок в сценариях. Размещение сценариев в документах В главе 4, к сожалению, вопрос о том, как именно выглядят сценарии или в каком месте их следует добавлять в документ HTML, не затрагивался. В данной главе мы наверстаем упущенное. Дескрипторы сценария <script> Чтобы браузер -мог узнать те строки кода в документе HTML, которые соответствуют сценарию, этот код следует выделить с помощью дескрипторов <script >. . . <\ script >. Такой подход является общим в HTML. Между открывающим и закрывающим дескрипторами размещается определенное содержимое, которое находится под управлением этих дескрипторов. В этом можно убедиться хотя бы на примере описания форм и абзацев текста. Для управления сценарием в дескрипторе <script> можно использовать различные атрибуты, которые зависят от типа используемого браузера. Один из атрибутов, которые поддерживают браузеры, управляющие сценариями, является type (тип). Данный атрибут имеет огромное значение, поскольку в разных типах и версиях браузеров указываются различные параметры для используемого языка написания сценариев (это может быть, например, VBScript, в Internet Explorer). Один из параметров, который воспринимают все поддерживающие сценарии браузеры, приведен ниже. <script type="text/javascript">
Обязательно убедитесь, что в код добавлен дескриптор окончания сценария. Все строки кода JavaScript должны располагаться между двумя дескрипторами начала и завершения сценария. <script type="text/javascript"> одна или больше строк кода JavaScript </script> Если не поставить дескриптор завершения сценария, то он может просто не запуститься, а документ HTML на странице будет выглядеть довольно странно. Будущие атрибуты Вы можете использовать в коде сценария еще один атрибут определения языка — language. Он часто применяется вместо атрибута type. Например, чтобы указать браузерам четвертого поколения (поддерживают JavaScript 1.2) обрабатывать сценарии, необходимо добавить в HTML-код следующий дескриптор. <script language="JavaScriptl.2">...</script> Атрибут language поддерживается только в спецификации HTML 4.0, которая уже давно не считается современной. В стандарте W3C DOM (например IE5+ и NN6+) активно применяется атрибут type. Вместе с тем, атрибут language все еще используется и будет использоваться довольно долго, поскольку с атрибутом type знакомы только новые версии браузеров. Существует еще один атрибут, который используется в коде для включения содержимого внешнего файла со сценарием в текущий документ. На данном этапе он использоваться не будет, но знать о нем нужно. Атрибут src (аналогичный атрибуту src дескриптора <img>) указывает на файл, содержащий код сценария. Такие файлы должны иметь расширение . j s. Дескриптор выглядят при этом следующим образом. <script type=" text/ javascript" src="myscript. js"x/script> Все строки кода находятся во внешнем файле, поэтому в документе между дескрипторами начала и завершения сценария никакие данные не вводятся. Размещение дескрипторов Так где же в документе нужно размещать дескрипторы? Ответ такой: везде, где это необходимо. Иногда имеет смысл разместить их между дескрипторами <head>. . .</head>. В других случаях требуется разместить сценарий в весьма специфических частях раздела <body> . . . </body>. Следующие четыре листинга (реализуемые с помощью шаблонного документа HTML) являются примерами того, как и где размещать дескрипторы сценария <script >. Несколько позже мы детально объясним, как, в зависимости от предъявляемых к сценарию требований, выбрать место размещения сценария в документе. В листинге 5.1 приведена общая схема наиболее распространенного способа использования дескрипторов сценария <script> в разделе <head>. Заголовок страницы (второй вариант) является хорошим местом для тех дескрипторов, которые непосредственно влияют на параметры страницы, напрямую не связанные с ее содержимым. Это так называемые управляющие HTML-элементы— дескриптор <meta> или имя документа. Однако здесь удобно размещать и сценарии, которые впоследствии вызываются в ответ на действия пользователя. 84 Часть II. Руководство по JavaScript
М, Сценарий в разделе заголовка <html> <head> <title>A Document</title> <script type-"text/javascriptM> //здесь размещаются строки кода </ecript> </head> <body> </body> </html> С другой стороны, если нужно, чтобы сценарий запускался при загрузке страницы и генерировал ее содержимое, его следует разместить в разделе <body> — листинг 5.2 (см. главу 3, в которой сценарий размещен именно в указанном разделе). Дело в том. что сценарий должен получить информацию о браузере и отобразить результат на странице при ее загрузке. <html> <head> <title>A Document</title> </head> <body> cscript type-"text/javascript1^ //здесь размещаются строки кода </script> </script> </body> </html> Приятно осознавать, что в документе может быть размещено неограниченное количество дескрипторов <script>. Например, в листинге 5,3 сценарий размещается как в разделе заголовка, так и в теле документа. Размещение сценария в теле документа целесообразно, если, скажем, при загрузке страницы нужно создать динамические структуры. На тот случай, если документ содержит кнопки, при щелчке на которых будет запускаться другой сценарий, то этот сценарий необходимо добавить в раздел заголовка. <html> <head> <title>A Document</title> <ecript type-"text/javascript"> //здесь размещаются строки кода </script> </head> <body> <script type»"text/javascript"> //здесь размещаются строки кода Глава 5. Сценарии и документы HTML 85
</script> </body> </html> He существует ограничения также на то, сколько дескрипторов сценария <script> размещать в разделах заголовка и тела документа. В документ можно включить столько дескрипторов <script>, сколько того требует приложение. В листинге 5.4 в качестве примера показано использование двух пар дескрипторов <script > в теле документа, между которыми расположены фрагменты HTML-кода. .'\>; ^/;у* ,/-:Ж <html> <head> <title>A Document</title> </head> <body> <script type*"text/javascript"> //здесь размещаются строки кода </ecript> <more html> //код HTML <script type» "text/javascripts //здесь размещаются строки кода </ecript> </body> </html> Особенности использования старых браузеров Только те браузеры, которые оснащены средствами поддержки JavaScript, знают, как интерпретировать в виде сценария строки кода между парой дескрипторов <script > . . </script >, и не путают их с текстом HTML, отображаемым в браузере. Это значит, что браузеры, которые появились раньше JavaScript, не только игнорируют дескрипторы, но и трактуют код JavaScript как содержимое страницы. Результат может быть весьма плачевным. Чтобы уменьшить риск отображения старыми версиями браузеров строк кода сценария на странице, можно воспользоваться нехитрым приемом. Основная его идея состоит в том, чтобы заключить строки кода сценария между символами комментария HTML, как это показано в листинге 5.5. Большинство не поддерживающих сценарии браузеров игнорируют то, что находится между дескрипторами комментариев <!--и-->,вто время как поддерживающие сценарии браузеры игнорируют эти символы, если они появляются внутри дескрипторов сценария <script >. <script type="text/JavaScript"> //здесь размещаются строки кода </script> 86 Часть II. Руководство по JavaScript
Странная конструкция перед самым дескриптором окончания сценария требует некоторых пояснений. Две косые черты являются символами комментария в JavaScript. Эти символы необходимо использовать, поскольку в противном случае JavaScript будет пытаться интерпретировать закрывающие символы (- - >) комментария HTML. Поэтому косые линии дают указание JavaScript полностью пропустить всю строку. Браузеры же старых версий будут интерпретировать эти символы как часть комментария HTML, которую нужно игнорировать. Несмотря на то, что такая методика скрывает сценарии, все же полностью сценарий при этом не маскируется. Все клиентские сценарии JavaScript являются частью документа HTML и загружаются в браузер подобно другим элементам HTML. Более того, их можно просматривать как составную часть исходного кода. Таким образом, описанным выше способом вы не спрячете сценарий от любопытных глаз. Операторы JavaScript Виртуально, каждая строка кода, расположенная между парой дескрипторов <script>. . .</script>, является оператором JavaScript. Более опытные пользователи могут обеспечить более удобную работу, если в конце каждого оператора JavaScript (подобно другим языкам программирования) будут ставить точку с запятой. К счастью, начинающим пользователям, использовать эту точку с запятой не обязательно. Символа возврата каретки в конце оператора JavaScript вполне достаточно, чтобы понять, что он завершен. В сценарии каждый оператор выполняет определенную задачу, делает что-то, имеющее непосредственное отношение к сценарию. Операторы используются, как правило, чтобы: ■ определить или инициализировать переменную; ■ присвоить значение свойству или переменной; ■ изменить значение свойства или переменной; ■ запустить функциональную программу; ■ принять решение. Если не все из перечисленного выше пока понятно, не волнуйтесь — вскоре все станет ясно. Подчеркнем еще раз— использование любого оператора в сценарии должно быть обосновано. Единственный оператор, который явно не выполняет ни одного действия, — это комментарий. Пара косых черт (без пробела между ними) — это наиболее простой способ включения комментария в сценарий. Комментарии в сценарий разработчики программных продуктов добавляют для собственного удобства. В них, как правило, объясняется назначение отдельных операторов или целых групп. Цель состоит в следующем: даже по прошествии шести месяцев вы сможете быстро восстановить в памяти принципы работы сценария. Выполнение операторов сценария Теперь, когда выяснен вопрос о том, где в документе размещаются сценарии, наступило самое время узнать, как же эти сценарии запускаются. В зависимости от целей, с которыми используется сценарий, существует четыре способа определения момента запуска сценария: ■ при загрузке документа; ■ сразу после загрузки документа; ■ в ответ на действия пользователя; ■ при вызове в результате выполнения оператора другого сценария. Определяющим фактором в данном случае является то, где операторы вызова сценария размещены в документе. Глава 5. Сценарии и документы HTML 87
Немедленное выполнение операторов в процессе загрузки документа Первый сценарий в главе 3 (воспроизведенный в листинге 5.6) запускается при загрузке документа в браузер. Для этого приложения важно то, что сценарий проверяет некоторые свойства объекта navigator и включает значения этих свойств в содержимое страницы при загрузке. Поэтому имеет смысл включить дескрипторы <script> и описание сценария в основной раздел тела документа. Операторы, которые выполнятся при загрузке страницы, можно было бы назвать операторами немедленного выполнения. Листинг 5.6. Страница НШ въшадивния еденэри* <html> <head> <title>My First Script</title> //Мой первый сценарий <style type="text/css"> .highlight {font-weight: bold} </style> </head> <body> <hl>Let's Script...</hl> //Составим сценарий... <hr> <script type="text/javascript"> <!-- Чтобы скрыть от браузеров старых версий document.write("This browser is version " + navigator.appVersion); document.write(" of <span class='highlight■>" + navigator.appName + "</span>.") ; // Окончание скрытия сценария --> </script> </body> </html> Отсроченные сценарии Три другие способа выполнения операторов сценария можно отнести к группе отсроченных сценариев. Чтобы объяснить принципы использования таких отсроченных сценариев, придется задействовать концепцию, которая подробно изложена в главе 7. Речь идет о функциях. Функция — это блок операторов сценария, вызываемых через некоторое время после того, как эти операторы загружены в браузер. Функции легко заметны внутри дескрипторов <script >, поскольку определение каждой функции начинается со слова function, после которого следует ее имя (и скобки). Как только функция будет загружена в браузер (обычно она находится в разделе заголовка, поскольку он загружается раньше), она готова к вызову, когда бы он ни последовал. Например, функция может вызываться для выполнения сразу после загрузки страницы. Объект окна window имеет обработчик события, который называется onload. В отличие от большинства обработчиков событии, которые выполняются как ответ на действия пользователя (например при щелчке на кнопке), обработчик события onLoad задействуется в тот самый момент, когда все компоненты страницы (включая изображения, аплеты Java и встроенные мультимедийные ресурсы) загружаются в браузер. Обработчик события onload размещается внутри дескриптора <body>, как это показано в листинге 5.7. В главе 4 (листинг 4.1) речь шла о том, как с помощью обработчика события непосредственно выполнить операторы сценария. Но если 88 Часть //. Руководство по JavaScript
обработчик события должен запустить сразу несколько операторов, то иногда удобнее поместить эти операторы в описание функции. Теперь обработчик события будет вызывать данную функцию. Это и продемонстрировано в листинге 5.7: после завершения загрузки страницы обработчик события onLoad запускает функцию done (). Эта функция (весьма упрощенная для данного примера) отображает диалоговое окно с предупреждением. Листинг 5.7. Запуск сценария с тжо^ <html> <head> <title>An onLoad script</title> <script type="text/JavaScript"> function done() { alert("The page has finished loading."); //Загрузка завершена } // --> </script> </head> <body onload="done()"> Текст страницы. </body> </html> He стоит беспокоиться по поводу использования фигурных скобок и других непонятных конструкций в листинге 5.7. Это не принципиально. Обратите внимание на структуру документа и порядок выполнения операций. Страница полностью загружается без выполнения операторов сценария, хотя при этом в память и загружается функция done (). Так что ее можно запустить в любой момент. После загрузки документа браузер вызывает обработчик события onload, который и запускает функцию done (). Только после этого пользователь увидит диалоговое окно с предупреждением. Запустить сценарий в ответ на действия пользователя можно практически так же, как в предыдущем примере — отсроченный сценарий выполнялся сразу после загрузки документа. Идея заключается в том, что в разделе заголовка определяется только функция сценария, а обработчик события (скажем, элемента формы) вызывает эту функцию из тела страницы. В листинге 5.8 приведен пример сценария, который запускается при щелчке на кнопке. Яистийг 5.8, Запуск с^^ <html> <head> <title>An onClick script</title> <script type="text/javascript"> <! - - function alertUserO { alert("Ough!"); } //--> </script> </head> <body> Текст страницы. <form> <input type="text" name="entry"> Глава 5. Сценарии и документы HTML 89
<input type="button" name="oneButton" value="Press Me!" onclick="alertUser()"> </form> </body> </html> He все объекты должен иметь обработчик события, определяемый в HTML (листинг 5.8), а только те из них, которые используются в сценарии. Согласно коду в листинге 5.8, ни один оператор сценария не будет выполняться до того момента, пока пользователь не щелкнет на кнопке. Функция alertUser () определяется при загрузке страницы и находится в ожидании запуска на протяжении всего времени, пока страница загружена в браузер. Если ее не запустят, никакого вреда от этого не будет. Последний рассматриваемый сценарий также подразумевает использование функций. Только в этом случае функция вызывается с помощью оператора другого сценария. Подробнее об этом речь пойдет в главе 6. Просмотр ошибок сценария На ранних этапах использования JavaScript в браузерах ошибки, обнаруживаемые при загрузке в сценарии, отображались в наглядных диалоговых окнах. Эти окна весьма полезны для тех разработчиков страниц, которые занимаются отладкой сценариев. Но если ошибка появлялась на странице пользователя, который мало знаком с основами создания сценариев, то такого рода диалоговое окно с сообщением об ошибке не только не приносило никакой пользы, но и просто наводило ужас. В результате производители браузеров попытались максимально уменьшить отображаемый в окне браузера эффект извещения о наличии ошибок — к несчастью, для создателей сценариев, поскольку в результате найти ошибки в сценарии стало труднее. Часто ошибки бывают не так очевидны, как кажется сначала. В последних версиях Ш и NN предусмотрено несколько способов отслеживания ошибок в сценариях. Браузер Ш5+ можно настроить так, что сценарий не будет отображать диалоговые окна ошибок. Для этого выберите Tools ^Internet Options^ Advanced^Browsing (Сервис=>Свойства обозревателя^Дополнительно^Обзор) и найдите опцию Display a notification about every script error (Отображать подробные сообщение об ошибках). Даже с отключенным режимом отображения сообщений об ошибках в левой части строки состояния окна браузера обнаруженные ошибки все равно регистрируются. В строке состояния появляется значок предупреждения и соответствующее сообщение. Если дважды щелкнуть на этом значке, то появится диалоговое окно извещения об ошибке (рис. 5.1). Детальную информацию о возникшей проблеме можно получить, если щелкнуть на кнопке Show Details (Подробнее) этого диалогового окна. Если режим отображения диалоговых окон не включен, то каждый раз при загрузке страницы и запуске сценария необходимо внимательно следить за строкой состояния и отслеживать появление ошибок. При работе в браузерах Mozilla выберите команду Tools^Web Development^JavaScript Console (СервисеWeb-paspaeoTKa1^ Консоль JavaScript). В результате для отображения детальной информации об ошибках будет открыто окно консоли отладчика JavaScript (отличное от консоли Java), как показано на рис. 5.2. При необходимости это окно можно сделать постоянно открытым. Если окно периодически не очищать, то в нем будут постоянно появляться сообщения о новых ошибках. Браузер Safari 1.0 регистрирует ошибки в сценариях, но по умолчанию не отображает их на экране. Для начала вам необходимо получить доступ к меню отладки (Debug), введя следующую команду в утилите Terminal. defaults write com.apple.Safari IncludeDebugMenu 1 90 Часть II. Руководство по JavaScript
А Problem» ««№ tffe Wfbpifp яфй (omni It iim being iftfletwlpnpwV erlundonhg prapof/, in the (uM«* j«j ош 4фку4м manege by dodb»4jc^^vw^i«ndiplyadinlh8it<tutb». S Д№» <fap**y Wt ouweeg» ««hen a page ccrtarmetltn. 1 OK "j |HtdeBcfi»«l line 214' Owl. Eiror Ywtf^tmlefinad CodKO URL Hk/zZ: VWWvakj*»«.f)W Pwc. 5.7. Развернутое окно сообщения об ошибке в Internet Explorer Рис. 5.2 Окно консоли JavaScript в браузерах МогШа Впоследствии при запуске Safari вам необходимо выбрать в меню Debug команду Log JavaScript Exceptions (Регистрировать ошибки JavaScript). Далее отобразите окно программы MacOS X Console, в котором и будут вьшодиться сообщения об ошибках выполнения JavaScript-кода. Будем надеяться, что в будущих версиях браузера Safari эта процедура станет менее обременительной. Изучение сообщений об ошибках и их устранение — довольно серьезная тема (см. главу 45). В этом издании речь также идет о том, как использовать сообщения об ошибках в качестве индикатора неправильности вводимых сценариев. Различие между написанием сценариев и программированием Может сложиться впечатление, что создавать сценарии намного проще, чем писать программы. Слово сценарий звучит проще и дружелюбнее, чем программа или даже приложение. И во многих отношениях это так и есть. В качестве аналогии приведем пример с коллекционером, Глава 5. Сценарии и документы HTML 91
который собирает модели самолетов из подручных материалов, и его коллегу, который для этого же использует специальные промышленные заготовки. Тот, который собирает модели из подручных материалов, аккуратно вырезает и подгоняет каждый кусочек дерева или металла, чтобы воплотить задуманную идею и придать модели нужную форму. Коллекционер, использующий промышленные заготовки, комбинирует их для того, чтобы получить конечный продукт. Когда оба заканчивают свою работу, не всегда можно с уверенностью сказать, какая модель собрана из подручных материалов, а какая — из деталей фабричного производства. В конце концов, оба моделиста используют подобную технику сборки и у каждого есть повод гордиться своей работой. Браузер предоставляет создателям сценариев много заранее заготовленных компонентов, на основе которых можно успешно создавать сценарии. Если вы не используете браузер, то это говорит о том, что высококлассный программист, который может разработать на основе подручных средств собственное приложение, позволяющее обслуживать данные и предлагающее широкие возможности по взаимодействию с пользователем. Но и в том, и в другом случае приложения должны иметь весьма профессиональный вид. За пределами рамрк объектной модели документа, тем не менее, "настоящее программирование" сжигает все мосты на пути к миру сценариев. Это происходит потому, что сценарии (и программы) работают не только с объектами. Когда выше в этой главе утверждалось, что каждый оператор сценария JavaScript должен нести функциональную нагрузку, то под этим подразумевалось управление определенного рода данными. Данными называется любая информация, связанная с объектами или другими частями информации, которую сценарий использует при выполнении очередного оператора. Данные могут принимать самые разные формы. В JavaScript общими типами данных являются числа, текст (строчный тип string), объекты (как принадлежащие объектной модели, так и создаваемые с помощью сценариев), а также логические или булевы (Boolean): true (правда) и false (ложь). Каждый язык программирования или создания сценариев определяет целый ряд структур и, разумеется, накладывает ограничения для каждого типа данных. К счастью для начинающих JavaScript-программистов, тот объем знаний, которыми необходимо обладать для успешного создания сценариев, намного меньше по сравнению с таковым для программирования в фундаментальных средах (например таких, как Java). В то же время, все, чему вы научитесь в JavaScript, сразу же найдет себе применение и при изучении других языков программирования — нельзя допускать даже мысли о том, что изучение методов создания сценариев пройдет впустую. Поскольку на профессиональном уровне процесс составления сценария сродни программированию, то чтобы стать хорошим разработчиком сценариев в JavaScript, необходимо иметь основные представления о принципиальных подходах, используемых в программировании. В следующих главах уклон будет сделан от объектной модели документа к принципам программирования, которые важны как в JavaScript, так и в других языках. Упражнения 1. Создайте полный сценарий, в котором использовался бы такой оператор: document.write("Hello, world."); 2. Создайте HTML-документ, включив в него сценарий из предыдущего задания. Сценарий должен запускаться при загрузке страницы. Результат выполнения сценария нужно проверить, открыв документ в браузере. 3. В описанный выше сценарий необходимо добавить комментарий, поясняющий принцип выполнения операторов этого сценария. 92 Часть II. Руководство по JavaScript
4. Создайте HTML-документ, который сразу после загрузки страницы будет отображать диалоговое окно с предупреждением. Другое диалоговое окно должно отображаться при щелчке пользователя на кнопке формы. 5. Внимательно изучите документ в листинге 5.9. Не выполняя ввод и загрузку документа, ответьте на такие вопросы. а) Как будет выглядеть страница. б) Как пользователь будет взаимодействовать со страницей. в) Как работает сценарий. Затем введите текст сценария в текстовом редакторе, как показано ниже (обратите внимание на регистр символов и пунктуацию). Не вводите символ возврата каретки после знака равенства "=" в описании функции upperME. Не следует также добавлять разрывы строки — все должно быть представлено, как показано в листинге. Символ возврата каретки можно использовать между парами имя=значение, как показано в первом дескрипторе < input >. Теперь сохраните документ как HTML- файл, после чего загрузите этот файл в браузер. <html> <head> <title>Text Object Value</title> <script type="text/javascript"> function upperMeO { document.getElementByld("output").value = document.getElementByld("input").value.toUpperCase(); } // --> </script> </head> <body> Enter lowercase letters for conversion to uppercase:<br> <form name="converter"> <input type="text" name="input" id="input" value="sample" onchange="upperMe0" /xbr /> <input type="text" name="output" id="output" value="" /> </form> </body> </html> Глава 5. Сценарии и документы HTML 93
Основы программирования. Часть 1 а данном этапе изучения JavaScript вопросы, непосредственно связанные с HTML-документами, следует оставить на потом — основное внимание мы уделим анализу принципов программирования. Это важный момент с практической точки зрения, а полученные навыки могут в дальнейшем быть использованы в любом языке при составлении сценариев или написании программ. Для начала мы познакомимся с переменными, выражениями, типами данных и операторами — названия эти могут звучать несколько непривычно для тех, кому не приходилось еще писать программы. Однако беспокоить это не должно. Наличие даже небольшого опыта работы быстро сделает перечисленные выше термины простыми и понятными. Язык программирования Используемым нами языком программирования будет JavaScript. У языка JavaScript есть еще несколько названий, с которыми, возможно, читателю уже приходилось сталкиваться. Версия компании Microsoft этого языка называется JScript. В последней из названия языка было убрано "ava", чтобы не получать лицензию на использование названия "Java" у владельца торговой марки — компании Sun Microsystems. В настоящее время основной ориентир для любого языка программирования (независимо от его называния) — это стандарт ЕСМА. Документ, в котором прописаны все детальные требования к языку, называется ЕСМА-262 (это 262-ой стандарт, разработанный ЕСМА). Как JavaScript, так и JScript поддерживают стандарт ЕСМА-262. Некоторые браузеры очень ранних версий демонстрируют весьма незначительное отклонение от стандарта ЕСМА-262 (который появился позже, чем эти браузеры). Наиболее существенные несоответствия описаны в справочных разделах по базовому языку в части ГУ этой книги. н
Способы управления информацией За очень редким исключением, каждый используемый оператор JavaScript выполняет определенные действия с различными наборами информации или данных. Данные могут быть представлены текстовой информацией, отображаемой на экране с помощью соответствующих операторов JavaScript, или в виде флажка на форме (включен или выключен). Каждая отдельная часть информации в программировании называется значением. В обычном понимании термин значение ассоциируется с числом, характеризующим количество чего-либо. В программировании, тем не менее, этот термин не настолько упрощен. Например, текстовая строка является значением. Отдельное число является значением. Опция элемента управления (которая либо активна, либо нет) также является значением. В JavaScript значения могут быть нескольких типов. В табл. 6.1 приведены формальные типы данных JavaScript и в качестве примеров те их значения, которые будут время от времени описываться в этой книге. Тип данных Пример Описание Строковый " Howdy" Последовательность символов, заключенных в кавычки Числовой 4.5 Любое число без кавычек Булев (логический) true Логическое да (true) или нет (false) Null null Отсутствие значения Объект Программный объект, определяемый своими свойствами и методами (массивы также являются объектами) Функция Определение функции Использование языка, в котором задействовано такое незначительное количество типов данных, упрощает решение многих задач программирования. Особенно если сравнивать его с другими языками программирования, где столь часто разработчики сталкиваются с проблемами, связанными с несогласованностью типов данных (целочисленных, действительных чисел или чисел с плавающей запятой). В некоторых примерах книги иногда используются формальные ссылки или условные имена объектов и переменных. В настоящих сценариях и программах их можно заменить собственными именами. Все строки заключаются в кавычки. Встречаются ситуации, когда тип значения напрямую связан с используемым сценарием. Например, если пользователь вводит в текстовом поле формы число, то браузер запомнит это число как значение строкового типа string. Если в сценарии предусмотрено выполнение некоторых арифметических действий с этим числом, то перед использованием данного числа в математических преобразованиях его необходимо сначала привести к числовому типу number. Примеры подобного преобразования типов представлены ниже. Переменные Приготовление по определенному рецепту блюд на кухне имеет, по сравнению с подготовкой данных для использования в программе, одно преимущество. На кухне вы имеете дело с вполне реальными вещами: морковкой, молоком или филе из лосося; при этом повар должен только следовать готовому рецепту. Компьютер, если проводить аналогию, тоже следует инструкциям Глава 6. Основы программирования. Часть 1 95
при управлении данными. Иногда такие данные представляют что-то вполне реальное (например, текст, введенный в текстовое поле формы). Однако как только нужное значение будет получено программой, изменить заранее определенный набор действий — не так и просто. На самом деле данные, с которыми работает программа, являются простым набором битов (единиц и нулей, если хотите) в памяти компьютера. Если выражаться более точно, то данные в модернизированных с помощью JavaScript Web-страницах занимают часть памяти компьютера, специально выделяемой для использования браузером. В былые времена программистам нужно было знать конкретные адреса в оперативной памяти, по которым хранились значения и откуда (в случае необходимости) их можно было востребовать. Поскольку на внутреннем уровне организации программы степень сложности осталась прежней, использование современных программных языков (например JavaScript) призвано избавить программистов от такой рутиной работы. Наиболее удобным способом использования данных в сценарии является такой, при котором данные присваиваются в качестве значения переменной. Переменную можно представить себе в виде контейнера, в котором хранится информация. Как долго эта переменная будет хранить информацию, зависит от нескольких факторов. Когда Web-страница удаляется с экрана (или окна), все используемые ею переменные немедленно удаляются из памяти. Создание переменной В JavaScript создать переменную можно несколькими способами. Но только один из них применим практически во всех случаях. Этот способ подразумевает использование ключевого слова var, после которого указывается имя, которое будет присвоено переменной. Например, чтобы таким образом определить переменную с именем myAge, нужно воспользоваться следующим оператором JavaScript. var myAge; Этот оператор указывает браузеру, на то что данную переменную можно использовать для последующего хранения информации. Любые данные, присвоенные этой переменной, могут в дальнейшем изменяться. Чтобы присвоить переменной значение, используются операторы присвоения. Наиболее распространенным среди них является знак равенства. Если описанной выше переменной myAge нужно присвоить значение сразу при описании (такой комбинированный процесс описания и присвоения значения еще называется инициализацией переменной), то в описании переменной используется еще и оператор присваивания. var myAge = 45; С другой стороны, если переменная описана в одном месте, а позже ей нужно присвоить другое значение, то сделать это можно следующим образом. var myAge; myAge = 45; Ключевое слово var для данной переменной в документе используется один-единственный раз: при описании или инициализации. Переменные в JavaScript могут принимать значения любого типа. В отличие от многих других языков, в JavaScript нет необходимости при описании переменной указывать тип ее значений. Тип переменной может меняться в процессе выполнения программы. Эта либеральность просто сводит с ума некоторых классических программистов, которые привыкли и для данных, и для переменных указывать тип. 96 Часть II. Руководство по JavaScript
Названия переменных Название для описываемых переменных следует выбирать весьма осторожно. Всегда можно найти сценарии, в которых используются переменные с именами, состоящими из отдельных букв. За исключением нескольких специфических случаев, где использование в качестве имени переменной только одной буквы бывает оправдано (например, переменной i для счетчика в операторе цикла в главе 7), я бы порекомендовал выбирать такие имена переменных, которые реально отображали бы их назначение. Подобная практика позволяет отслеживать состояние данных в большом наборе операторов и переходов, особенно в сложных сценариях. Ряд ограничений, налагаемых на имена переменных, также способствует выработке у начинающих программистов корректного стиля именования переменных. Во-первых, в качестве имен переменных нельзя использовать зарезервированные в JavaScript слова. Это относится как к тем ключевым словам, которые уже используются в языке, так и к тем, которые зарезервированы для использования в будущих версиях JavaScript. Дизайнеры JavaScript, тем не менее, не смогли бы предусмотреть абсолютно все ключевые слова, которые будут использоваться в будущем, даже если бы очень захотели. Однако, используя в качестве имен своих переменных термины, которые приведены в списке зарезервированных служебных слов (см. приложение Б), вы гарантировано обеспечите себе неприятности в будущем. В именах переменных нельзя использовать пробелы. С этой точки зрения оптимальными именами являются те, которые состоят из одного слова. Если у вас возникла необходимость в имени переменной использовать более одного слова, то для преобразования нескольких слов имен в одно можно воспользоваться рядом хитростей. Один из способов подразумевает использование между словами в качестве разделителя символа подчеркивания. Другой метод заключается в том, чтобы начинать комбинацию слов в имени с маленькой буквы, а потом каждое новое слово начинать с большой буквы. При этом между словами разделители вообще не ставятся. Это так называемый слитный формат (interCap format). Внизу приведены имена переменных, образованные согласно описанным выше правилам. my_age myAge Второй вариант является более предпочтительным. Такие имена гораздо легче вводить при написании кода JavaScript, а потому легче и воспринимать. С точки зрения возможности возникновения конфликта со служебными словами будущих версий JavaScript, использование в качестве имен переменных нескольких слов является неплохой идеей. Ведь вероятность появления таких "многословных" комбинаций в списке зарезервированных терминов достаточно невелика. Кроме того, на имена переменных накладывается и ряд других существенных ограничений. В них, кроме прочего, следует избегать всех знаков пунктуации, кроме символа подчеркивания. Первый символ в имени переменной не может быть числом. Если эти ограничения показались вам знакомыми, то это потому, что они идентичны правилам задания идентификаторов элементов HTML, о которых рассказывалось в главе 4. Выражения и их вычисление К другой концепции, имеющей непосредственное отношение к переменным и их значениям, относится концепция вычисления выражений. Возможно, это один из самых важных моментов в понимании методов программирования. Выражения используются повсеместно в нашем ежедневном общении. В фильма The Beverly Hillbillies есть такая интересная песенка. Глава 6. Основы программирования. Часть 1 97
Then one day he was shootin' some food And through the ground came a-bubblin' crude Oil that is. Black gold. Texas tea. (Голодный, хлеба он искал, А отыскал источник счастья. То нефть была — Техасский чай, На цвет черна и золота прекрасней.) В конце этой песни можно найти различные ссылки: "источник счастья" (crude), "нефть" (oil), "черное золото" (black gold), "Техасский чай" (Texas tea). Везде подразумевается нефть. Эти все выражения используются для обозначения понятия нефть. Стоит упомянуть одно из них, и все окружающие поймут, о чем идет речь. В нашем воображении мы вычисляем эти выражения и сводим их к одному значению — нефть. В программировании переменные всегда ценны их содержимым или значением. Например, после присвоения значения переменной, определяющей возраст автора книги, var myAge = 45; каждый раз, когда эта переменная будет использоваться в выражении, ее значение (45) автоматически будет применяться в любом операторе. Если известно, что, например, читатель на 15 лет моложе, то можно ввести новую переменную, значение которой будет рассчитываться исходя из указанной выше информации и уже известной переменной. var yourAge = myAge - 15; При следующем использовании в сценарии переменной yourAge ее значение будет рассчитано и окажется равным 30. Если позже в сценарии значение переменной myAge будет изменено, то на переменную yourAge эти изменения никак не повлияют, поскольку при описании переменной yourAge и расчете ее значения значение переменной myAge было равно 45. Выражения в сценарии scriptl .htm Возможно, на это в свое время никто не обратил внимания, но уже в главе 3 в первом приведенном сценарии можно было отследить вычисление выражения. Речь идет о втором операторе сценария document. write (). document.write(" of " + navigator.appName + "."); При использовании метода document. write () (под этим термином в JavaScript подразумевается команда) следует указать в скобках все необходимые параметры. В данном случае это текстовая строка, которая будет отображаться на Web-странице. В использованном примере параметр является одним выражением, состоящим из трех отдельных строк. и of и navigator.appName И II Использование знака "плюс" (+) в JavaScript является одним из способов объединения строк. Перед тем как JavaScript сможет отобразить данную строку, нужно выполнить несложные расчеты. Первым этапом является вычисление значения свойства navigator. appName. Это значение равно строке, содержащей название используемого браузера. Когда соответствующее значение будет успешно преобразовано к строковому типу, JavaScript сможет завершить процесс объединения трех строк в одно целое. Такая результирующая строка и будет отображена на Web-странице. 98 Часть II. Руководство по JavaScript
Проверка вычислений Поэкспериментировать с тем, как в JavaScript выполняются вычисления выражений, можно с помощью специального программного средства, которое называется The Evaluator Jr. (Jr. — "младший", см. следующий рисунок). Более совершенная (Senior, "старшая") версия этого средства будет описана в главе 13. В верхнем текстовом поле нужно ввести любое выражение JavaScript, после чего нажмите <Enter> или щелкните на кнопке Evaluate (Вычислить). The Evaluator Jr. Enter an expression to evaluate: 1 Results: 15 Enter a reference to an object: List Properties go ■-fl'TJtfHtiam Приложение The Evaluator Jr. предназначено для тестироеания выражений В The Evaluator Jr. используется 26 предопределенных переменных (от прописной литеры а до z), поэтому с его помощью можно присваивать переменным значения, тестировать операторы сравнения и даже выполнять нехитрые математические операции. Используя приводившийся выше в этой главе пример с переменной, "запоминающей" возраст, можно повторить все выполненные выше расчеты и проверить, что будет отображаться в поле Result (Результат). При этом не забывайте проверять регистр символов. 45; а а; Ь = а а - Ь; а > Ь; 15; Для повтора щелкните на кнопке Reload (Перезагрузить). Выражения и переменные Использование вычисляемых выражений позволяет реализовать более гибкий, по сравнению с примененным ранее, способ вызова метода document. write (). Вместо того, чтобы в качестве параметра метода document .write () указывать объединяемые строки в явном виде, можно сохранить эти строки в отдельную переменную, а потом уже задать эту пере- Глава & Основы программирования. Часть 1
менную в качестве параметра метода. Вот как будет выглядеть наш метод в том случае, если предварительно объявить переменную и задать ей значение. var textToWrite'"« " of " + navigator. appName + " . " docunment .write (textToWrite) Этот метод будет выполняться, поскольку значение переменной textToWrite преобразуется к необходимому типу данных. Метод docunment .write О примет значение этой переменной строкового типа и выполнит свою часть работы по отображению данных на экране. Это довольно показательный пример. Он еще раз доказывает, что при ознакомлении со сценариями или их отладке следует всегда обращать внимание на то, как именно производится в сценарии вычисление каждого выражения (переменной, значения, свойства объекта). В противном случае при изучении JavaScript (или любого другого языка) немало времени у вас уйдет на попытку разобраться, откуда в сценарии появилось то или иное значение переменной. Преобразование типов данных Как уже отмечалось ранее, тип данных существенно влияет на выполнение операторов сценария, особенно если один из операндов принадлежит не к тому типу, который можно ожидать в данном конкретном случае. Хотя в JavaScript предпринята серьезная попытка разрешить подобного рода проблемы путем преобразования типов данных, следует понимать, что мысли пользователей JavaScript все же угадать не сможет. Если пользователь склонен трактовать переменную несколько иначе, чем это делает JavaScript, то вряд ли он может рассчитывать на получение приемлемого результата. Представим, например, сложение чисел, которые могут быть записаны в текстовом строковом формате. В самом обычном случае арифметическая операция сложения двух чисел проблем не вызывает, в ее результате можно получить вполне ожидаемый результат. 3+3 // результат = 6 Но если одним из чисел является строка, то JavaScript попытается преобразовать и второй операнд в строковый тип. В этом случае арифметическая операция по сложению чисел превращается в процесс слияния двух строк. Поэтому в выражении 3 + "3" // результат = "33й "(прочность" второго операнда "задает тон" всей операции. Первое значение автоматически преобразуется в строковый тип, а результатом операции является объединение двух строк. В этом можно убедиться самостоятельно, воспользовавшись услугами приложения The Evaluator Jr. Если такой процесс несколько расширить и рассмотреть сумму из трех слагаемых 3 + 3 + "3й // результат = "63й то вначале полученное конечное значение может показаться нелогичным. Однако логика все же есть. Выражения вычисляются слева направо. Поэтому первый знак "плюс" связан с первыми двумя числами, и результатом выполнения такой операции является число 6. Поскольку к числу б прибавляется строчное выражение "3", то конечным результатом, по причине использования в JavaScript правила "строчность", будет "63". Большинство из того, что с точки зрения типов данных будет важно в дальнейшей работе, имеет непосредственное отношение к математическим операциям, описанным выше. Тем не менее, некоторые методы требуют, чтобы в качестве параметров в них указывались данные одного или двух конкретных типов. JavaScript предоставляет довольно широкие возможности по преобразованию типов, однако на данном этапе имеет смысл более детально ознакомиться с двумя способами такого преобразования — чисел в строки и строк в числа. 100 Часть II. Руководство по JavaScript
Преобразование строк в числа Сразу необходимо отметить следующее: если числовое значение сохранено в качестве строки (например, при введении значения в текстовое поле), у сценария могут появиться проблемы при попытке использовать это значение в математических операциях. В JavaScript предусмотрены две встроенные функции; которые можно применить для преобразования чисел, представленных в виде строки, к числовому формату: это функции parselnt () и parseFloat (). В JavaScript существует разница между целыми числами и числами с плавающей точкой. Целые числа (integer) всегда являются целыми. У них нет десятичной точки и справа от целой части у них ничего не задается. Числа с плавающей точкой (floating-point), в противоположность целым, могут содержать дробную часть справа от десятичной точки. С точки зрения вычисления арифметических операций, в JavaScript разницы между целыми числами и числами с плавающей точкой нет. Различать целые и нецелые числа необходимо лишь при передаче их в качестве параметров в некоторых методах, которые не могут обрабатывать дробную часть. Например, параметры метода scroll () должны быть числами целыми, поскольку они определяют число пикселей по вертикали и горизонтали, на которые нужно прокрутить окно. А на часть пикселя окно прокрутить не удастся даже самому ловкому пользователю. Чтобы использовать любую из указанных функций преобразования типов, ей в качестве параметра следует передать ту строку, которую нужно преобразовать к числовому формату. Например, внизу приведен код, использующий функцию parselnt (), преобразования двух различных строк в числовые значения. parselnt("42") // результат = 42 parselnt("42.33") // результат = 42 Несмотря на то, что во второй строке передается строчный вариант числа с плавающей точкой, возвращаемое функцией значение соответствует целочисленному типу. В данном случае округление не использовалось (хотя другие математические функции могли бы помочь и в этом). Десятичная точка и все, что стоит за ней, просто отбрасывается. В качестве результата функция parseFloat (), если это возможно, возвращает целое число. В противном случае в качестве результата возвращается число с плавающей точкой, как это и показано ниже. parseFloat("42") // результат = 42 parseFloat("42.33") // результат = 42.33 Поскольку эти две функции преобразуются к возвращаемому результату, то в тех местах, где нужно выполнить преобразование строковой переменной в числовое значение, следует просто вставить одну из этих функций. В отношении используемого ранее примера суммирования трех значений, одним из которых была строка, данную рекомендацию можно реализовать следующим образом. 3 + 3 + parselnt("3") // результат = 9 Преобразование чисел в строки Как правило, преобразовывать числа в строки приходится намного реже, чем строки в числа. Как можно было убедиться на приведенных выше примерах, JavaScript больше привязан к строковым типам данных, а не к числовому формату, чем можно эффективно пользоваться при смешанном применении типов данных в операторах. В любом случае, это является еще одним хорошим способом уберечь собственный код от различных недоразумений и несоответствия типов. Наиболее простой способ преобразования чисел в строки был описан Глава 6. Основы программирования. Часть 1 101
в приведенных выше примерах; он основан на исключительной "любви" JavaScript к строкам. Путем добавления пустой строки к числу из последнего можно получить строковый эквивалент. ("" + 2500) // результат = "2500" ("" + 2500).length // результат « 4 В последнем примере особенности вычисления выражений проиллюстрированы довольно наглядно. Наличие кавычек приводит к тому, что числовое выражение преобразуется к строковому типу. Строка string в JavaScript является объектом, который имеет связанные с ним свойства. Одно из этих свойств— length, значение которого равно количеству символов в строке. Количество символов в строке "2500" равно 4. Обратите внимание на то, что длина length — это число, а не строка. Операторы В выражениях используется огромное число операторов. Ранее операторы нами уже использовались. Например, знак равенства (=) применялся в качестве оператора присвоения значения переменной. В предыдущем примере со строками символ "плюс" (+) использовался для объединения двух строк. Оператор выполняет, как правило, определенного рода вычисления (операции) или сравнивает два значения (значение с каждой стороны оператора называется операндом) с целью получения третьего. В данной главе будут описаны два типа операторов — арифметические и операторы сравнения. В главе 32 будет представлено значительно большее количество операторов. В данный момент вам необходимо понять, как функционируют базовые элементы. Тогда и работа остальных станет намного доступнее. Арифметические операторы Может показаться странным описание текстовых строк в контексте "арифметических" вычислений. Но выше уже приводился пример использования оператора (+) в тех случаях, когда одним из операндов была строка. Оператор в виде знака "плюс" дает указание JavaScript объединить две строки именно в том месте, где размещен оператор. Оператор объединения строк ничего не знает о словах и пробелах, поэтому программисту нужно заранее позаботиться о том, чтобы любые две объединяемые строки имели достаточное количество Пробелов — даже если для этого придется добавлять пробелы специально. firstName = "John" lastName = "Doe" fullName = firstName + " " lastName В JavaScript для обозначения арифметической операции сложения тоже используется знак "плюс". Если двумя операндами являются числа, JavaScript будет трактовать операцию как арифметическое сложение двух чисел, а не как объединение строк. В JavaScript встроены арифметические операторы сложения (+), вычитания (-),^умножения (*) и деления (/). Операторы сравнения Довольно важным типом являются операторы, с помощью которых выполняется сравнение двух или более значений на предмет совпадения. Такое сравнение в качестве результата продуцирует значение логического типа Boolean— true (истина) или false (ложь). В табл. ^.2 представлен список операторов сравнения. Оператор, с помощью которого можно определять эквивалентность двух элементов, состоит из пары знаков равенства (чтобы отличать его от знака равенства, используемого в операторе присвоения). 102 Часть II. Руководство по JavaScript
Символ Описание Равно i = Не равно > Больше >= Больше или рано < Меньше <= Меньше или равно Наиболее часто операторы сравнения применяются в тех конструкциях сценария, где принимаются решения. Для сравнения: повар на кухне такие процедуры выполняет очень часто (если соус слишком жидкий, нужно добавить муки). С операторами сравнения вы детальнее ознакомитесь в следующей главе. Упражнения 1. Укажите, какой из приведенных ниже способов описания и инициализации переменных является приемлемым? Объясните, почему так, а не иначе. Если способ неправильный, что нужно сделать, чтобы исправить ситуацию? а) my_name = "Cindy"; б) var how many = 25; в) var zipCode = document.forml.zip.value; r) var laddress = document.nameForm.address1.value; 2. Для каждого из приведенных ниже выражений укажите, как изменится выражение someVal после выполнения следующих операторов JavaScript. var someVal = 2; someVal = someVal + 2; someVal = someVal * 10; someVal = someVal + "20"; someVal = "Robert"; 3. Назовите две функции JavaScript, которые выполняют преобразование строк в числа. Как можно задать функцию преобразования строчного значения в число? 4. Наберите код согласно листингу 6.1 и загрузите HTML-страницу. Введите трехзначное число в два верхних поля и щелкните на кнопке Add (Сложить). Изучите код и скажите, в чем ошибка сценария. Как его исправить, чтобы он правильно считал сумму двух чисел, вводимых в указанные поля? <html> <head> <title>Sum Maker</title> <script type="text/javascript"> Глава ft Основы программирования. Часть 1 103
function addlt() { var valuel = document.getElementByld("inputA").value; var value2 - document.getElementByld("inputB").value; document.getElementByld("output").value = valuel + value2; } // --> </script> </head> <body> <form name*"adder"> <input type="text" name="inputA" id="inputA" value="0" size="4" /> <br /> <input type="text" name="inputB" id="inputB" value="0" size="4" /> <input type="button" value="Add" onclick="addIt()"> <p> </p> <input type="text" name="output" id="output" size="6" /> </form> </body> </html> 5. Что значит термин объединение в программировании на JavaScript? 104 Часть II. Руководство по JavaScript
Основы программирования. Часть 2 этой главе знакомство с основами программирования откроет перед вами новые горизонты. Например, будут рассмотрены вопросы принятия решений программами; вы узнаете, почему некоторые операторы сценария нужно повторять снова и снова. В конце главы можно будет также узнать об одном из самых эффективных способов хранения информации в JavaScript — о построении массивов. Решения и циклы Ежедневно и ежечасно каждому из нас приходится принимать важные решения — и очень часто об этом мы даже не подозреваем. Наверное, с этим согласны не все. Тогда имеет смысл рассмотреть, какие решения принимаются покупателем, скажем, в супермаркете от момента, когда он туда заходит, и до момента выхода. Без предварительного принятия решения никто в супермаркет не заходит. В зависимости от количества и размера предполагаемых покупок, посетитель берет либо ручную сумку, либо тележку самообслуживания в углу возле стойки. Это решение позже может быть подвергнуто суровой самокритике, если по пути своего следования покупатель обнаружит скидки на товары, которых по такой цене можно было бы купить больше, да вот сумочка для ручной клади маловата. Теперь предположим, что покупатель подходит к продуктовому отделу. Прежде чем что-то выбрать, он проверяет наличие тех товаров, которые специально дома выписал на листочек, чтобы ничего не забыть. Если ассортимент покупателя устраивает, то он подойдет ближе и начнет искать нужный продукт. В противном случае покупатель пойдет к другому отделу. Дальше предположим, что покупатель направляется к овощному отделу, чтобы купить спелых помидоров. Подойдя к лотку
с помидорами, он начинает выбирать — берет его, проверяет твердость, цвет, ищет изъяны. Если покупатель забраковал один овощ, он берет другой и повторяет описанные действия: до тех пор пока, наконец, не найдет то, что ищет. Последней остановкой покупателя является касса. "Пакет бумажный или пластиковый?" — спрашивает продавец. Это еще одно решение, которое нужно принять. От него будет зависеть, в какой сохранности покупки будут доставлены из супермаркета прямо на кухню. Процесс принятия решений при посещении магазина напоминает то, через что проходит JavaScript при выполнении программы. Если основную идею описанного процесса вы уже поняли, то теперь самое время обратиться к особенностям синтаксиса JavaScript и способам реализации с его помощью программ. Управляющие структуры На программном языке все операторы, используемые для принятия решений, а также связанные с ними циклические команды повторения называются структурами управления (или управляющими структурами). Структуры управления с помощью последовательности операторов сценария направляют поток обработки данных в нужном направлении. В основе используемых методов лежит схема принятия простых решений и других факторов. Важной частью каждой управляющей структуры является условный оператор. Точно так же, как к месту работы можно добираться несколькими путями, в зависимости от тех или иных условий (например погоды, времени суток или настроения), программа тоже иногда содержит условные выражения, которые могут принимать значения true (истина) или false (ложь) — одно из логических значений булевого типа, уже упоминавшихся в главе 6. Как правило, в качестве подобных условных конструкций используются те, которые содержат оператор сравнения. В реальной жизни все происходит абсолютно аналогично: если истина заключается в том, что за окном мороз, то перед выходом на улицу лучше надеть пальто. В программировании сравнивают, как правило, числа или строки. Для разных программируемых ситуаций в JavaScript предусмотрены различные типы управляющих структур. Три наиболее часто используемые структуры — это условный оператор if, условный оператор if. . . else и оператор цикла for. Другие управляющие структуры детально описываются в главе 31. На данном же этапе мы остановимся только на трех упомянутых выше конструкциях. Условный оператор if Наиболее простой пример принятия решения в программе— это ситуация, в которой в зависимости от справедливости определенного условия в программе выбирается тот или иной алгоритм действий. Формальный синтаксис соответствующей структуры приведен ниже. Текст, отображенный курсивом, в реальном сценарии следует заменить на выражения и операторы, соответствующие конкретной задаче. if (условие) { оператор [ы] , выполняемый[е] , если условие справедливо } Не стоит беспокоиться по поводу наличия фигурных скобок —сконцентрируйтесь на основной структуре. Ключевое слово if является обязательным. В круглых скобках вводится выражение, значение которого имеет булев тип. Это именно то условие, которое проверяется, когда процесс выполнения программы подходит к данному месту. Если значение выражения равно true (истина), то будет выполнен оператор или операторы, заключенные в фигурные скобки, а после этого программа перейдет к оператору, который находится после закрывающей 106 Часть II. Руководство по JavaScript
фигурной скобки. Если значение выражения равно false (ложь), то операторы внутри фигурных скобок игнорируются и процесс продолжается с первого оператора после закрывающей фигурной скобки. В приведенном далее примере подразумевается, что переменная myAge имеет значение, заданное ей ранее в сценарии (как именно, в данном случае не важно). В условном выражении осуществляется проверка сравнения значения переменной myAge с числом 18. if (myAge < 18) { alert("Sorry, you cannot vote."); } Тип данных значения myAge должен соответствовать числу, чтобы процесс сравнения (с помощью оператора сравнения <) производился корректно. Во всех случаях, когда значение myAge меньше 18, оператор в фигурных скобках будет выполнен, в результате на экране появится окно предупреждения. После того как пользователь закроет это диалоговое окно с предупреждением, выполнение сценария будет продолжено с того оператора, который расположен непосредственно после фигурной скобки, закрывающей условный оператор. Условный оператор if...else Не все решения в программах принимаются так просто, как это показано выше на примере условного оператора if. Вместо того, чтобы определять направление программы только в случае выполнения или невыполнения условия, явно укажите оба пути для случая выполнения и невыполнения условия. Это не очень заметное но очень важное различие. В стандартном условном операторе if в случае, если значение контрольного выражения равно false (ложь), специальный оператор не выполняется. Если же и при негативном ответе после проверки условного выражения (значение false) нужно выполнить набор определенных действий, применяется конструкция if. . . else. Ее синтаксис приведен ниже. if (условие) { оператор [ы] выполняемый[е] , если условие = true } else { оператор [ы] выполняемый[е], если условие = false } Здесь представлено все, что уже известно о конструкции if. Главным отличием от рассмотренного выше случая является только наличие ключевого слова else. Оно введено для того, чтобы указать альтернативный путь выполнения программы в том случае, если значение проверяемого условия равно false. Как пример использования структуры if. . .else приведен фрагмент кода, в котором определяется количество дней в феврале месяце в зависимости от того, високосный год или нет. Для упрощения примера в условии просто проверяется, делится ли номер года нацело на 4. (Настоящая проверка должна учитывать переход в новое столетие, но в данном случае это несущественно). Оператор в виде знака процента (%) обозначает делением по модулю, и о нем речь пойдет в главе 32. Результат выполнения этого оператора — это остаток от деления одного числа на другое. Если остаток равен нулю, то первое число делится на второе нацело. var febDays; var theYear = 2004; if (theYear % 4 == 0) { febDays = 29; } else { febDays = 28; } Самое важное в этом примере происходит в конце кода, в конструкции if. . .else. Значение переменной febDays устанавливается равным 28 или 29. Ни одно из других значений Глава 7. Основы программирования. Часть 2 107
не является возможным. Для тех лет, числа которых нацело делятся на 4, выполняется первый встроенный оператор условной конструкции. Во всех других случаях выполняется второй оператор. Процесс выполнения кода в любом случае продолжается с первого после окончания структуры if. . .else оператора. Циклы В реальной жизни циклы означают повторение последовательности определенных шагов или действий до тех пор, пока не выполнится определенное условие. Именно это условие позволяет разорвать заколдованный круг повторений. Так было в примере с посещением магазина, когда посетитель перебирал помидоры до тех пор, пока не находил для себя подходящий экземпляр. Это же можно сказать и о долгом пути по улицам города в поисках аптеки. Цикл дает сценарию инструкцию периодически повторять последовательность действий до тех пор, пока не будет выполнено определенное условие. Например, программа JavaScript проверки правильности данных может анализировать каждый символ, вводимый пользователем в текстовом поле, чтобы убедиться в его принадлежности к числовым данным. Если у вас есть набор данных, сохраненных в виде списка, то в цикле можно проверить, где в этом списке располагается введенный символ. Как только условие выполнится, сценарий прекратит выполнение цикла и продолжит работу со следующей после последнего оператора цикла инструкции. Наиболее часто используемой в JavaScript циклической структурой является оператор for. Он получил свое имя по первому слову используемого в нем оператора. Оператор цикла for является мощным программным средством, поскольку с его помощью можно много раз подряд выполнять самые сложные операторы. Используется этот оператор следующим образом. for {[начальное выражение]; [условие]; [выражение обновления]) { операторы внутри цикла ) Квадратные скобки указывают на то, что расположенные в них параметры не обязательны для введения. Тем не менее, пока у вас нет твердых навыков использования оператора цикла for, рекомендуем использовать эти опции в каждом случае. Раздел начальное выражение обычно используется для того, чтобы установить начальное значение для счетчика цикла. Под условием подразумевается такое же выражение, что использовалось в условной конструкции if. В данном случае это выражение определяет условие, при наступлении которого выполнение цикла прекращается. Наконец, выражение обновления представляет собой оператор, который выполняется каждый раз после выполнения всех вставленных в тело цикла операторов. Общий принцип использования цикла подразумевает инициализацию переменной i, значение которой постоянно увеличивается по ходу выполнения цикла. Так продолжается до тех пор, цока это значение не превысит некоторой максимальной величины, как это показано в следующем примере. for (var i = начальное значение; i <= максимальное значение; i++) { операторы цикла } Под терминами начальное значение и максимальное значение в данном случае подразумевается произвольное числовое значение (в том числе явно заданные числа и переменные с числовыми значениями). В выражении обновления использован оператор, с которым ранее мы сталкивались. Оператор ++ увеличивает значение i на 1 каждый раз после выполнения тела цикла. Это увеличение происходит обязательно после выполнения итерации цикла. Если значение начальное значение равно 1, то в первой итерации цикла значение i будет равно 1, во второй итерации — 2 и т.д. Если значение максимальное значение равно 10, то цикл будет повторяться ровно 10 раз (другими словами, до тех пор, пока значение i будет меньше 108 Часть II. Руководство по JavaScript
либо равно 10). Выражения в теле цикла могут также использовать значение переменной- счетчика. Позже в этой главе речь пойдет о переменной, которая играет ключевую роль в операторах тела цикла. В то же время, вы должны знать, как прервать выполнение цикла и в каких ситуациях это следует делать. Функции В главе 5 приведен пример использования в JavaScript функции. Под функцией подразумевают набор предопределенных действий. Функции используются повсеместно в сценарии обработчиками событий или операторами. Где это только возможно, все сложные наборы операторов стоит организовывать в функции, чтобы впоследствии использовать их в других документах. Функции — это те строительные блоки, которые применяются многократно. Тем, кто уже имеет опыт программирования, может показаться очевидным подобие функций JavaScript и подпрограмм в других средах программирования. Но, в отличие от других языков, где используется разделение на процедуры (в которых выполняются последовательности действий) и функции (в которых выполняются действия и в качестве результата обязательно возвращается значение), в JavaScript подобного разделения нет. Функция в JavaScript может возвращать значение в вызывающий ее оператор, однако это требование не является обязательным. Тем не менее, когда при использовании функции значение все же возвращается, вызывающий ее оператор трактует эту функцию как обычное выражение— значение функции используется именно в том месте, откуда эта функция вызвана. Формальный синтаксис использования функций выглядит так. function имя_Функции ([параметр!] ... [параметре] ) { опера торы } На имена, которые присваиваются функциям, накладываются те же ограничения, что и на имена элементов и переменных HTML. Можно порекомендовать использовать такое имя для функции, которое отображало бы задачи, возлагаемые на нее. Удобным при этом является использование имен из нескольких слов в слитном формате. В таком случае имя лучше начинать с глагола, поскольку функция выполняет действие (даже если она только получает или устанавливает значение определенной переменной). При написании функций полезно задать ей узкую специализацию. В принципе, можно сгенерировать функцию длиной в несколько сотен строк кода. Однако такие функции трудно обслуживать и отлаживать. Поэтому такие громадные конструкции следует разбить на небольшие, более сегментированные структуры. Параметры функций В главе 5 был приведен пример обработчика события, который вызывает функцию с помощью ее имени. Любой вызов функции, включая и функции из других операторов JavaScript, осуществляется по одной и той же схеме: в конце имени каждой функции следуют скобки. Можно определить функцию так, что она будет получать значения своих параметров непосредственно из вызывающего ее оператора. В листинге 7.1 показан пример документа, в который добавлена кнопка. Обработчик события onclick этой кнопки вызывает функцию, передавая ей при этом текстовые данные в качестве параметра. Текстовая строка, используемая в вызове обработчиком события, является вложенной строкой — это набор одинарных кавычек внутри двойных кавычек, используемых во внешних атрибутах обработчика событий. Глава 7. Основы программирования. Часть 2 109
<html> <head> <script type="text/javascript"> function showMsg(msg) { alert("The button sent: " + msg); } </script> </head> <body> <form> <input type="button" value="Click Me" onclick="showMsg('The button has been clicked!')"> </form> </body> </html> Параметры (известные также как аргументы) призваны обеспечить механизм "передачи" значения от одного оператора к другому в процессе вызова и выполнения функции. Если в определении функции вообще не используются параметры, то и в описании функции при ее вызове вы увидите пустую пару скобок (см. листинг 5.8 главы 5). Переменным, указанным на месте параметров в описании функции, присваиваются вводимые в коде вызова функции значения. Рассмотрим, например, такой фрагмент кода сценария. function sayHiToFirst(a,b,c) { alert("Say hello, " + a); } sayHiToFirst("Gracia", "George", "Harry"); sayHiToFirst("Larry", "Мое", "Curly"); Если функция определена в сценарии, в следующем операторе она будет вызвана. В качестве параметров ей при этом передается три строки. В силу определения функции любые значения строк присваиваются параметрам a, b и с. Таким образом, еще до того, как будет выполнен оператор alert () внутри функции, значение а будет приравнено к "Gracia", значение b— "George", а значение с— "Harry". Поскольку в операторе alert О используется только значение а, то в результате получим сообщение. Say hello, Gracia Когда пользователь закроет окно первого сообщения, согласно сценарию данная функция будет вызвана еще раз. На этот раз, тем не менее, функции передаются уже другие значения, которые и будут присвоены параметрам a, b и с. Диалоговое окно в этом случае содержит такое предупреждение. Say hello, Larry В отличие от других переменных, которые определяются в сценариях, при инициализации параметров функции не нужно использовать ключевое слово var. Параметры инициализируются автоматически, в каком бы месте ни вызывалась функция. Диапазон действия переменных Говоря о переменных, самое время разграничить их на те, которые определяются внутри функций, и те, которые определяются вне функций. Переменные, определяемые вне функций, называются глобальными переменными. Переменные же, определяемые в рамках функций, называются локальными переменными. 110 Часть //. Руководство по JavaScript
Глобальные переменные в JavaScript имеют совершенно иное, особое значение, по сравнению с большинством других языков. В JavaScript пределы "глобальности" для переменных доходят до размеров текущего документа, загруженного в окно браузера. Поэтому инициализация переменной в качестве глобальной подразумевает, что все операторы страницы (включая и те, что расположены в описании функций) получают прямой доступ к значению этой переменной. Операторы могут восстанавливать и изменять значения глобальных переменных в любом месте страницы. Используя терминологию программирования, можно сказать, что эти переменные имеют глобальную область действия, поскольку буквально все элементы страницы могут их использовать для своих нужд. Помните, что в тот самый момент, когда страница выгружается, все глобальные переменные, определенные на ней, будут удалены из памяти. Если нужно передать определенное значение от одной страницы к другой, то для этого следует использовать другие технологии (например, глобальную переменную в документе многофреймовой структуры, о чем рассказано в главе 16, или использовать метод, приведенный в главе 18). Ключевое слово var при инициализации глобальных переменных задавать необязательно, однако мы настоятельно рекомендуем его использовать в любых ситуациях. Это поможет избежать недоразумений при работе с будущими версиями языка JavaScript. В отличие от глобальных переменных, локальные переменные определяются внутри функций. С тем, как в функциях описываются параметры, вам уже приходилось сталкиваться (в этом случае ключевое слово var при инициализации не использовалось). Что касается остальных переменных, то их можно определить с помощью ключевого слова var (для локальных переменных его использовать обязательно всегда). Диапазон легитимности локальных переменных не выходит за рамки операторов в теле описания функции. Ни одна другая функция или оператор за пределами текущей не в силах получить доступ к локальной переменной. "Локальная область действия" определяется в тех случаях, когда для разных локальных переменных в рамках одного документа используются одинаковые имена. В большинстве случаев подобная практика весьма ущербна, поскольку приводит к очень неприятным ошибкам, которые крайне тяжело отслеживать. В то же время, в некоторых случаях удобно использовать одни и те же имена, скажем, для счетчиков в программном цикле for. Это вполне безопасно, поскольку такие счетчики в начале запуска цикла каждый раз заново инициализируются с начальным значением. Тем не менее, вставить один цикл for в другой такой же цикл, не использовав при этом отличную переменную для счетчика, вам не удастся. Для того чтобы продемонстрировать структуру и поведение локальных и глобальных переменных, а также показать, почему крайне нежелательно использовать в документе для разных переменных одинаковые имена, приведен листинг 7.2. В нем описаны две локальные и две глобальные переменные. При этом имена локальной переменной совпадают с именами глобальной переменной. <html> <head> <script type="text/JavaScript"> var aBoy = "Charlie Brown"; // глобальная переменная var hisDog = "Snoopy"; // глобальная переменная function demo() { // Это пример того, как поступать не следует var hisDog ="Gromit" // локальная версия переменной hisDog var output = hisDog + "does not belong to " aBoy + ".<br>n; document.write(output); } </script> Глава 7. Основы программирования. Часть 2 111
</head> <body> <script type="text/JavaScript"> demo(); // запускается при загрузке документа document.write(hisDog + "belongs to " + aBoy + "."); </script> </body> </html> Когда страница загружается, сценарий в разделе заголовка инициализирует две глобальные переменные (аВоу и hisDog) и создает в памяти функцию demo (). В теле документа эту функцию вызывает другой фрагмент сценария. Внутри функции инициализируются две локальные переменные, одна из которых (hisDog) имеет имя, совпадающее с именем глобальной переменной. В JavaScript такое двойное описание переменной приводит к тому, что везде в пределах данной функции приоритетным для всех операторов функции будет описание локальной переменной. Однако следует обратить внимание на такой факт: если убрать ключевое слово var из локальной инициализации, то в результате глобальной версии этой переменной будет присвоено новое значение "Gromit". Другая локальная переменная output предназначена, скорее, для сохранения текста, чем для отображения его на экране. Аккумуляция текста переменной начинается с того момента, когда вычисляется значение локальной переменной hisDog. Затем проводится объединение текстовых фраз (обратите внимание на дополнительные пробелы в конце строк). Затем определяется значение глобальной переменной аВоу. Ни одна глобальная переменная не может быть вытеснена локальной переменной, доступной в данной функции. После этого определяется выражение HTML, которое нужно отобразить на странице так, чтобы оно заканчивалось пробелом и дескриптором <br>. В последнем операторе функции содержимое выводится на странице. Когда стоящая перед функцией задача будет выполнена, следующий оператор тела документа выведет на страницу еще одну строку. Поскольку этот оператор сценария имеет глобальную область действия (т.е. он находится вне функции), ему будут доступны все глобальные переменные, включая и те, которые определены внутри других дескрипторов <script > данного документа. Когда загрузка всей страницы будет полностью завершена, на странице появится следующий текст. Gromit does not belong to Charlie Brown. Snoopy belongs to Charlie Brown. Использование фигурных скобок Вводить фигурные скобки ({}) и применять их в JavaScript (и многих других языках) несложно. Их обычно используют для выделения блоков кода, которые должны выполняться вместе. Наличие таких фигурных скобок позволяет программистам легче разобраться в последовательности выполнения операторов, кроме того, они помогают браузеру определить порядок группировки инструкций. Фигурные скобки вводятся только парами. Фигурные скобки используются, в основном, в описаниях функций и в управляющих структурах. В описании функции в листинге 7.2 фигурные скобки группируют вместе четыре оператора, которые выполняют все ее действия (включая и строки комментария). Закрывающая скобка указывает браузеру на то, что все расположенное после нее к функции никакого отношения не имеет. Если говорить о синтаксическом размещении фигурных скобок, то жестких правил в JavaScript на этот счет не существует (как вы уже наверняка убедились). Приведенные ниже описания функций трактуются браузером совершенно идентично. 112 Часть //. Руководство по JavaScript
function sayHiToFirst(a, b, c) { alert("Say hello, " + a); } function sayHiToFirst(a, b, c) { alert("Say hello, " + a); } function sayHiToFirst (a, b, c) {alertC'Say hello, " + a);} В этой книге мы будем придерживаться первого варианта, поскольку он является более простым при анализе кода сценария — особенно это относится к сценариям, в которых много вложенных управляющих структур. Массивы В JavaScript одним из наиболее полезных способов организации и хранения данных являются массивы. Представить себе самый простой массив можно в виде одномерной таблицы. В каждом столбце строки такой таблицы содержатся данные, при этом каждый столбец пронумерован. Для нумерации столбцов массива используется строгая числовая последовательность, в которой первый столбец имеет нулевой номер (программисты всегда начинают считать с нуля). Эти номера столбцов массива еще называют индексами. Чтобы получить доступ к элементу массива, необходимо знать имя этого массива и номер столбца нужного элемента массива. Поскольку значения индексов начинаются с нуля, то общее количество элементов массива (определяется свойством массива length) всегда на единицу больше самого большого индекса в массиве. Более совершенная концепция массивов позволяет создать подобие массива с несколькими строками в столбце. Такие структуры описаны в главе 30. На данном этапе имеет смысл ограничиться рассмотрением массивов, состоящих из одной строки. Данные, хранящиеся в качестве элементов массива в JavaScript, могут быть любого типа, в том числе и объектами. В отличие от большинства других языков программирования, в различных столбцах массива JavaScript могут содержаться данные разных типов. Создание массива Массив определяется с помощью переменной. Поэтому при создании массива переменной присваивается объект нового массива. Да, массивы являются объектами JavaScript, но к базовому языку JavaScript они все же имеют большее отношение, чем к объектной модели документа. При объявлении массива используется специальное ключевое слово new, которое помогает вызвать специальную функцию JavaScript, генерирующую массив и выделяющую для него место в памяти. Необязательный параметр функции Array () позволяет указать еще на этапе создания массива, ориентировочное количество элементов, зарезервированных в данном массиве. В этом смысле JavaScript является очень демократичным языком, поскольку размер массива можно изменить в любое время. Поэтому если при создании нового массива в качестве параметра ничего указано не будет, то сценарий от этого совершенно не пострадает. Для того чтобы наглядно продемонстрировать процесс создания массива, приведем код конструктора массива, элементами которого являются названия 50 штатов и одного округа Колумбия (всего 51 элемент). Первым делом создается массив; ему присваивается имя, которое лучше всего характеризует содержащиеся в нем данные. var USStates = new Array(51); Начиная с этого момента, в памяти будет выделено место для массива с именем USStates, где содержится 51 элемент. Для того чтобы заполнить этот массив, каждому его элементу Глава 7. Основы программирования. Часть 2 113
нужно присвоить значение. Обращение к каждому элементу массива требует использования специального индекса: сначала указывают имя массива, а затем в квадратных скобках вводится индекс нужного элемента. Первым элементом в массиве USStates будет USStates[0] Чтобы присвоить первому элементу массива первое по алфавиту название штата, необходимо воспользоваться обычным оператором присваивания USStates[0] = "Alabama"; Остальные элементы массива можно заполнить следующим способом. USStates[1] = "Alaska"; USStates [2] = "Arizona"; USStates[3] = "Arkansas"; USStates [50] = "Wyoming"; Если в документе нужно использовать таблицу данных, из которой сценарий впоследствии должен получать информацию, то исключить обращение к серверу можно, оформив ее в виде массива. Если сделать соответствующие операторы выполняющимися в процессе загрузки документа, то к тому моменту, когда документ будет полностью отображен в браузере, массив данных уже будет создан и готов к использованию. Несмотря на то, что у вас может сложиться впечатление о необходимости использования в такой ситуации большого числа операторов, объем загружаемых данных, на самом деле, невелик. Он не представляет особых проблем, поэтому загрузка страницы проходит идеально даже у тех пользователей, которые используют каналы соединений со скоростью передачи данных 28,8 Кбит/с. Получение доступа к данным массива Индекс элемента массива является тем ключом, который позволяет получать доступ к нему. Указав имя массива и индекс нужного элемента в квадратных скобках после имени, можно получить значение, записанное в соответствующем столбце массива. Например, после создания массива USStates сценарий может вывести на экран окно сообщения с названием штата Аляска, для чего предназначается следующий код. alert("The largest state is " + USStates[1] + "."); Точно так же, как вы добираетесь до значения элемента по имени массива и индексу, можно изменить значение элементов массива. Для этого нужно указать элемент и присвоить ему новое значение. Параллельные массивы Ниже показано, почему использование в качестве индексов массивов чисел в JavaScript является оптимальным вариантом. Для того чтобы пример был более наглядным, сгенерируйте еще один массив наряду с уже существующим USStates. Этот новый массив также будет состоять из 51 элемента и содержать в качестве данных годы, в которые соответствующие штаты из первого массива USStates вступили в Конфедерацию. Выглядит описанная выше структура следующим образом. var stateEntered = new Array(51); stateEntered [0] = 1819; stateEntered [1] = 1959; stateEntered [2] = 1912; stateEntered [3] = 1836; stateEntered [50] = 1890; 114 Часть II. Руководство по JavaScript
Содержащиеся в памяти браузера две таблицы с данными можно представить так, как показано на рис. 7.1. Используя описанный принцип, добавьте любое количество дополнительных массивов, параллельных текущим массивам. Например, это могут быть почтовые индексы или названия столиц штатов. Важно отметить, что нулевые элементы всех массивов соответствуют штату Алабама — первому штату массива USStates. USStates "Alabama" "Alaska" "Arizona" "Arkansas" "Wyoming" [0] [1] | [2] [3] [50] stateEntered 1819 1959 I 1912 1836 I 1890 1 Рис. 7.1. Вид двух взаимосвязанных таблиц Если на Web-странице используются обе эти таблицы и пользователю необходимо найти дату вступления конкретного штата в Конфедерацию, то сначала придется просмотреть все записи массива USStates, найти индекс нужного штата, а лишь затем по данному индексу из массива stateEntered вы узнаете нужную дату. В данном примере на страницу добавляется текстовое поле — в него пользователь может ввести название штата, дату вступления которого в Конфедерацию необходимо определить. В реальном приложении такой подход может привести к некоторым проблемам. Вы должны обязательно проверить правильность вводимого пользователем названия. В данном случае на такие "пустяки" пока отвлекаться не будем. Будем считать пользователя грамотным человеком. Конечно, при разработке настоящих приложений для Web такими вещами пренебрегать нельзя. Обработчик события текстового поля или специальной кнопки (в данный момент это не важно) вызывает функцию, которая занимается поиском элемента для названия штата, определяет соответствующую дату и отображает окно, содержащее найденную информацию. function getStateDate{) { var selectedState = document.entryForm.entry.value; for ( var i = 0; i < USStates.length; i++) { if (USStates[i] == selectedState) { break; } } } alert("The state entered the Union in + ".") ; + stateEntered[i] В первом операторе функции переменной selectedState присваивается то значение, которое введено пользователем в текстовом поле. Такое длинное имя для переменной выбрано для большей наглядности. Фактически, эта переменная используется только в цикле for, поэтому браузеру не нужно каждый раз преобразовывать длинную ссылку на текстовое поле, что в конечном счете способствует повышению эффективности сценария. Особенность функции заключается в цикле for. Именно в нем увеличение счетчика на каждом этапе выполнения цикла совмещается с использованием этого счетчика в качестве индекса для элементов обоих массивов. В параметрах цикла указывается следующее: начальным значением для переменной-счетчика i должен быть нуль. Цикл будет выполняться до тех пор, пока значение переменной i будет меньше длины массива USStates. Не забывайте, Глава 7. Основы программирования. Часть 2 115
что длина массива всегда на единицу больше, чем индекс последнего элемента в этом массиве. Поэтому, когда цикл запускается последний раз и значение переменной i равно 5 0 (что точно меньше длины массива, равной 51), то это будет соответствовать индексу последнего элемента массива. Каждый раз после выполнения очередной итерации значение переменной- счетчика будет увеличиваться на единицу. Внутри оператора цикла for используется условный оператор if, с помощью которого проверяется совпадение значения элемента массива с тем, что введено пользователем в текстовом поле. Каждый раз при запуске цикла условие проверяется для очередного элемента массива, начиная с элемента с индексом нуль. Другими словами, условие, используемое в операторе if, может проверяться десятки раз, пока совпадение не будет обнаружено. Но каждый раз при этом значение переменной i увеличивается на единицу по сравнению с предыдущим вариантом. Оператор проверки равенства (==) необычайно строг при сравнении строковых значений. В этом случае на совпадение проверяются символы с учетом регистра (т.е. строчные и прописные буквы различаются). Для того чтобы в данном примере совпадение было обнаружено, название штата должно указываться пользователем абсолютно идентично тому, как оно представлено в массиве US States. В главе 10 будут описаны методы, позволяющие ослабить жесткость требований при проверке равенства строковых значений. Если совпадение имен обнаружено, выполняется оператор, заданный внутри условного оператора if. Оператор break добавлен в сценарий на тот случай, если понадобится прервать выполнение программы. В данном приложении при обнаружении совпадения оператор цикла for досрочно прекращает работу. Когда цикл for прерывается, значение переменной i фиксируется на том значении, которое соответствует элементу массива USStates, в котором хранится нужная запись. Это значение впоследствии используется для получения доступа к элементу другого массива. Даже несмотря на то, что переменная-счетчик i специально инициализирована для использования в операторе цикла for, она остается доступной в пределах функции для всех операторов даже после выполнения цикла. Вот почему эту переменную можно использовать для того, чтобы определить значение нужного элемента в массиве stateEntered и отобразить результат в окне сообщения. Приведенный пример использования в операторе for переменной-счетчика для указания индексов является довольно типичным для JavaScript. Поэтому внимательно изучите код и разберитесь, как он работает. Это имеет отношение не только к способам управления массивами, но и к генерации браузерами массивов в объектных моделях документов. Объекты документа в массиве Если заглянуть в справочные разделы приложения А и найти там подраздел, описывающий объект document, то нетрудно заметить, что свойства некоторых объектов приведены в квадратных скобках после соответствующих имен. Это такие же квадратные скобки, которые использовались выше для указания элементов массива. Дело в том, что при загрузке браузером в документе создаются объекты, подобные массивам. Например, если на странице используются два дескриптора формы <FORM>, то в документе появится две формы. В браузере будет поддерживаться массив объектов форм для данного документа. Ссылаться на такие формы можно следующим образом. document.forms[0] document.forms[1] Индекс значения для объектов документа присваивается в зависимости от очередности загрузки объектов. В случае с объектами формы такой порядок определяется очередностью следования дескрипторов формы <FORM> в коде документа. Такая индексная форма записи является еще одним способом представления формы в структуре ссылки на объекты. Параллельно можно продолжать использовать имена форм, что намного удобнее, поскольку 116 Часть //. Руководство по JavaScript
в последнем случае изменение порядка их следования в коде HTML-документа никак не повлияет на ссылки. Но если страница содержит, скажем, только одну форму, то можно использовать разные типы ссылок поочередно, как это показано на примере обращения к свойству length текстового поля формы. document .getElementsById( "entryForm'i) .elements, length document.forms[0].elements.length В многочисленных примерах этой книги можно найти ссылки самых разных типов и структур. Однако подобное разнообразие редко применяется одновременно в серьезных программных разработках. Упражнения 1. Получив информацию об использовании функций, обработчиков событий и управляющих структур, воспользуйтесь фрагментами сценария этой главы, чтобы создать страницу, в которой представлена таблица всех штатов с датам их вступления в Конфедерацию. Если у вас под рукой нет справочника с соответствующими датами, то используйте любые числа, начиная с 1800. На странице нужно создать поле для ввода текста, в котором задается название штата, а также кнопку, щелчок на которой будет инициализировать начало поиска в массивах. 2. Исследуйте приведенное ниже описание функции. Есть ли в этом описании неточности? Если да, то как их устранить? function format(ohmage) { var result; if ohmage >= le6 { ohmage = ohmage / 1еб; result = ohmage + " Mohms"; } else { if (ohmage >= le3) ohmage = ohmage / le3; result = ohmage + " Kohms"; else result = ohmage + " ohms"; } alert(result); 3. Разработайте собственный синтаксис для сценария выбора зрелого помидора в овощном отделе супермаркета. Запишите цикл for для этого сценария. 4. Измените листинг 7.2 так, чтобы внутри функции переменная hisDog повторно не использовалась. ч 5. Ниже приведена таблица с данными о некоторых планетах Солнечной системы. Нужно создать Web-страницу, на которой пользователь введет название планеты и по щелчку на кнопке получит окно сообщения с указанием расстояния этой планеты до Солнца и ее диаметр. Если получится, сделайте так, чтобы эта информация выводилась на странице в отдельных полях. Планета Расстояние до Солнца Диаметр Меркурий 52 млн. км 4 880 км Венера 108 млн. км 12 100 км Земля 149 млн. км 12 750 км Марс 228 млн. км 6 800 км Глава 7. Основы программирования. Часть 2 117
Объекты документа и окна осле изучения методологических основ программирования можно перейти к вопросу взаимодействия сценариев и объектов документа. Начиная с этой главы, мы обратимся к объектной модели документа. Более подробно мы остановимся на тех объектах, которые в дальнейшем будут чаще всего использоваться в документе. Объекты окна документа Чтобы вспомнить, как выглядит самая общая иерархическая структура объектов документа, взгляните в рис. 8.1. В этой главе ваше внимание будет сконцентрировано на верхней части этой структуры: на объектах window, location, navigator и document. Главная цель — не просто загрузить вас багажом знаний, необходимых для решения простых задач, но также подготовить к глубокому и всестороннему исследованию как каждого объекта, так и его свойств, методов, а также обработчиков событий. Последним посвящена часть Ш этой книги. Вы узнаете об основных свойствах, методах и обработчики событий объектов — более подробную информацию о них можно получить в части Ш. Примеры, приведенные в этой главе, полностью основаны на материале предыдущих глав, посвященных основам написания программ. Объект окна В самом верхней части иерархической структуры объектов документа находится объект window. Этот объект занимает особое, привилегированное положение в наборе объектов, поскольку он представляет основной контейнер, в котором размещается все то, чем можно управлять с помощью Web- браузера. В течение всего времени, пока окно браузера открыто (даже если в нем не загружен ни один документ), объект window будет находиться в текущей объектной модели, хранящейся в памяти. п
window navigator screen history location document Рис. 8.1. Общая иерархическая структура объектов документа, используемая браузерами Область использования объекта окна достаточно широка — от регулирования содержимого окна до настройки его размеров. Размеры окна определяют область, в которой размещаются также полосы прокрутки, панели инструментов, строки состояния и меню (в Windows) т.е. все, что относится к атрибутам окна. Далеко не каждый браузер обладает средствами управления этими элементами главного окна браузера. Однако всегда можно написать сценарий, создающий дополнительное окно, размеры которого несложно изменить в соответствии с вашими требованиями, а также отобразить в нем только самые необходимые элементы. Несмотря на то, что о подокнах (или фреймах) речь пойдет только в главе 11, на данном этапе можно совершенно спокойно утверждать, что каждый фрейм может рассматриваться как отдельный объект window. Использовать систему фреймов весьма эффективно, поскольку в каждом фрейме могут содержаться отдельные готовые документы. Когда в одном из этих документов запускается сценарий, то в иерархической структуре объектов соответствующее подокно рассматривается как объект window. Как вы узнаете далее в этой главе, объект window удобно использовать для определения методов объектной модели документа, которые отображают вложенные диалоговые окна и управляют текстом, представляемым в строке состояния окна браузера. Методы объекта window позволяют создать отдельное окно, которое будет отображаться на экране. Основная же часть всех свойств, методов и обработчиков событий объекта window (см. главу 16) связана с процессами отображения различных элементов окна. Получение доступа к свойствам и методам окна В сценарии ссылки на свойства и методы объекта window можно реализовать разными способами. Это определяется, скорее, предпочтениями профаммиста и стилем, которого он придерживается, чем определенными синтаксическими требованиями. Наиболее общим и логическим подходом является тот, в котором задается непосредственное обращение к объекту window. window.имяСвойства window. имяМетода ( [параметры] ) К объекту window часто обращаются с помощью синонима. Делается это в тех случаях, когда в сценарии используются ссылки на окно, содержащее текущий документ. Синонимом является ключевое слово self. В таких случаях ссылки выглядят следующим образом. self.имяСвойства self. имяМетода ( [параметры] ) Использовать подобные ссылки можно по собственному усмотрению. Однако целесообразно задавать ссылки с помощью self в сложных сценариях, в которых задействовано несколько фреймов или окон. Другими словами, идентификатор self используется для обозначения того текущего окна, в котором находится документ с данным сценарием. А это, в свою очередь, делает сценарий более читабельным, по крайней мере так думают многие разработчики программных продуктов. Глава 8. Объекты документа и окна 119
Как уже отмечалось в главе 4, поскольку объект window всегда присутствует "на месте" при запуске сценария, то в ссылке на объекты внутри текущего окна его имя можно опустить. В качестве примера ниже приведена синтаксическая модель обращения к свойствам и методам текущего окна. имяСвойства имяМетода ( [параметры] ) Принципы использования некоторых методов воспринимаются легче, если в ссылке не используется ключевое слово window. В этом случае методы выполняются так же эффективно, как и ранее. Создание окна Главное окно браузера в сценарии не создается. Это делает пользователь при запуске браузера, а также при открытии документа с определенным URL или другого файла (если окно браузера не было открыто до этого). Однако с помощью сценария можно сгенерировать любое число дополнительных окон (если главное окно открыто и в него помещен документ, новые окна открывает сценарий главного окна). Метод, с помощью которого можно генерировать новые окна, — window. open (). В этом методе используется до трех параметров, которые определяют такие характеристики окна, как URL загружаемого документа, его название, указываемое в атрибутах target дескрипторов HTML, а также физические параметры (размер и содержимое). Более детально на этих параметрах мы пока останавливаться не будем (они рассмотрены в главе 16), однако одну важную особенность использования метода window, open () все же рассмотрим. Ниже приведен пример оператора, который открывает новое окно предопределенного размера с отображенным документом HTML, расположенным в той же папке на сервере, в которой хранится текущая страница. ' var subWindow = window.open("define.html","def", "height=200/ width=300");, Обратите внимание на то, что в приведенном выше коде используется оператор присваивания. С его помощью переменной subWindow присваивается некое значение. Оказывается, что при запуске метода window. open () не только открывается новое окно согласно используемым параметрам, но также создается ссылка на новое окно. На языке программирования можно сказать, что метод возвращает значение — в данном случае это самая настоящая ссылка на объект. Значение, возвращаемое методом, присваивается переменной. Теперь эта переменная может вполне законно использоваться как ссылка на второе окно. Если нужно получить доступ к одному из его свойств или методов, то следует использовать указанную ссылку как часть полной ссылки. Например, для того чтобы закрыть прямо из сценария главного окна данное подокно, можно воспользоваться методом close (). subWindow.close(); Если в сценарии главного окна используются записи window, close (), self .close или просто close (), то будет закрыто главное окно, а вовсе не дополнительное. Поэтому для обращения к другим окнам следует использовать ссылку на нужное окно как часть общей ссылки. Этот момент важен при составлении.сценариев: часто требуется, чтобы переменная, содержащая ссылку на дополнительное окно, была доступна в течение всего времени, пока главный документ загружен в браузер. Чтобы обеспечить это, следует объявить данную переменную как глобальную, но ни в коем случае не внутри функции (хотя значение этой переменной можно присвоить и в пределах функции). В такой ситуации используйте одну функцию, чтобы открывать окна, а другую — для их закрытия. Листинг 8.1 описывает страницу, которая содержит кнопку открытия нового, пустого окна, которое впоследствии можно будет закрывать из главного. Вы увидите, как работает сценарий, 120 Часть //. Руководство по JavaScript
если зададите размеры главного окна браузера так, чтобы оно не было развернуто во весь экран. Тогда при генерации нового окна можно будет разместить окна на экране таким образом, чтобы новое окно было видно даже в том случае, когда основное находится на переднем плане. Если окно было при этом "скрыто" за основным, то для его отображения используйте меню Window (Окно) браузера. В листинге 8.1 переменная newWindow объявлена как глобальная, поэтому обе функции— makeNewWindow () и closeNewWindowO — без особых проблем получают к ней доступ. Если переменная объявляется без присвоения ей значения, то по умолчанию оно равно null. Значение null интерпретируется как эквивалентное false в условном операторе. С другой стороны, наличие в условном операторе любого ненулевого значения интерпретируется как true. В функции closeNewWindowO перед использованием метода закрытия close () сначала проверяется, было ли вообще создано новое окно. Затем для выполнения очистки переменной newWindow присваивается значение null, поэтому при повторном щелчке на кнопке Close (Закрыть) закрытия уже несуществующего окна не произойдет. Листинг 8.1. Ссьшка на объекты окна <html> <head> <title>Window Opener and Closer</title> <script type="text/javascript"> var newWindow function makeNewWindow() { newWindow = window.open("","»,"height=3 00,width=300"); } function closeNewWindowO { if (newWindow) { newWindow.close(); newWindow = null; </script> </head> <body> <form> <input type="button" value=nCreate New Window" onclick="makeNewWindow()"> <input type="button" value="Close New Window" onclick="closeNewWindowO"> </form> </body> </html> Свойства и методы окна Три описываемых в этой главе метода и одно свойство объекта window имеют непосредственное отношение к задачам, часто решаемым пользователями. Они доступны во всех браузерах, поддерживающих сценарии. Для каждого метода и свойства, подробно описанного в части Ш, в данной книге приведено немало примеров использования. Вы можете поэкспериментировать со сценарием, состоящим из единственного оператора, введя его в верхнем текстовом поле приложения The Evaluator Jr (см. главу 6). Глава ft Объекты документа и окна 121
Свойство window.status Строка состояния в нижней части окна браузера при наведении на нее указателя мыши обычно отображает адрес URL ссылки. При загрузке документа, инициализации аплетов Java и подобных действиях в этой области отображаются другие сообщения. Тем не менее, с помощью JavaScript можно сделать так, что в определенные моменты в строке состояния будут отображаться собственные сообщения разработчика страницы, которые предоставляют полезную для пользователя информацию. Например, вместо того чтобы отображать адрес URL ссылки, можно вывести дружественное, доступное описание страницы (или комбинацию первого и второго, чтобы удовлетворить самые изысканные запросы). Присвоить свойству window, status другое текстовое значение можно в любое время. Чтобы заставить текст в строке состояния изменяться каждый раз при наведении на ссылку указателя мыши, следует задать обработчик события onmouseover для объекта ссылки. В JavaScript такое поведение задается крайне редко, однако к таким мерам приходится прибегать, чтобы сценарий успешно перепрограммировал содержимое строки состояния. Поскольку свойство window, status установить достаточно просто, то наиболее общий подход для управления строкой состояния — это запуск внутри дескрипторов операторов обработчика события. Это удобно при управлении небольшими сценариями, поскольку не требует определения отдельных функций или добавления дескрипторов <script> на страницу. В дескриптор <а> оператор обработчика события добавляется без предварительного задания дескриптора сценария. <а href=Mhttp://www.microsoft.com" onmouseover= "window.status='Visit the Microsoft Home page (microsoft.com)' "> Microsoft</a> Обратите особое внимание на операторы, используемые в обработчике события onmouseover. Речь идет о двух следующих выражениях. window.status='Visit the Microsoft Home page (microsoft.com)1 При запуске этих операторов внутри обработчика события нужно разделять их точкой с запятой. Пробел после точки с запятой ставить не обязательно, однако он улучшает читабельность кода. Важно даже то, что весь набор операторов заключен в двойные кавычки ("..."). Чтобы вставить в двойных кавычках строку, присвоенную в качестве значения свойству window.status, следует заключить эту строку в одинарные кавычки ('...'). Настройка строки состояния в будущем принесет значительные дивиденды, а для этого нужно всего-то ввести несколько дополнительных строк кода. Как бы там ни было, а работа с успехом завершена. Все! Метод window.alert() В этом руководстве метод alert () уже использовался неоднократно. Он генерирует диалоговое окно, отображающее тот текст, который передается методу в качестве параметра (рис. 8.2). Единственная кнопка ОК, надпись которой нельзя изменить предназначена для того, чтобы пользователь мог закрыть окно предупреждения. Рис. 8.2. Окно с предупреждением Внешний вид этого окна и двух других, которые бу- в JavaScript (устаревший стиль) ДУ1 описаны ниже, очень изменился с момента появления первого браузера, поддерживающего использование сценариев. В старых версиях браузеров (как на рис. 8.2) в явном виде указано, что это окно предупреждения JavaScript ([JavaScript Application]). Разные браузеры отображают разные 122 Часть //. Руководство по JavaScript
заголовки окон, что в сценарии изменить невозможно. Изменять допускается только содержимое сообщений. Все три описанных в этой главе метода отображения диалоговых окон можно задать без указания в ссылке объекта window. Даже несмотря на то, что метод alert () технически является методом объекта window, никакой специальной взаимосвязи между диалоговым ойюм и окном, отображающим это диалоговое окно, не существует. В сценарии произвольного назначения обычно добавляют следующую ссылку. alert("This is a JavaScript alert dialog"); //Это диалоговое окно предупреждения JavaScript Метод window.confirm() Ф Are you sure you warrt to start over? С OK 1С Cancel В диалоговом окне другого типа используются уже две кнопки. Для большинства версий браузеров и платформ это кнопки ОК и Cancel (Отмена). Называется такое окно диалоговым окном подтверждения (рис. 8.3). Важным для метода является то, что он возвращает значение true, если пользователь щелкает на кнопке ОК, и false, если пользователь щелкает на кнопке Cancel. Это диалоговое окно и значение, им возвращаемое, можно использовать для предоставления пользователю возможности управления дальнейшими действиями сценария. Поскольку метод возвращает значение булевого типа, то оно может использоваться в качестве условного оператора в конструкции if или операторе if. . .else. Например, в приведенном ниже фрагменте кода у пользователя запрашивается подтверждение на запуск приложения Результат подтверждения — это загрузка используемой по умолчанию страницы узла в браузере. if (confirm("Are you sure you want start over?")) { location.href = "index.html"; } Puc. 8.3. Диалоговое окно подтверждения JavaScript (стиль IE6/WindowsXP) Метод window.prompt() Последним диалоговым окном объекта window является диалоговое окно запроса (рис. 8.4). В нем отображается определяемое разработчиком страницы сообщение и выводится текстовое поле для ввода ответа. Две кнопки, которые присутствуют в диалоговом окне, ОК и Cancel, позволяют пользователю закрыть диалоговое окно с двумя взаимоисключающими исходами: отменой всей операции или принятием того, что введено в текстовом поле. Sctjpt Pkodnpt p. fl in ЦЫв tor how n*y factor»? (20 Puc. 8.4. Диалоговое окно запроса данных в JavaScript (стиль IE6/WindowsXP) Метод window.prompt () подразумевает использование двух параметров. Первый — сообщение, которое выводится пользователю в качестве подсказки. Второй параметр в виде строки используется для того, чтобы задать в текстовом поле предлагаемый по умолчанию Глава 8. Объекты документа и окна 123
ответ пользователя. Если по умолчанию предлагать ответ пользователю не предусмотрено, то в этом случае отображается пустая строка (две двойные кавычки без пробелов между ними). Этот метод возвращает только одно значение при щелчке пользователем на любой из кнопок. Щелчок на кнопке Cancel возвращает значение null независимо от того, что пользователь ввел в текстовом поле. Если пользователь щелкнул на кнопке ОК, то в качестве значения будет возвращена введенная им в текстовом поле строка. Сценарии могут использовать эту информацию в конструкциях if или if. . .else. Значение null в условном операторе при этом трактуется как false. Пустая строка также трактуется как false. Это значение можно использовать для непосредственной проверки того, введены ли вообще в текстовом поле данные — см. следующий пример. var answer = prompt("What is your name?"); if (answer) { alert("Hello," + answer + "!"); } Единственная ситуация, в которой вызывается метод alert О, — пользователь ввел в диалоговое поле текст и щелкнул на кнопке ОК. Обработчик события onload Объект window реагирует на многочисленные события, генерируемые системой или пользователем. Но с одним событием придется работать чаще остальных. Оно возникает тогда, когда все элементы страницы успешно загружены. Это событие состоится только после того, как все изображения, аплеты Java и файлы данных будут полностью загружены в браузер. Получение из сценария доступа к элементам документа в процессе загрузки страницы таит в себе опасность: если объект еще не загружен (возможно, по причине использования плохого сетевого соединения или низкопроизводительного сервера), то в сценарии произойдет ошибка. Преимущество использования события onload состоит именно в том, что оно позволяет использовать функции, обеспечивая наличие объектов документа в объектной модели. Все обработчики событий окна размещаются внутри дескрипторов <body>. Даже если установилась четкая связь атрибутов дескриптора <body> со свойствами объекта документа document, следует помнить, что обработчики событий окна window также располагаются внутри этих дескрипторов. Объект location Иногда создается впечатление, что объект в иерархической структуре не представляет ничего такого, что может нести реальный физический смысл. Именно это относится к объекту location. Данный объект содержит адрес URL загруженного в окне документа. Он существенно отличается от объекта документа document (см. далее) хотя бы потому, что документ имеет реальное содержимое, location — это только URL. Если вы не являетесь экспертом в области Web-технологий, то можете даже не подозревать, что URL состоит из многих компонентов, которые определяют расположение ресурса и методы отправки данных файла. В состав URL входят сведения о протоколе (например, http:) и имени узла (например, www.giantco.com). Получить отдельный доступ ко всем этим элементам можно как к обычным свойствам объекта location. Но, как правило, практический интерес представляет только одно свойство — href, которое определяет URL полностью. Ссылаться на другие страницы сценарий сможет только тогда, когда правильно задано свойство location.href. location.href = "http://www.dannyg.com" 124 Часть II. Руководство по JavaScript
Путешествовать по страницам в пределах собственного Web-узла можно, указывая только относительный URL (т.е. адрес относительно текущей страницы), и для этого совсем не обязательно использовать полный URL со всеми его протоколами и информацией об узле. Для представления страниц за пределами домена текущей страницы нужно обязательно указывать полный URL. Если загружаемая страница будет находиться в другом окне или фрейме, то ссылка на окно должна содержать его адрес. Например, если сценарий открывает новое окно и присваивает на него ссылку переменной newWindow, то оператор, загружающий страницу в подокно, будет выглядеть следующим образом. newWindow.location.href = "http://dannyg.com" Объект navigator Несмотря на созвучие с названием браузера Netscape Navigator, объект navigator поддерживается во всех современных браузерах. С помощью его свойств в сценарии можно легко определить, а потому и передать на сервер сведения об используемом браузере и компьютерной системе. Так, свойство navigator .userAgent возвращает в виде текстовой строки основные сведения о программной среде браузера. Например, если сценарий выполняется в браузере Internet Explorer 6, запущенном в Windows XP, то свойство navigator. userAgent будет содержать следующее значение. Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461) Этот же сценарий, запущенный в браузере Mozilla в Macintosh, возвратит следующие сведения. Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624 В первом сценарии главы 3 вы уже использовали два свойства объекта navigator (appVertion и appName). В главе 38 на прилагаемом к книге компакт-диске вы найдете полное описание этого объекта и его свойств. Обратите внимание, что браузеры обрабатывают данные по-разному (см. главу 14). Объект документа В объекте документа document хранится все реальное содержимое страницы. Свойства и методы объекта document, в основном, воздействуют на внешний вид и содержимое страницы, загруженной в окне. В браузерах W3C DOM можно с помощью сценария получать доступ к тексту страницы только в том случае, если документ полностью загружен. Тем не менее, как это было замечено еще в самом первом сценарии главы 3, метод document .write () позволяет динамически создавать содержимое в процессе загрузки страницы. Многие свойства объекта document являются другими объектами документа. Это позволяет получить к ним доступ несколькими более простыми способами (с помощью метода document. get Element By Id ()). Получить доступ к свойствам и методам объекта document достаточно просто, как это и показано ниже. [window.]document.имяСвойства [window.I document.имяМетода([параметры]) Ссылка на окно [window. ] при получении сценарием доступа к содержащему его объекту document является необязательной. Если нужно с помощью браузера выполнить предварительный просмотр свойств объекта document, то следует в верхнем текстовом поле приложения The Evaluator Jr. ввести document и нажать клавишу <Enter>. В поле Result (Результат) будут отображены свойства объекта и их текущие значения. Глава А Объекты документа и окна 125
Свойство document.forms[] Еще один тип объектов, содержащихся в документе,— это объекты элементов форм form. Поскольку на странице может использоваться более одной формы, то все они собираются в виде массива свойств документа document. forms []. Как читатель, наверное, помнит из главы 7, числовой индекс внутри квадратных скобок указывает на один из элементов массива. Чтобы выяснить, сколько всего форм form используется в данном документе, можно обратиться к следующей команде. document.forms.length Для получения доступа, скажем, к первой форме документа, следует использовать такую ссылку. document.forms[0] Все современные браузеры позволяют обращаться к форме по имени (идентификатору, сохраненному в атрибуте name дескриптора <form>). Причем эту задачу можно выполнить двумя способами. В первом случае используется синтаксис, близкий к используемому при управлении массивами. document.forms["имяФормы" ] В следующих главах вы узнаете о том, как назначить имя форме. Чтобы не ошибиться с формой, рекомендуем вместо имени использовать индекс элемента массива. Второй способ более простой, поскольку имя формы указывается сразу после ключевого слова document. document.имяФормы Использование указанных способов приведет к одинаковому результату. Если в сценарии нужно сделать ссылку на элемент внутри формы, то полный адрес объекта обязательно должен содержать ссылку на document и на саму форму. Свойство document.images[] Подобно тому, как в документе сохраняются сведения о формах (массив элементов), в объекте document содержится коллекция (массив) изображений, которые вставляются в документ с помощью дескриптора <img>. Изображения, представленные массивом document. images, доступны в программном коде по числовому индексу или имени элемента img. Как и в случае с формами, текстовый атрибут name однозначно идентифицирует элемент в наборе объектов. Поддержка браузером свойства document. images гарантирует загрузку и отображение им изображений стандартных для Web. Таким образом, данное свойство можно успешно использовать в качестве флага, указывающего на способность текущего браузера к загрузке и возможность последующего управления изображениями. Чтобы выполнить в сценарии подобную проверку, заключите операторы управления изображениями в конструкцию if, как показано ниже. If (document.images) { //операторы управления изображениями } Старые браузеры не распознают вложенных операторов, а использование конструкции if предотвращает возникновение ошибки, отображаемой на экране. 126 Часть //. Руководство по JavaScript
Метод document.write() Метод document .write () используется как непосредственно в исполняемых сценариях для создания содержимого загружаемой страницы, так и в сценариях, которые создают новое содержимое в текущем или другом окне. Для использования метода нужно указать один строчный параметр, который является элементом HTML, вводимым в окно или фрейм. В качестве указанных строчных параметров могут использоваться переменные или другие выражения, которые преобразуются в строки. Очень часто к ним относятся HTML-дескрипторы. Помните, что после загрузки страницы, выходной поток браузера автоматически закрывается. После этого каждый новый вызов метода document .write () будет приводить к открытию нового потока, что, в свою очередь, вызывает немедленную очистку текущей страницы (вместе со всеми переменными и другими значениями в исходном документе). Поэтому, если вам нужно переместить текущую страницу с помощью генерируемого в сценарии HTML- кода, представьте этот переменной и отобразите соответствующий текст с помощью метода document. write (). Не стоит выполнять очистку документа в явном виде и открывать новый поток данных. Для этого достаточного одного вызова метода document. write О . Еще один полезный совет, относящийся к использованию метода document .write (), имеет отношение к его "сородич/* и "собрату" — методу document. close (). Сценарий должен закрывать выходной поток по окончании записи содержимого в окно (как своего, так и чужого). После последнего вызова метода document .write О в сценарии следует использовать метод document .close О . В противном случае может оказаться, что изображения и формы не будут отображаться. Любое использование метода document .write () впоследствии способствует только добавлению данных на страницу, что предпочтительнее по сравнению с очисткой содержимого и записью его заново. В качестве примера использования метода document .write () приведено две версии одного приложения. В первом случае запись производится в тот же документ, который содержит сценарий. Во втором случае» запись производится в отдельное окно. Введите в текстовом редакторе необходимые документы, сохраните файлы с расширением . html и откройте их с помощью браузера. В листинге 8.2 используется кнопка, которая вызывает новое содержание HTML для документа, включая дескрипторы HTML для заголовка нового документа и атрибуты цвета дескриптора <body>. В листинге присутствует оператор, который ранее не описывался. Это оператор +=. Данный оператор добавляет к строке, содержащейся слева от него, строку, расположенную справа от оператора. Этот оператор позволяет быстро объединить длинные строки из нескольких отдельных операторов. Используя содержимое переменной newContent и всего один вызов метода document. write (), можно наполнить весь документ полностью новым содержимым, не оставив даже следа от содержимого листинга 8.2. Оператор document. close (), тем не менее, в обязательном порядке используется для нормального закрытия выходящего потока. Теперь загрузите документ, щелкните на кнопке и обратите внимание на то, как изменится название документа в строке названия браузера. Если после этого щелкнуть на оригинале и затем снова воспользоваться кнопкой, то динамически заполняемая вторая страница будет загружаться намного быстрее, даже по сравнению с перезагрузкой исходного документа. <html> <head> <title>Writing to Same Doc</title> <script type="text/javascript"> function rewrite() { // Вызов содержимого для нового окна Глава 8. Объекты документа и окна 127
var newContent = "<html><headxtitle>A New Doc</titlex/head>; " newContent += "<body bgcolor='aqua'><hl>this document is brand new.</hl>;" newContent += "Click the Back button to see original document"; newContent += "</body></html>"; // Записывается HTML в новое окно документа document.write(newContent); document.close(); // Закрытие потока } </script> </head> <body> <form> <input type="button" value="Replace Content" onclick="reWrite()"> </form> </body> </html> В листинге 8.3 ситуация несколько сложнее, поскольку сценарий создает подокно, в которое записывается целый документ, сгенерированный сценарием. Чтобы ссылка на новое окно была доступна для всех функций, переменную newWindow объявляют как глобальную. Сразу после загрузки страницы, обработчик события onload вызывает функцию makeNewWindow (). Эта функция создает пустое подокно. Третьему параметру метода window. open () добавлено свойство, которое дает инструкцию строке состояния подокна на отображение данных. Кнопка на странице используется для вызова метода subWrite. Первым заданием, которое он выполняет, является проверка свойства closed подокна. Это свойство (которое введено только в последних версиях браузеров) возвращает значение true, если окно, на которое сделана ссылка, закрыто. Если это так (пользователь самостоятельно закрыл окно), то будет вызвана функция makeNewWindow () и окно будет снова открыто. При открытом окне в виде строчной переменной вызывается новое содержимое. Как и в листинге 8.2, содержимое записывается в один подход (хотя это и не является обязательным для отдельного окна), после чего сразу вызывается метод close (). Обратите внимание на важную особенность: как в методе write (), так и в методе close () подокно задается в явном виде. <html> <head> <title>Writing to Subwindow</title> <script type="text/javascript"> var newWindow; function makeNewWindow() { newWindow = window.open("","","status,height=200,width=300"); } function subWrite() { // Создается новое окно в том случае, если кто-то его закрыл if (newWindow.closed) { makeNewWindow(); } • // Выведение окна на передний план newWindow.focus(); // Вызов содержимого для нового окна var newContent = "<htmlxhead><title>A New Doc</tilex/head>" ; newContent += "<body bgcolor=•coral'> <hl>This document is brand new.</hl>"; 128 Часть II. Руководство по JavaScript
newContent += "</body></html>"; // Запись HTML в новый документ окна newWindow.document.write(newContent); newWindow.document.close(); // Закрытие потока } </script> </head> <body onload="makeNewWindow()"> <form> <input type="button" value="Write to Subwindow" onclick="subWrite()"> </form> </body> </html> Методы document.createElement() и document.createNodef) Метод document. write () применяется к отдельной части Web-страницы на этапе ее первой загрузки в браузер. Любое повторное выполнение этого метода приводит к удалению содержимого Web-страницы и созданию новой страницы. Если вам необходимо изменить уже существующие данные страницы или дополнить ее новой информацией, то воспользуйтесь возможностью технологии Dynamic HTML, поддерживаемой в >¥ЗС-совместимых браузерах. На первый взгляд задача не так уж и сложна: достаточно добавить новый узел, удалить старый или просто заменить часть уже существующей иерархической структуры документа. Большинство элементов объектов обладают соответствующими методами (детально они рассмотрены в главе 14). Если вам необходимо лишь добавить в документ новые данные, то достаточно создать элемент или текстовый узел. Объект document имеет для этого два специальных метода. Метод document. createElement () позволяет создать в памяти совершенно новый объект. Чтобы в точности указать тип создаваемого элемента, подставьте имя дескриптора этого элемента в строковый параметр метода. var newElem = document.createElement("р") В процессе создания элемента можно добавить к нему специальные характеристики (назначить ему свойства), сделав это еще до включения элемента в конечный документ. Как отмечалось в главе 4, многие объекты элементов в иерархической структуре имеют текстовое содержимое, заключенное между открывающими и закрывающими дескрипторами. В W3C DOM текстовое содержимое добавляется в результате создания нового текстового узла с помощью метода document. createTextNode (). var newText = document. createTextNode ("Всем привет !*') Операция создания элементов и текстовых узлов сама по себе не приводит к изменению иерархической структуры документа. Чтобы вставить новые объекты в документ, вам необходимо воспользоваться дополнительными методами (глава 14). Детально с ней вы ознакомитесь в последней главе этой части (глава 12). Метод document.getElementByld() В многих программных кодах, которые вам придется изучать, вы встретите метод document .getElementByld (). С его синтаксисом вы ознакомились в главе 14 при изучении способов обращения к объектам документа. Пусть вас не смущает столь длинное и за- Глава 8. Объекты документа и окна 129
пуганное имя. Наличие в нем большого количества символов смешанного регистра делает имя легким для запоминания и распознания в коде. Единственный параметр этого метода представляет собой текстовую строку, заключенную в кавычки. В этой текстовой строке указывается идентификатор элемента, на который в коде создается ссылка. Сам же метод возвращает значение, которое обычно подставляется в переменную, используемую в операторах сценария. var oneTable = document.getElementByldC'salesResults") После назначения переменной подобного значения она представляет в программном коде объект элемента. В дальнейшем с ее помощью можно назначить объекту все необходимые свойства и выполнить его методы. В следующей главе мы рассмотрим объекты более высокого иерархического уровня — формы. Упражнения 1. Какие из приведенных ниже ссылок являются корректными, а какие нет? Объясните, почему некоторые из них неверны. а) window.document.form[0] б) self.entryForm.submit() в) document.forms[2].name r) document.getElementByld("firstParagraph") д) newWindow.document.write("Howdy") 2. Напишите оператор JavaScript, который отображает сообщение в строке состояния, приветствующее новых посетителей Web-страницы. 3. Напишите оператор JavaScript, который отображает упомянутое выше сообщение, но уже на уровне заголовка <hl> страницы. 4. Создайте страницу, которая предлагает (в диалоговом окне) пользователю ввести его или ее имя, а после этого будет приветствовать его (ее) по имени. Приветствие должно отображаться в основной части страницы. 5. Создайте страницу, содержащую произвольный текст (какой хотите). Сразу после загрузки она должна автоматически выводить диалоговое окно с адресом URL текущей страницы. 130 Часть II. Руководство по JavaScript
Формы и их элементы ольшая часть интерактивных взаимодействий между Web-страницей и пользователем происходит внутри формы. Это именно то место, где спрятана большая часть интерактивных возможностей любого браузера: текстовые поля, кнопки, флажки опций, переключатели, списки и т.д. Как уже отмечалось в предыдущих главах, для доступа к определенным объектам часто используется метод document. getElementByld (). Не являются исключением объекты формы и элементов управления форм. Именно о последних мы и поговорим в настоящей главе. Наше внимание будет сосредоточено на старом варианте синтаксиса (полностью совместимого с большим количеством используемых браузеров) — его еще часто называют синтаксисом DOM нулевого уровня. Объект form В базовом синтаксисе модели DOM нулевого уровня ссылка на объект формы form задается либо по его расположению в массиве форм, содержащихся в документе, либо же по имени (если атрибуту name внутри дескриптора <f orm> присвоено значение). Если в документе используется только одна форма, то она все равно является элементом массива (который состоит из одного элемента), и ссылка на нее будет выглядеть следующим образом. document. forms [0] Вы также можете обратиться к элементу по имени, использовав его в качестве индекса массива. document.forms[имяФормы] Обратите внимание на то, что в записи ссылки на объект в имени элемента массива используется множественная форма (т.е. forms а не form); после имени вводятся квадратные скобки с указанием в них числового индекса элемента (первый элемент всегда имеет индекс нуль). Но если форме было присвоено имя, то ссылку можно записать значительно проще. document.имяФормы
Форма как объект и контейнер В отличие от современной модели DOM, в которой доступ к любому элементу документа можно получить по идентификатору, в DOM нулевого уровня используется иерархический подход. Форма, с одной стороны, сама содержится в документе, а с другой — может содержать любое число элементов (называемых элементами управления формы). На рис. 9.1 показана иерархическая структура элементов формы и ее место в объектной модели документа. Все эти интерактивные элементы используются для того, чтобы пользователь мог ввести информацию или выбрать опцию непосредственно в объекте form. Подобный подход отображает организационную структуру дескрипторов HTML, в которой элементы размещаются внутри пары дескрипторов <f orm> и </f orm>. В дополнение к большому количеству свойств и методов, свойственных любым HTML- элементам, объект form обладает уникальными характеристиками, присущими только ему одному. Практически все уникальные свойства объектов можно задать в сценариях с помощью атрибутов элемента form. Браузеры поддерживают управление свойствами формы на программном уровне, что позволяет разработчикам на более низком уровне настроить вид и поведение любых ее элементов. Рис. 9.1. Иерархическая структура объектов формы и ее элементов управления в DOM нулевого уровня Доступ к свойствам формы Формы на странице полностью создаются с помощью стандартных дескрипторов HTML. В них можно задать такие важные атрибуты, как name, target, action,, method и enctype. Каждый из них является свойством объекта form, доступ к которому можно 132 Часть II. Руководство по JavaScript
получить, воспользовавшись соответствующим ключевым словом, вводимым только строчными литерами (см. ниже). document.forms[0].action document.имяФормы.action Для изменения любого из этих свойств ему нужно просто присвоить новое значение. document.forms[0].action = "http://www.giantco.com/cgi/login.pl"; Свойство form.elements[] Кроме отслеживания поведения различных элементов в пределах формы, браузер также поддерживает список всех элементов управления формы. Этот список является еще одним массивом, в котором элементы располагаются в том порядке, в каком приведены их HTML- дескрипторы в исходном коде. Однако более эффективно использовать ссылки на эти элементы по именам. С другой стороны, иногда сценарий просматривает сразу все элементы формы. Это справедливо, если форма изменяется при последующей загрузке, особенно когда число текстовых полей зависит от типа используемого браузера. Например, сценарий может использовать метод document .write () для добавления на страницу дополнительного текстового поля с информацией, применяемой только пользователями системы Windows. Приведенный ниже фрагмент кода демонстрирует принцип использования свойства form.elements [] в цикле повторения for, который просматривает каждый элемент формы и очищает содержимое всех текстовых полей. Сценарий не может просто "пройтись" по форме сверху вниз и задать ее содержимое или значение каждого элемента равным пустой строке (среди элементов формы могут встречаться, например, кнопки, не имеющие свойства value, которое нужно приравнять к пустой строке). var form = window.document.forms[0] for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].type == "text") { form.elements[i].value = ""; } } В первом операторе создается переменная с именем form— она содержит ссылку на первую форму документа. Форма сохраняется в переменной на тот случай, если в дальнейшем придется делать ссылки на элементы формы. Ссылки по имени намного компактнее (и выполняются быстрее). Теперь имя переменной form можно использовать для задания ссылок на элементы, содержащиеся на форме. Далее выполнятся просмотр элементов массива elements данной формы. Каждый элемент формы имеет свойство type, которое и определяет тип объекта текущего элемента: текст, кнопка, переключатель, флажок и т.д. В данном случае нам нужно отобрать элементы текстового поля text. Для каждого из таких элементов значение свойства value устанавливается равным пустой строке. К формам мы вернемся в этой главе несколько позже. Там будет показано, как создаются сценарии, не использующие кнопку Submit (Отправить), но все же отправляющие данные на сервер. Вы также узнаете, как происходит проверка данных формы, введенных пользователем. Элементы формы - это тоже объекты В объектных моделях документа всех браузеров представлено три типа элементов HTML, используемых в дескрипторах формы <form>, которыми управляют в сценарии объекты. Большинство объектов обязаны своим существованием дескрипторам < input > исходного Глава 9. Формы и их элементы 133
кода страницы. Единственное значение, присвоенное атрибуту type дескриптора < input >, определяет, чем является элемент: текстовым полем, полем введения пароля, скрытым полем, кнопкой, флажком или переключателем. К другим элементам управления формы относятся text area nselect, но они имеют собственные дескрипторы, задающие их в коде. Чтобы обратиться к определенному элементу управления формы с помощью синтаксиса DOM нулевого уровня, необходимо создать ссылку, начинающуюся с document (она содержит имя формы и название конечного элемента управления). Ранее было приведено несколько способов получения доступа к элементам формы, каждый из которых требует использования ссылки строго определенной структуры. В случае применения только имен формы и элементов управления ссылка будет выглядеть следующим образом. document. имяФормы. имяЭлементаУправления Для начала рассмотрим следующий фрагмент кода. <form name="searchForm" action="cgi-bin/search.pi"> <input type="text" name="entry"> <input type="submit" name="sender" valuer"Search"> </form> Следующие ссылки позволяют получить доступ к текстовому полю описанной выше формы. document.searchForm.entry document.searchForm.elements[0] document.forms["searchForm"].elements["entry"] document.forms["searchForm"].entry Как мы уже определили, элементы управления имеют несколько свойств общего характера (стандартные свойства); некоторые свойства вводятся для определения специфических характеристик объектов элементов. Например, только объект select имеет свойство, указывающее, какой элемент в списке выбран в текущий момент. Флажки и переключатели имеют свойство, которое определяет, включена или выключена соответствующая опция. Точно так же, все текстовые поля используют одинаковые методы для чтения и изменения их содержимого. Понимание принципов управления свойствами объектов элементов управления формы — это важный этап в изучении JavaScript. В следующем разделе описаны наиболее важные объекты управления формы и приведены способы их взаимодействия в сценариях. Текстовые объекты Каждый из четырех текстовых HTML элементов формы — текстовое поле, поле пароля, скрытое поле и текстовая область — это объект в иерархической структуре модели документа. Все эти элементы, кроме скрытого поля, отображаются на странице, что позволяет пользователю ввести в них необходимые данные. Эти объекты также отображают текстовую информацию, которая может изменяться по мере загрузки и использования страницы (Dynamic HTML в современных браузерах также предоставляет возможность с помощью сценариев изменять основной текст документа). Поведение текстовых объектов Многие создатели сценариев обращаются за помощью к JavaScript в надежде решить проблему некоторых дефектов или аномалий в поведении текстовых объектов формы. Только браузеры самых последних версий предоставляют сценариям полную возможность настройки шрифтов, их размеров, стилей и типа выравнивания текста в текстовых объектах. Изменения можно выполнять с помощью стилей соответствующих элементов (глава 26). В большинстве браузеров попытка контроля за поведением форм была реализована много лет назад неформально. Если форма содержит только один объект input, использование 134 Часть II. Руководство по JavaScript
клавиши <Enter> при активном текстовом объекте приводит к автоматической отправке данных формы. При наличии двух или более полей в браузерах, отличных от Мас1Е5 и Safari, для отправки данных необходимо использовать несколько другой способ. Например, задействовать кнопку Submit (Отправить). Метод предоставления данных формы при наличии только одного текстового поля во многих случаях себя оправдывает, например, на страницах большинства поисковых систем в Web. Если вы экспериментируете только с простейшими формами, содержащими единственное поле, то данные формы можно легко отправить с помощью клавиши <Enter>. Создание формы, которая не выполняет никаких действий и не имеет конкретного назначения, приведет к тому, что страница выполнит безусловную перезагрузку — удалит все данные, введенные на форме. Тем не менее, отправку данных формы можно отменить; для этого следует воспользоваться обработчиком события формы onSubmit, как это будет продемонстрировано позже в этой главе. Кроме того, начиная с четвертой версии браузеров, можно для каждого текстового поля задать реакцию на нажатие клавиши <Enter> и обеспечить отправку данных формы без специальной кнопки (глава 25). Чтобы объектами полей можно было управлять непосредственно из сценария, специальных действий с их HTML-дескрипторами выполнять не придется — за исключением, может быть, присвоения значения атрибуту name. Рекомендуем присваивать всем элементам управления формы необычные имена. Это удобно в том случае, если в сценарии устанавливаются свойства или вызываются методы этих элементов. Кроме того, если форма предоставляется программе сервера, которой фактически управляют данные элементов, атрибуту name просто необходимо присвоить значение. При управлении объектами этого типа обработчики событий должны реагировать на многочисленные действия пользователей — активизацию поля (в поле появляется курсор ввода текста) и изменение текста (введение нового значения и выход из поля). Большинство действий над текстовыми полями так или иначе связаны с изменением текста (обработчик события onchange). Если вы используете браузеры современных версий, то в них представлены обработчики событий, позволяющие программировать реакцию на нажатие каждой отдельной клавиши или щелчок на кнопке. Вне всяких сомнений, наиболее часто используемым свойством текстовых элементов является value. Это свойство представляет собой текущее значение текстового элемента. Сценарий может в любой момент вызвать это свойство и установить для него новое значение. Содержимое свойства value — это всегда строка. Может так произойти, что эту строку придется преобразовывать в числовой формат (глава 6), если, например, текстовое поле используется для введения числовых значений или выполнения математических операций. Для того чтобы продемонстрировать способы чтения и записи свойства value текстового поля, в листинге 9.1 приведено описание HTML-страницы с единственным полем введения данных. Обработчик события onchange в данном примере вызывает функцию upperMe (), которая преобразует текст в верхний регистр (все буквы прописные). В функции upperMe () первый оператор присваивает переменной field ссылку на текстовый объект, что выполняется исключительно с целью обеспечения удобства при обращении к объекту поля. Многое скрыто и во втором операторе этой функции. То, что находится в правой части оператора присвоения, направлено на выполнение ряда ключевых задач. Ссылка на свойство value объекта (field, value) позволяет узнать, что именно в данный момент введено в текстовое поле. Затем эта строка передается одной из функций JavaScript, управляющих строковыми данными. В данном случае это функция toUpperCase (). Она преобразует символы текста в верхний регистр. Вычисленный результат выражения, указанного справа от оператора присвоения, присваивается затем второй переменной upperCaseVersion. При этом в текстовом поле не происходит никаких изменений. Изменения начинаются с третьего оператора, в котором свойству value текстового поля присваивается значение, содержащееся в переменной upperCaseVersion. Необходимости во втором операторе нет, и используется он, Глава ft Формы и их элементы 135
скорее, в целях большей наглядности, поскольку в этом случае весь описанный процесс отчетливо разбивается на отдельные этапы. На практике можно объединить второй и третий операторы в один. Выполнить это можно следующим образом. field.value - field.value.toUpperCase() <html> <head> <title>Text Object value Property</title> <script type="text/javascript"> function upperMeO { var field = document.forms[0].converter; var upperCaseVersion = field.value.toUpperCase(); field.value = upperCaseVersion; } </script> </head> <body> <form onsubmit="return false"> .<input type="text" name="converter" value="sample" onchange="upperMe()"> </form> </body> </html> Позже в этой главе будет показано, как можно еще больше упростить в приведенном выше листинге 9.1 обращение к таким функциям, как upperMe (). Тем временем, имеет смысл подробнее остановиться на обработчике события onsubmit в дескрипторе формы <f orm>. Далее мы неоднократно будем останавливаться на описании этого обработчика событий. В настоящий момент следует обратить ваше внимание на ту конструкцию, которая используется для предотвращения отправки формы с единственным полем в результате нажатия клавиши <Enter>. Объект кнопки В этом руководстве элемент кнопки input уже применялся неоднократно. Кнопка, с точки зрения использования в сценарии, является одним из наиболее простых объектов. В упрощенной модели, описанной в данной книге, объект кнопки имеет ограниченное количество свойств, которые редко используются или изменяются в сценариях "повседневного назначения". Подобно текстовому объекту, за визуальное отображение кнопки отвечает не HTML или сценарии, а операционная система, а также браузер, используемый пользователем при посещении страницы. Безусловно, самым полезным обработчиком событий для кнопки является onclick. Соответствующее событие наступает при щелчке пользователя на кнопке. Все просто. Никаких подвохов. Объект флажка Флажок опции — это достаточно простой объект элемента формы form, однако некоторые его свойства не всегда правильно трактуются начинающими разработчиками. В отличие от свойства value объекта обычнойГ кнопки (для кнопки это свойство определяет текстовую 136 Часть II. Руководство по JavaScript
надпись), в качестве свойства value элемента управления выступает любой текст, описывающий задаваемую опцию. Этот текст не отображается на странице ни в каком виде, однако свойство (первоначально устанавливаемое в атрибуте дескриптора value) имеет важное значение в сценарии, которому необходимо больше "знать" о назначении этого элемента формы. Ключевое свойство элемента управления флажка определяет, выбран он или нет. Соответствующее свойство checked принимает булево значение: true (истина), если элемент выбран, и false (ложь) — если нет. Как только в сценарии появляется булево свойство, сразу же приходит мысль использовать его в конструкциях типа if или if. . .else. В листинге 9.2 с помощью значения свойства checked определяется, какое диалоговое окно будет выведено пользователю. /Ысшг9.2.С^йстмсЬ.ск^<Иажифор«ы t\^'*?%% '^ *,£•':* <html> <head> <title>Checkbox Inspectors/title> <script type="text/javascript"> function inspectBoxO { if (document.forms[0].checkThis.checked) { alert("The box is checked."); } else { alert("The box is not checked at the moment."); } } </script> </head> <body> <form> <input type="checkbox" name="checkThis">Check here<br> <input type="button" value="Inspect Box" onclick="inspectBox()"> </form> </body> </html> Флажки чаще используются для проведения настроек, а не в качестве переключателя действий. Поскольку флажок оснащен обработчиком события onclick, следует помнить, что последний редко применяется для выполнения радикальных операций (например, перехода к другой странице). Объект переключателя Использование в сценарии группы переключателей потребует от вас внимательности. Чтобы браузер мог выставлять и снимать переключатели в группе, всем переключателям этой группы необходимо присвоить одинаковые имена. На форме можно использовать несколько групп переключателей, но в рамках каждой группы ее элементы должны иметь одно и то же имя. Присвоение элементам формы одинаковых имен приводит к тому, что браузер управляет ими иначе, чем остальными элементами управления с разными именами. В этом случае браузер использует для организации элементов с одинаковыми именами массивы. Название, присвоенное группе элементов, становится именем массива. Некоторые свойства применимы при этом к группе как к целому. Другие свойства применимы только к отдельным переключателем груп- Глава 9. Формы и их элементы 137
пы, и на них нужно ссылаться с помощью индекса элемента массива. Например, узнать, сколько переключателей находится в группе можно, используя значение свойства length всей группы. document.forms[0].имяГруппы.length Если необходимо определить, выставлен ли в данный момент какой-либо переключатель (для этого предназначено такое^ же, как и для флажка, свойство checked), нужно получить доступ к конкретному элементу. document.forms[0] .имяГруппы[0] .checked В листинге 9.3 проиллюстрированы некоторые аспекты управления переключателями, втомяисле способы поиска в группе переключателей выставленного в данный момент элемента. Также вы увидите, как используется атрибут value и соответствующее свойство для решения поставленных целей. Страница содержит три переключателя и одну обычную кнопку. Атрибут value каждого переключателя состоит из полного имени. Когда пользователь щелкает на кнопке, обработчик события onclick вызывает функцию fullName О. В этой функции первый оператор создает ссылку на форму. Дальше с помощью цикла for выполняется просмотр всех переключателей группы stooges. Конструкция if используется для проверки свойства checked переключателей. Если переключатель выставлен, то оператор break даст инструкцию выйти из цикла for. При этом значение переменной-счетчика цикла i будет равно тому значению, при котором работа цикла прекращена. В диалоговом окне предупреждения используется свойство value элемента с номером, соответствующим последнему значению переменной i, поэтому в диалоговом окне будет отображено полное имя этого элемента. <html> <head> <title>Extracting Highlighted Radio Button</title> <script type="text/javascript"> function fullName() { var form = document.forms[0]; for (var i = 0; i < form.stooges.length; i++) { if (form.stooges[i].checked) { break; } } alert("You chose " + form.stooges[i] .value + "."); } </script> </head> <body> <form> <p>Select your favorite Stooge: <input type="radio" name="stooges" value="Moe Howard" checked>Moe <input type="radio" name="stooges" value="Larry Fine">Larry <input type="radio" name="stooges" value="Curly Howard">Curly<br> <input type="button" name="Viewer" value="View Full Name..." onclick="fullName()"></p> </form> </body> </html> 138 Часть II. Руководство по JavaScript
Объект элемента select Наиболее трудный элемент формы, с точки зрения использования в сценариях, — это объект элемента select. Как легко видеть на иерархической структуре объектов (рис. 9.1) bDOM W3C, объект select является объектом весьма общего характера: он содержит массив объектов option. Более того, в HTML его можно использовать для отображения выпадающего меню или прокручиваемого списка— последний применяется для предоставления пользователю возможности множественного выбора. Чтобы упростить задачу, на данном этапе будем рассматривать применение его в качестве выпадающего меню, позволяющего сделать выбор только одной опции. Некоторые свойства относятся непосредственно ко всему объекту select, в то время как другие применимы только к отдельным его элементам. Если нужно определить, какую опцию выбрал пользователь, то используйте свойства как объекта select, так и option. Самое важное свойство всего объекта select — это selectedlndex, доступ к которому задается следующим образом. document.form[0].имяСписка.selectedlndex Его значение — это индекс выбранного в текущий момент элемента меню или списка. Как это имеет место в большинстве систем нумерации в JavaScript, первый элемент (в списке начиная сверху) имеет нулевой индекс. Значение selectedlndex является исключительно важным параметром для получения доступа к свойствам выбранной опции. В каждой опции чаще всего используются свойства text и value, которые вызываются следующим образом. document.form[0].имяСписка.options[n].text document.form[0].имяСписка.options[n].value Свойство text представляет собой строку, которая отображается в объекте select. Свойство text представлено необычным для объекта формы form образом, поскольку в HTML, генерирующем объект select, соответствующий текст определяется вне дескриптора <option>. Внутри дескриптора <option> можно установить только атрибут value, который, подобно переключателям, рассматривавшимся ранее, позволяет связывать его значение в виде скрываемой строки с каждым элементом списка. Для того чтобы получить значение text или value для выбранной опции, можно использовать свойство selectedlndex объекта select в качестве значения индекса опции. Ссылки в таких случаях достаточно длинные. Поэтому, чтобы понять, как они выполняются, придется немного попрактиковаться. В приведенной ниже функции первый оператор необходим для создания ссылки на объект select. Свойство selectedlndex объекта select заменяет затем значение index массива option того же самого объекта. function inspect!) { var list = document.forms[0]choices; var chosenltemText = list.options[list.selectedlndex].text; } Чтобы "вдохнуть жизнь" в объект select, нужно воспользоваться обработчиком события onchange. Как только пользователь выберет новый элемент в списке, сценарий запустит обработчик события, связанный с ним. В листинге 9.4 приведен пример использования объекта select. Записи элементов списка указывают адреса, по которым проводится перемещение внутри и вне текущего Web-узла. В атрибуте value заданы адреса URL конечных Web- страниц. Когда пользователь выбирает из предложенного списка элемент, обработчик события onchange запускает сценарий, который извлекает свойство value выбранной опции и присваивает его значение объекту location (этот объект обеспечивает переход). Под управлением JavaScript переходы такого типа могут выполняться без использования на странице специальной кнопки Go (Перейти). Глава ft Формы и их элементы 139
ЛШ^^ select <html> <head> <title>Select Navigation</title> <script type="text/javascript"> function goThereO { var list = document.forms[0].urlList; location.href = list.options[list.selectedlndex].value; } </script> </head> <body> <form> Choose a place to go: <select name="urlList" onchange="goThere0"> <option selected value="index.html">Home Page <option value="store.html">Shop Our Store <option value="policies.html">Shipping Policies <option value="http://www.google.com">Search the Web </select> </form> </body> </html> I В последних версиях браузеров свойство value выбранной пользователем опции /назимтжу трактуется как свойство value объекта select. Это вполне логичный и удобный * ***"' прием, который можно смело применять в современных браузерах IE, Mozilla и Safari. Об объекте select можно говорить довольно долго. В новых браузерах даже предусмотрена возможность изменения содержимого списков (см. главу 24). Передача функциям данных форм и элементов Во всех приведенных в этой главе примерах соблюдено следующее правило: когда обработчик события вызывает функцию, которая управляет элементами формы, эти формы или их элементы указываются в функции в явном виде. Однако существуют вполне приемлемые способы передачи информации такого рода от форм или ее элементов управления непосредственно в функции — эти методы основаны на системе сокращений. В таком случае нет необходимости использовать длинные и неудобные ссылки, начинающиеся с уровня объектов окна window или документа document. В JavaScript представлено ключевое слово this. Оно может использоваться для ссылки на любой объект, содержащий сценарий с этим словом. Так, в обработчике события onchange для текстового поля при передаче в функцию ссылки на текстовый объект достаточно вставить ключевое слово this в качестве параметра этой функции. <input type="text" name="entryM onchange="upperMe(this)"> 140 Часть II. Руководство по JavaScript
В результате функция определит параметрическую переменную, которая будет возвращать указанную ссылку в качестве значения для переменной (такую переменную в дальнейшем можно будет использовать в функции) function upperMe(field) { оператор (ы) } Название, которое присваивается переменной-параметру функции, является абсолютно произвольным. Однако часто полезно использовать такие имена, которые бы отображали смысл соответствующей ссылки. Важно, чтобы данная ссылка представляла "живую" связь с объектом. Поэтому с помощью соответствующих операторов в сценарии можно получать и устанавливать значения свойств объекта. Для других функций может возникнуть потребность получить ссылку на всю форму в целом, а не просто на объект, вызывающий функцию. Это особенно актуально, когда функция должна иметь доступ к другим элементам той же формы. Для обращения ко всей форме следует сослаться на свойство form объекта input, при этом используется ключевое слово this. <input type="button" value="Click Here" onclick^"inspect(this.form)"> В определении функции должна присутствовать переменная-параметр, которую используют для присвоения ей ссылки на объект. Опять же, имя можно выбирать по своему усмотрению. В данном случае предлагается использовать в качестве имени form, тогда легче запомнить, на что указывает соответствующая ссылка. function inspect(form) { опера тор (ы) } В листинге 9.5 продемонстрирован способ обращения как к отдельному элементу формы, так и к форме в целом (этот способ состоит из двух действий). Предполагается, что страница имеет непосредственный доступ к базе данных песен группы Beatles. По щелчку на кнопке Process Data (Передать данные) происходит передача объекта form, который в цикле for вызывается функцией processData () для получения доступа к группе переключателей. Дополнительная ссылка с использованием передаваемого объекта form вызывает свойство value выбранных переключателя и текстового поля. Текстовое поле имеет свой собственный обработчик события, который передает текстовое поле в функцию verifySongO. Обратите внимание на то, насколько компактна внутри функции ссылка на свойство value поля, содержащего название песни. <html> <head> <title>Beatle Picker</title> <script type="text/javascript"> function processData(form) { for (var i = 0; i < form.Beatles.length; i++) { if (form.Beatles[i].checked) { break } } var beatle = form.Beatles[i].value var song = form.song.value alert("Checking whether " + song + " features " + beatle + "...") } Глава 9. Формы и их элементы 141
function verifySong(entry) { var song = entry.value alert("Checking whether " + song + " is a Beatles tune...") } </script> </head> <body> <form onsubmit="return false"> <p>Choose your favorite Beatle: <input type="radio" narae="Beatles" value="John Lennon" checked>John <input type="radio" name="Beatles" value="Paul McCartney">Paul <input type="radio" name="Beatles" value="George Harrison">George <input type="radio" name="Beatles" value="Ringo Starr">Ringo</p> <p>Enter the name of your favorite Beatles song:<br> <input type="text" name="song" value = "Eleanor Rigby" onchange="verifySong(this)"> <input type="button" name="process" value="Process Request..." onclick="processData(this.form)"</p> </form> </body> </html> Теперь вы знаете, как с использованием ключевого слова this передать функциям объекты формы form и ее элементов. Такая методика позволяет не только сократить объем кода, но и повышает надежность выполнения ссылок на нужные объекты. Отправка данных форм и проверка их правильности В сценарии процесс отправки формы реализуется с помощью метода submit (). Все, что нужно сделать, — это указать ссылку на форму и данный метод. document.forms[0].submit(); По идее, с помощью данного метода можно так организовать страницу, чтобы при посещении новым пользователем вашего Web-узла сценарий отправлял почтовое сообщение владельцу узла. Однако не все так просто. Дело в том, что указанный метод требует использования протокола mailto:, который позволяет извлекать почтовый адрес посетителя. Из соображений безопасности в современных браузерах он блокирован для использования. Перед тем, как форма будет отправлена, полезно выполнить предварительную проверку правильности введенных в нее данных или программных кодов (например, можно изменить в зависимости от предпочтений пользователя свойство формы action). Для этого воспользуйтесь функцией, которая вызывается обработчиком события формы onsubmit. Сам код программы проверки правильности содержащихся в форме данных в данной главе описываться не будет (однако этот вопрос детально рассмотрен в главе 43). Тем не менее, узнать, как работает обработчик события onsubmit, весьма полезно даже на данном этапе изучения JavaScript. В большинстве браузеров существует возможность применения функции проверки правильности данных, которая позволяет отменить отправку формы в тех случаях, когда данные содержат ошибку или часть из них отсутствует. При таком управлении отправкой данных формы обработчик события onsubmit должен вернуть значение true, иначе процесс будет считаться незавершенным. Если возвращается значение false, то отправка формы отменяется. 142 Часть II. Руководство по JavaScript
Все это вначале будет вызывать затруднения, поскольку в каждом конкретном случае требуется больше, чем просто с помощью обработчика события вызвать функцию, которая возвращает значение true или false. Возвращается значение с помощью ключевого слова return. В листинге 9.6 приведен пример программы проверки корректности данных, которая перед тем, как разрешить отправку формы, просматривает все поля и проверяет наличие в них информации. Форма в этом примере вообще не имеет атрибута action, поэтому она в любом случае на сервер отправляться не будет. Обратите особое внимание на то, как в обработчике события onsubmit (который в данном случае задает ссылку на объект form в виде параметра— ключевое" слово this указывает на объект form, поскольку его дескрипторы содержат обработчик события) перед именем функции используется ключевое слово return. Если функция возвращает в качестве своего результата значение true или false, обработчик события преобразует это в return true или return false, соответственно. <html> <head> <title>Validator</title> <script type="text/javascript"> function checkForm(form) { for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].value == "") { alert("Fill out ALL fields."); return false; return true; } </script> </head> <body> <form onsubmit="return checkForm(this)"> Please enter all requested information:<br> First Name :< input type="textn name="f irstName"xbr> Last Name:<input type=Mtext" name="lastName"><br> Rank:<input type="text" name= "rank"><br> Serial Number :<input type="text" name="serialNumber"xbr> <input type="submit "> </form> </body> </html> Еще одна особенность поведения обработчика события onsubmit (казалось бы, вызывающего метод submit ()) требует дополнительных пояснений. У вас могло сложиться впечатление (и с логической точки зрения оно было бы вполне обосновано), что метод submit () должен вызываться в сценарии после того, как пользователь щелкнет на кнопке Submit. Однако это не так. В NN использование метода submit () вообще не связано с обработчиком события onsubmit. Если нужно выполнить проверку корректности данных предоставляемой формы посредством метода submit (), то следует вызвать функцию проверки формы, которая непосредственно вызовет метод submit (). Это все, что на данном этапе мне хотелось рассказать о формах и их элементах. В следующей главе мы сделаем упор на некоторых завершенных средствах базового языка JavaScript (речь пойдет о строках, математических выражениях и датах). Глава 9. Формы и их элементы 143
Упражнения 1. Переделайте листинги 9.1-9.4 так, чтобы все функции сценария использовали наиболее удобную форму ссылок на формы и их элементы в задействованных обработчиках событий. 2. Укажите для следующей формы (предположительно единственной на странице) по меньшей мере 10 способов ссылки на текстовое поле. <form name="subscription" action="cgi-bin/maillist.pi" method="post"> <input type="text" id="email" name="email"> <input type="submit"> </form> 4. Какого рода информация в приведенном ниже HTML-дескрипторе, по вашему мнению, будет передана обработчиком события? Напишите функцию, отображающую в диалоговом окне предупреждение с предназначенной для передачи информацией. <input type="text" name="phone" onchange="format(this.value)"> 5. Документ содержит две формы с именами specifications и accessories. Форма accessories включает поле с именем accl. Напишите две отдельные команды, которые устанавливали бы содержимое этого поля равным Leather Carrying Case. 6. Создайте страницу, в которой представлен объект select, используемый для изменения фона текущей страницы. Свойством, отвечающим за изменение цвета фона, является document .bgColor. Следует предложить использовать на выбор один из трех цветов: red (красный), yellow (желтый) и green (зеленый). В объекте select цвета должны отображаться как Stop (Стоять), Caution (Приготовиться) и Go (Идти), соответственно. 144 Часть II. Руководство по JavaScript
Строки, математические выражения и даты о этого момента большинство из рассмотренных в книге объектов имели непосредственное отношение к объектной модели документа. Однако, как это подчеркивалось еще в главе 2, между объектной моделью документа и языком JavaScript существует различие. В языке используются собственные объекты, которые полностью независимы от объектов модели документа. Эти объекты определяются таким образом: если разработчику сценария необходимо использовать JavaScript в качестве языка программирования для полноценного решения другой задачи, то в этом языке для управления текстом, проведения сложных математических вычислений (выходящей за пределы элементарных математических операций) и задания дат можно использовать основные программные средства. Формальное описание соответствующих объектов приведено в инструкциях стандарта ЕСМА-262. Объекты базового языка Зачастую не только новичкам, но и вполне опытным пользователям, которым не приходилось сталкиваться ранее с объектно-ориентированным программированием, крайне сложно привыкнуть к отдельным объектам. Например, довольно просто осознать, что кнопка на странице является объектом. Она имеет несколько свойств, которые поддаются логическому восприятию. А вот как быть со строкой или символом? В любой объектно-ориентированной среде (в том числе в JavaScript) все, что может изменяться, трактуется как объект, — каждый фрагмент данных, начиная с логических значений и заканчивая датами. Такой объект, вероятнее всего, имеет одно или более свойств, которые призваны помочь в определении его содержимого. Каждый объект также имеет методы, определяющие задачи, которые этот объект может выполнять. д
Все объекты, не относящиеся к объектной модели документа, называются объектами базового языка. Полный их перечень можно найти в приложении А. В этой главе основное внимание уделено объектам типа String, Math и Date. Строковые объекты В предыдущих главах строковые объекты String использовались неоднократно. Строкой считается любой текст, заключенный в кавычки. Кавычки могут быть двойными или одинарными. Это позволяет вставить одну строку в другую (что приходится часто выполнять при управлении обработчиками событий). В приведенном ниже примере методу alert () в качестве параметра нужно задать заключенную в кавычки строку. Но при этом сам вызов метода также осуществляется с использованием кавычек. onclick="alert('Hello, all')" В JavaScript нет практических ограничений на количество символов в строке. Тем не менее, в старых версиях браузеров существует максимально допустимое значение длины строки оператора сценария, равное 255 символам. Этот предел может превышаться, когда сценарий включает в себя длинные строки, требующие отображения на странице. В таких случаях эти строки следует разбить на более короткие (см. приемы, описанные ниже). Существует два способа присвоения значения строчной переменной. Наиболее просто эта задача решается с помощью оператора обычного присвоения. var myString = "Howdy"; Этот подход превосходно срабатывает во всех, за редким исключением, случаях. Начиная с NN3 и IE4, строки можно создавать с использованием более формального синтаксиса на основе ключевого слова new и конструктора функции (конструктор создает новый объект). var myString = new String("Howdy"); Какой бы способ из описанных выше ни использовался для инициализации строковой переменной, она становится доступной для всех методов объекта String. Объединение строк Соединение двух строк в одну называется объединением (или конкатенацией) строк. Этот термин уже встречался в главе 6. Для объединения строк нужно воспользоваться одним из двух предусмотренных для этого случая JavaScript-операторов. Уже в первом сценарии главы 3 было продемонстрировано, как оператор сложения (+) использовался для объединения нескольких строк с целью создания на загружаемой Web-странице динамически отображаемого текстового сообщения. document.write(" of <span class='highlight'>" + navigator.appName + "</span>."); Для этой цели используют еще один оператор. В основном, к нему обращаются в том случае, когда в одной строке нужно объединить несколько длинных строк. Строка может быть настолько большой и громоздкой, что весь процесс придется разбить на несколько этапов. Объединяемыми фрагментами могут выступать строковый текст (строка в кавычках) или строковые переменные. Не самым эффективным' в таком случае способом объединения строк (хотя и легко выполняемым в JavaScript) является использование оператора сложения для добавления к строке новых фрагментов текста. var msg = "Four score" msg = msg + " and seven" msg = msg + " years ago," 146 Часть II. Руководство по JavaScript
Другой оператор, оператор дополнения, предлагает более компактную форму записи. Символ этого оператора — это знак "плюс" и знак равенства, не разделенные пробелом (+=). Использование этого оператора эквивалентно добавлению в конец переменной, стоящей слева от оператора, того выражения, которое находится справа от оператора. Поэтому команды из приведенного выше примера будут упрощены. var msg = "Four score"; , msg += " and seven"; msg += " years ago,"; При необходимости можно поступить еще проще. var msg = "Four score"; msg += " and seven" + " years ago"; Оператор приращения удобно использовать, когда для его отображения в текущем документе или другом окне нужно собрать вместе фрагменты текста HTML. Методы строковых объектов Из всех основных объектов JavaScript объект String имеет наиболее богатый набор методов. Многие из этих методов используются для извлечения фрагментов строк. Другая группа методов, которая применяется значительно реже, задается с помощью стилевых дескрипторов (эквивалент дескрипторов, определяющих размер шрифта, стиль и др. параметры, в сценарии). При использовании одного из методов строкового объекта строка задается с помощью ссылки, в конце которой указывается имя метода. Все методы возвращают значения определенного типа. В большинстве случаев возвращаемое значение — это преобразованная версия исходного строкового объекта, на который ссылается вызываемый метод (исходные строки при этом остаются неизменными). Чтобы сохранить такую измененную версию строки, результат вызова метода присвойте в качестве значения переменной. var result = string.имяМетода(); В следующем разделе описано несколько полезных методов строковых объектов, которые доступны в браузерах всех типов и версий. Изменение регистра Существует два метода, которые преобразуют всю строку в символы верхнего или нижнего регистра (т.е. все буквы становятся либо строчными, либо прописными соответственно). var result = string.toUpperCase(); var result = string.toLowerCase(); Названия этих методов говорят сами за себя (to upper case — в верхний регистр и to lower case — в нижний регистр). Указанные методы могут пригодиться в том случае, если нужно сравнить две строки без учета регистра символов (например, когда строка в таблице поиска сравнивается с введенной пользователем). Поскольку методы не изменяют содержимого исходных строк, используемых в выражениях, в данном случае можно просто сравнить результаты вызова соответствующих методов. var foundMatch = false; • if (stringA.toUpperCaseО == stringb.toUpperCase()) { foundMatch = true; } Поиск строк Для того чтобы определить, содержится ли одна строка внутри другой, используется метод string. indexOf (). Даже при работе с данными объектов JavaScript это весьма полезная и часто используемая информация. Например, свойство navigator. userAgent позволяет Глава 10. Строки, математические выражения и даты 147
узнать много интересного о браузере, с помощью которого выполняется загрузка страницы. Сценарий может проверить значение соответствующего свойства на наличие в нем, скажем, фрагмента Win. Полученные данные позволяют определить, какие операционные системы используются посетителем. Часто внутри очень длинной строки скрывается коротенький текстовый фрагмент особой важности, поэтому каждый сценарий должен определять, содержится ли одна строка в другой — где бы она ни располагалась. Метод string. indexOf () возвращает в качестве значения число, определяющее индекс (начальное значение нуль) того символа длинной строки, с которого начинается искомая вложенная строка. Если совпадение не обнаружено, то возвращается значение -1. Чтобы выяснить, содержится ли данная строка в длинном текстовом фрагменте, достаточно просто убедиться, что возвращаемое методом значение отлично от -1. В этом методе указываются две строки: короткая и длинная. Длинная строка что задается в ссылке слева от имени метода. Более короткая, указывается в качестве параметра метода indexOf (). Чтобы продемонстрировать, как этот метод применяется на практике, приведем следующий фрагмент кода. В нем выясняется, использует ли пользователь операционную систему Windows. var isWindows = false; if (navigator.userAgent.indexof("Win") != -1) { isWindows = true; } В условии конструкции if использован оператор неравенства (! =). Он определяется, как "не равно". Извлечение копий символов и подстрок Для того чтобы извлечь в определенной позиции строки отдельный символ, используется метод chartAt (). Параметр этого метода — индекс (начальное значение нуль) искомого символа. Выше мы указали на необходимость извлечь символ, однако это не подразумевает удаление. Извлечение, скорее, напоминает "фотографирование" символа. Исходная строка не изменится при этом никоим образом. Например, рассмотрим сценарий в основном окне, который проверяет переменную stringA другого окна (в последнем отображаются планы различных зданий). Когда в окне отражается план здания Building С, значение переменной stringA равно "Building С". Символ, обозначающий здание, всегда представлен в десятой позиции (т.е. индексом номер 9, если начинать отсчет с нуля), поэтому сценарию достаточно проверить только один этот символ, чтобы идентифицировать карту, отображенную в текущий момент в окне. var stringA = "Building С"; var bldgLetter'= stringA.charAt(9); // Результат: bldgLetter = "C" Другой метод — строка . substring () — позволяет извлечь последовательность символов по известному индексу начала и окончания той подстроки, копию которой нужно получить. Здесь обязательно обратите внимание на тот факт, что последний символ такой подстроки (который соответствует конечному индексу) не извлекается. Все остальные символы, начиная с символа, соответствующего начальному индексу, и заканчивая символом, стоящим перед соответствующим конечному индексу, будут извлечены в виде единой подстроки. Строка, из которой извлекается фрагмент, в ссылке на метод располагается слева от имени метода. Два параметра, передаваемых методу, соответствуют начальному и конечному индексу (если начинать отсчет с нуля) извлекаемой подстроки. var stringA = "banana daiquiri"; var excerpt = stringA.substring(2, 6); // Результат: excerpt = "nana" 148 Часть II. Руководство по JavaScript
Операции со строками в JavaScript, по сравнению с некоторыми другими языками, выглядят несколько громоздкими. Такие высокоуровневые понятия, как слова, предложения или абзацы, просто отсутствуют. Очень часто управление строчными объектами реализуется с помощью немногочисленных простых операторов, что создает впечатление небывалой просты вьшолняемых операций. Чтобы разубедиться в этом, попробуйте применить полученные ранее знания о вычислении выражений для обработки текстовых структур нетривиального характера, вложенных одна в другую. Например, в следующем фрагменте нужно создать новую строку, полученную на основе более длинной строки, из которой исключено первое слово. Примите во внимание, что первое слово может иметь любую длину. Поэтому во втором операторе вы должны найти первый пробел, использовав метод string. indexOf (). К индексу первого пробела в строке прибавляется единица, в результате определяется начальный индекс для метода string, substring (). Для определения второго параметра этого метода используется свойство length строки (оно на единицу больше того числа, которое передается в качестве параметра). var stringA = "The United States of America"; var excerpt = stringA.substring(stringA.indexOf(" ") + 1, stringA.length); // Результат: excerpt = "United States of America" Создание подобного рода кода иногда вызывает затруднения. В главе 27 продемонстрированы способы создания собственной библиотеки функций, управляющих строками, которые впоследствии можно эффективно использовать при написании сценариев управления строковыми данными. Основные же средства обработки строковых данных, реализуемые в виде обычных выражений, поддерживаются во всех современных браузерах (глава 27 и 42). Объект Math В JavaScript представлен широкий набор программных средств для проведения математических вычислений. Все "уважающие себя" языки программирования включают подобные мощные программные средства, чтобы программисты имели возможность создавать окна, выдающие на экран числовые результаты. Все эти возможности предоставляются объектом Math. Он выгодно отличается от всех остальных объектов JavaScript — для работы с ним не нужно создавать его копии. Вместо этого просто вызываются методы и свойства единственного объекта Math. Объект Math является производным от окна или фрейма, однако на ход выполнения сценария это совершенно не влияет. Программисты называют такого рода фиксированные объекты статичными. Объект Math (пишется с большой буквы М) обязательно должен указываться в ссылке на свойство или метод. Свойства объекта Math— это постоянные значения (константы), например число я или корень квадратный из 2. var piValue = Math.PI; var rootOfTwo = Math.SQRT2; Методы объекта Math выполняют широкий круг задач, вплоть до вычисления тригонометрических и других математических функций, управляющих числовыми значениями, которые предопределены в сценарии. Например, следующим образом в сценарии определяется большее из двух чисел. var larger = Math.max{значение!, значение2) ; Таким образом число возводится в десятую степень. var result = Math.pow(значение!, 10); Ниже приведен очень эффективный метод, с помощью которого можно округлить значение до ближайшего целого числа. var result = Math.round{значение!) ; Глава 10. Строки, математические выражения и даты 149
Еще один часто используемый метод — это генерирование случайного числа с помощью объекта Math. Хотя это свойство и недоступно в NN2 для Windows и Macintosh, во всех других браузерах его применение не вызывает затруднения. Метод Math. random () возвращает в качестве значения число с плавающей точкой в диапазоне от 0 до 1. Если вами создается сценарий карточной игры, то в нем обязательно понадобится сгенерировать случайные числа от 1 до 52. При бросании кубика задаются случайные числа в диапазоне от 1 до 6. Для того чтобы сгенерировать целое число в диапазоне от нуля до любого другого числа, можно воспользоваться следующей формулой. Math., floor (Math, random () * (n+1) ) где n — верхний предел диапазона. Метод Math. floor () возвращает целую часть любого числа с плавающей точкой. Для генерирования случайных чисел в диапазоне между единицей и числом, большим единицы, используется формула Math.floor(Math.random() * n) +1 где п также является верхним пределом диапазона. Для игры с подбрасыванием кубика случайное число в диапазоне 1-6 задается следующим образом. newDieValue = Math.floor(Math.random() * 6) +1; Чтобы увидеть результат, следует правую часть приведенного выше выражения ввести в верхнее поле приложения The Evaluator Jr. и щелкнуть на кнопке Evaluate (Вычислить). Единственное, в чем на JavaScript нельзя положиться, за исключением применения его в IE5.5 и Mozilla-совместимых браузерах, — это форматирование чисел. В числах с плавающей точкой после десятичной может отображаться не больше десятка цифр. Добавьте также всевозможные погрешности в операциях с числами с плавающей точкой, которые зависят от используемой операционной системы, особенно для ранних версий браузеров. Для браузеров, созданных ранее ГЕ5.5 и NN6, форматирование любого типа данных придется выполнять самостоятельно — для долларов и центов, например, с помощью отдельных сценариев. В главе 28 приведены соответствующие примеры. Объект Date Работа с датами в JavaScript, выходящая за рамки простых задач, может быть весьма непростым делом. Большинство проблем возникает по причине того, что дата и время рассчитываются непосредственно по Гринвичскому времени (Greenwich Mean Time — GMT). При этом подразумевается, что время на часах компьютера пользователя выставлено правильно (см. главу 29). В данной главе будут рассмотрены только основные способы управления объектом Date в JavaScript. В браузерах, поддерживающих сценарии, присутствует только один глобальный объект Date (если точно, то один объект Date в одном окне), к которому можно обратиться в любое время. Объект Date является еще одним примером статичного объекта. Когда вам нужно получить дату, например, для отображения ее на странице, вызовите конструктор объекта Date для получения экземпляра объекта Date, задающего определенную дату и время. Например, если вызвать конструктор без указания параметров, например, как в следующем случае. var today = new Date(); то в объекте Date будут сохранены показания системных часов компьютера, используемого посетителем; кроме того, будет возвращен соответствующий экземпляр объекта. Обратите внимание на разницу между объектом Date и экземпляром объекта, содержащим текущие дату и время. В переменной today "спрятано" не динамически изменяемое время, а значение, которое можно проверить, разбив на составляющие, и использовать в сценарии по своему усмотрению. 150 Часть //. Руководство по JavaScript
Значение экземпляра объекта даты — это время, выраженное в миллисекундах, начиная с 1 января 1970 года в зоне Гринвичского меридиана (всемирный стандарт для задания абсолютных дат и времен). Таким образом в объекте даты удается сразу запомнить и дату, и текущее время. С помощью объекта Date можно определить дату и момент времени как в прошлом, так и будущем, для чего полученная информация задается в качестве параметров функции конструктора объекта Date. var someDate = new Date("Month dd, yyyy hh:mm:ss"); var someDate = new Date("Month dd, yyyy"); var someDate = new Date(yy,mm,dd,hh,mm,ss); var someDate = new Date(yy,mm,dd); var someDate = new Date(GMT milliseconds from 1/1/1970); Если теперь попробовать просмотреть ряд объектов date, JavaScript преобразует соответствующие значения в строку, которая содержит время текущего часового пояса (эта строка задается согласно настройкам папки Панель управления компьютера пользователя). Воспользуйтесь приложением The Evaluator Jr. и введите в верхнее поле следующий код. new Date(); Часы персонального компьютера представляют текущие дату и время в таком виде, как они задаются на экране обычных часов (даже несмотря на то, что JavaScript управляет временем в миллисекундах соответственно времени Гринвичского меридиана). Тем не менее, в результате применения некоторых методов к экземпляру объекта даты из него можно извлечь отдельные компоненты даты. В табл. 10.1 приведен краткий список соответствующих свойств и их описания. Метод Диапазон значений Описание объектДа ты. get Time () 0- . . . объектДа ты. get Year () 70-... объектДаты.getFullYear() 1970-. объектДаты, объектДаты, объектДаты, объектДаты, объектДаты, объектДаты, объектДаты, {значение) объектДаты, {значение) объектДаты, {значение) .getMonthO .getDate () .getDay() .getHours 0 .getMinutes 0 .getSeconds() .setTime .setYear .setMonth 0-11 1-31 0-6 0-23 0-59 0-59 0-. . 70-. 0-11 Количество миллисекунд, начиная с 1 января 1970 года 00:00:00, по Гринвичскому времени Заданный год минус 1900. Четырехзначное число для года, начиная с 2000 и позже Четырехзначное число, определяющее год. Поддерживается браузерами, начиная с четвертой версии Месяц года (Январь=о) Число месяца День недели (Воскресеньем) Время суток в часах Минуты Секунды Задает количество миллисекунд, начиная с 1 января 1970 года 00:00:00 по Гринвичскому времени Задает год минус 1900. Четырехзначное число для года, начиная с 2000 и позже Задает месяц года (Январь=о) Глава 10. Строки, математические выражения и даты 151
Окончание табл. J 0.1 Метод Диапазон Описание значении объектДаты. set Date (значение) 1-31 Задает ЧИСЛО месяца объектДаты. set Day (значение) о-б Задает день недели (Воскресенье=о ) объектДаты. setHours (значение) о-23 Задает время суток в часах объектДаты. setMinutes {значение) 0-59 Задает минуты объектДаты. setSeconds {значение) 0-59 Задает'секунды Будьте внимательны, работая со значениями, диапазон возможных изменений которых начинается с нуля. Особенно это касается месяцев. Методы getMonthO и setMonthO могут возвращать в качестве значения нуль. Таким образом соответствующее число на единицу меньше, чем номер месяца (например, январю соответствует о, декабрю— и). В методах, используемых для задания даты (те, что содержат в имени set), можно заметить одну интересную особенность. Вместо того чтобы возвращать новое значение, эти методы, фактически, изменяют значение экземпляра объекта даты, на который сделана ссылка при вызове метода. Определение даты Работа с датой подразумевает использование значений объектов. Значения эти, как уже отмечалось, указаны в миллисекундах. Это позволяет легко складывать, вычитать и сравнивать даты. В целях демонстрации методов управления датой и временем приведен листинг 10.1. В нем на загружаемой странице отображаются текущие дата и время. В другом сценарии производится расчет даты и времени на семь дней вперед по сравнению с текущей датой и временем. JlM^iiHii^l^ f4'.Шм»|*«в#мр№«р. 4ЯЙП!*М^!^|мШ. <html> <head> <title>Date Calculation</title> <script type="text/j avascript" > function nextWeek() { var todaylnMS = today.getTime(); var nextWeeklnMS = todaylnMS + ' (60 * 60 * 24 * 7 * 1000); return new Date(nextWeeklnMS); } </script> </head> <body> Today is: <script type="text/javascriptu> var today = new DateO ; document.write(today); </script> <br> Next week will be: <script type="text/javascript"> 152 Часть II. Руководство по JavaScript
document.write(nextWeek()); </script> </body> </html> В теле документа первый сценарий запускается при загрузке страницы, определяя глобальную переменную (today), значение которой равно текущей дате и времени. Строковый ее эквивалент отображается на странице. Во втором сценарии упомянутого раздела метод document .write () вызывает функцию nextWeek (), определяющую значение, которое впоследствии будет отображено на странице. Эта функция использует глобальную переменную today и копирует ее значение в миллисекундах в новую переменную todaylnMS. Для вычисления даты через семь дней после текущей в следующем операторе к текущей дате (в миллисекундах) добавляется число миллисекунд в семи днях (60 секунд умножить на 60 минут, умножить на 24 часа, умножить на 7 дней и умножить на 1000 миллисекунд). Далее в сценарии задается новый экземпляр объекта с рассчитанным суммарным числом миллисекунд. С этой целью вызывается конструктор объекта Date с данным числом миллисекунд в качестве параметра. Возвращаемым значением является объект даты, который автоматически преобразуется к строковому типу для отображения на странице. При создании с помощью JavaScript нового объекта даты вы можете воспользоваться одной хитростью, которая избавляет вакс от необходимости подсчета количества миллисекунд. Удачно комбинируя методы setDate () и getDate (), вы получите объект даты, в котором не выполняются дополнительные временные преобразования. today.setDate(today.getDate() + 7); document.write(today); Тех, кто и в дальнейшем будет использовать в своих сценариях даты, ждет много откровенных неожиданностей в поведении дат. Однако конечный результат стоит затраченных усилий. Упражнения 1. Создайте Web-страницу, которая содержит одно поле формы для введения в него почтового адреса пользователя и кнопку Submit. Используйте программу предварительной проверки правильности введенных данных. Отправка формы должна выполняться только в том случае, если в текстовом поле обнаружен используемый в почтовых адресах символ @. 2. У вас естъ текстовая строка "Internet Explorer". Ниже приведен оператор myString. substring () с пропущенными параметрами. Расставьте эти параметры так, чтобы получить нужный результат. var myString = "Internet Explorer" myString. substring ( , ) //Результат = "Intt" myString. substring ( , ) //Результат = "plorer" myString. substring ( , ) //Результат = "net Exp" 3. Введите недостающий код функции, приведенной ниже, так, чтобы она просматривала каждый символ текстового поля ввода и определяла, сколько раз в этом поле использована буква "е". Подсказка: в представленном коде отсутствует цикл повторения for. <html> <head> <title>Wheel o' Fortuna</title> <script type="text/javascript"> function countE(form) { Глава 10. Строки, математические выражения и даты 153
var count = 0; var inputString = form.mainstring.value.toLowerCase(); missing code var msg = "The string has " + count; msg += " instances of the letter е."; alert(msg); } </script> </head> <body> <form> Enter any string: <input type="text" name="mainstring" size="30nxbr> <input type="button" value="Count the Es" one1ick="countE(this.form)"> ' </form> </body> </html> 4. Создайте страницу, имеющую два поля и одну кнопку. Кнопка должна запустить функцию, генерирующую два случайных числа в диапазоне от 1 до 6, разместить эти числа по одному в каждом поле. Результат напоминает подбрасывание двух кубиков при игре в кости. 5. Создайте страницу, которая бы отображала число дней, оставшихся до Рождества. 154 Часть II. Руководство по JavaScript
Работа с окнами и фреймами дним из главных преимуществ JavaScript с точки зрения клиента является управление в одном окне или фрейме содержимым других окон и фреймов, реализуемое с помощью родительско-дочерних отношений. В этом разделе вы расширите свои знания о ссылках на объекты многофреймовых документов. Окна: отцы и дети Вероятно, вы уже заметили, что расположенный в верхней части иерархической структуры упрощенной объектной модели документа (рис. 4.1) объект window связан с некоторыми другими объектами. В главе 8 вы узнали, что ключевое слово self — синоним понятия window, когда ссылка задается на то же окно, которое содержит документ со сценарием. В этой главе рассказывается о том, какую роль играют три других целевых объекта — frame, top и parent. Загрузка в браузер самого обычного документа HTML приводит к тому, что в браузере создается модель, которая начинается с единого объекта окна window, содержащего документ. Документ, скорее всего, будет содержать другие элементы, но пока этрт вопрос мы затрагивать не будем. Верхняя часть иерархической структуры настолько проста, насколько это вообще возможно. Ее можно увидеть на рис. 11.1. Именно в этой части начинаются ссылки, в начале которых задано window или self (они также могут начинаться с document, поскольку текущее окно задано по умолчанию). В случае, если в браузер загружает документ с несколькими фреймами, то он создает несколько иную иерархическую структуру. Точный вид структуры полностью зависит от вставленных в документ фреймов, определяемых Рис. 11.1. Простое ок- в загружаемом документе. Далее мы рас- но и иерархия обьек- смотрим одно из представлений много- тов документа фреймового документа. о
<html> <frameset cols="50%,50%"> <frame name="le£tFrame" src=Msomedocl.html"> <frame name="rightFrame" src="somedoc2.html"> </frameset> </html> Этот HTML-код разбивает окно на два фрейма (подокна), расположенных рядом. В каждом фрейме загружается отдельный документ. Модель отображает только структуру — в этом случае относительный размер фреймов не столь важен, как их расположение (по вертикали или по горизонтали). Настройки фреймов задают взаимоотношения между всеми объектами. Используя терминологию объектно-ориентированной концепции, многофреймовые документы загружаются в родительское окно. Каждый фрейм в этом родительском окне является дочерним фреймом. На рис. 11.2 показана иерархическая структура двухфреймовой среды. Эта иллюстрация помогает выяснить многие тонкости взаимоотношений фреймов в одном документе. <frame> Рис. J 1.2. Окно, разделенное на два фрейма, и иерархия многофреймового документа Иногда довольно сложно сразу представить многофреймовую структуру в качестве объекта окна в иерархической структуре. Если не считать отображаемого в поле Location или Address адреса URL, никакие другие признаки фреймовой структуры в браузере обнаружить невозможно. Однако сам объект многофреймового документа в модели все же представлен. Возьмите на заметку, что родительское окно на диаграмме многофреймовой структуры не содержит никаких документов. Это может показаться странным, поскольку окно, по всей видимости, должно содержать HTML-файл с приведенными в нем параметрами всех фреймов. На самом деле родительское окно представлено объектом документа, но он специально опущен в структуре (мы упростили описание принципа взаимодействия между родительским и дочерними окнами). Родительский документ многофреймовой структуры содержит лишь часть объектов обычных НТМ1^документов (в эту часть формы и элементы управления не входят). Таким образом, ссылки на родительский документ используются крайне редко, если вообще когда-нибудь используются. Если в многофреймовый документ добавить сценарий, в котором требуется получить доступ к свойству или методу объекта исходного окна, структура ссылок останется абсолютно такой же, как и в случае использования простого окна. Ситуация полностью идентична расположению сценария в этом окне. Ситуация станет намного интереснее, если нужно обратиться к дочерним фреймам. Каждый такой фрейм содержит объект документа (его содержимое отображается в окне браузера). 156 Часть II. Руководство по JavaScript
Структура всей этой модели такова, что каждый фрейм является независимым друг от друга. Создается впечатление, что каждый документ существует в отдельном окне браузера. Именно поэтому дочерние фреймы могут рассматриваться как объекты окна. Фреймы имеют тот же набор свойств и методов объекта окна, что и большое окно, расширенное до максимального размера. С точки зрения любого дочернего фрейма (рис. 11.2) его непосредственным контейнером является родительское окно. Если родительское окно находится в верхней части иерархической модели, загружаемой в браузер, то на это окно ссылка задается так же, как на объект высшего уровня. Ссылки на другие объекты Далее мы выясним, как сценарии, размещенные во всех окнах многофреймовой структуры (рис. 11.2), получают доступ к объектам, функциям или переменным в других окнах. Таким образом, если сценарий получает доступ к объектам, функциям или глобальным переменным в текущем окне, то он может получить доступ к таким же элементам и в других окнах структуры (подразумевается, что всеми документами управляет один и тот же Web-сервер). В сценарии, который управляет двухуровневой иерархической структурой (описываемой в данной главе), вам понадобятся ссылки трех типов: из родительского фрейма на дочерний; из дочернего фрейма на родительский; из одного дочернего фрейма на другой дочерний фрейм. Каждый из этих типов ссылок подразумевает использование разных вариантов введения кода. Ссылки из родительского фрейма на дочерний Наиболее редко используют такой тип ссылок, при котором сценарий из родительского окна получает доступ к элементу в одном из его фреймов. Родительское окно содержит два или более фреймов. Это подразумевает, что родительское окно содержит массив объектов дочерних фреймов. Доступ к фрейму из этого массива можно получить с помощью индекса массива или его имени, которое присваивается фреймам в атрибуте name дескриптора <f гагае>. В приведенных ниже примерах ссылок в качестве заполнителя объектов, функций или глобальных переменных окон или фреймов, доступ к которым нужно получить, используется ИмяПеременнойОбъектаФункции. Не следует забывать, что каждый отображаемый фрейм содержит объект документа, который обычно выступает контейнером для элементов, задействованных в сценарии, — поэтому в соответствующих ссылках нужно использовать указание на document. Учтя все это, можем организовать ссылку из родительского окна на один из его фреймов, используя любой из приведенных двух способов. [window.]frames[n].ИмяПеременнойОбъектаФункции [window.]имяФрейма.ИмяПеременнойОбъектаФункции Индексы фреймов определяются в той же очередности, в которой они описаны в дескрипторах <f rame> многофреймового документа. Чтобы упростить задачу, каждому фрейму присвойте легкоузнаваемое имя, а затем эти имена используйте в ссылках. Отметьте также, что в ранних версиях браузеров часто возникают проблемы с обработкой ссылок, начинающихся с window. Поэтому я бы порекомендовал отказаться от использования window в таких ссылках. Ссылки из дочернего фрейма на родительское окно Достаточно распространена ситуация, когда сценарии размещаются в родительском окне (в разделе заголовка), а потом используются несколькими фреймами или документами в качестве библиотеки. При таком способе загрузки сценарии загружаются только один раз, когда Глава 11. Работа с окнами и фреймами 157
отображается окно многофреймового документа. Если спустя некоторое время во фреймы загружаются другие документы, то вы сможете воспользоваться всеми преимуществами, предоставляемыми при этом родительскими сценариями (дополнительно не дозагружая собственные сценарии в браузер). В дочернем фрейме следующий уровень вверх в иерархической структуре будет представлен объектом parent. Поэтому ссылка из дочернего фрейма на элемент родительского окна выглядит следующим образом. "parent. ИмяПеременнойОбъектаФуикции Если ссылка задается на функцию родительского окна, которая возвращает значение, то это значение будет отправлено из родительского в дочерний фрейм без дополнительного вмешательства. Если родительское окно находится на вершине иерархической структуры, загруженной в текущий момент в браузер, то по желанию ссылку на него можно задать как на окно наивысшего уровня. top. ИмяПеременнойОбъектаФуикции Использовать в ссылках ключевое слово top достаточно опасно, если по каким-то причинам используемая страница отображается во фрейме другого Web-узла. В этом случае окно наивысшего уровня (если можно так сказать) располагается не на самом высоком уровне. Поэтому, где это только возможно, используйте в ссылках термин parent (если только предыдущий метод не используется для очистки узла от нежелательных фреймов). Ссылка из дочернего фрейма на дочерний фрейм Если требуется организовать взаимодействие одного фрейма с одноуровневым объектом, затрагиваются все высшие уровни структуры объектной модели браузера. Одно из свойств любого окна или фрейма — это его родитель parent (данное значение для обычного окна имеет значение null). В ссылке на одноуровневый объект обязательно используется это свойство, что обеспечивает переход к общей исходной точке обоих дочерних фреймов (в данном случае — к их родительскому окну). Теперь, когда ссылка начинается на родительском уровне, остальная ее часть организована точно так, как если бы орта задавалась из родительского окна на дочернее. Таким образом, ссылка из одного дочернего фрейма на другой задается любым из приведенных ниже двух способов. parent.frames[n].ИмяПеременнойОбъектаФуикции parent.frames["имяФрейма"].ИмяПеременнойОбъектаФуикции parent. имяФрейма. ИмяПеременнойОбъектаФуикции Обратная ссылка из второго фрейма на первый реализуется так же, за исключением другого индекса или значения имяФрейма в массиве frames. Конечно же, в HTML можно использовать более сложные иерархические структуры ссылок. Как бы сложна ни была объектная модель документа, правила задания ссылок позволяют найти решение при использовании самых запутанных структур и глубоко вложенных фреймов. Полезные советы Одна из наиболее распространенных ошибок, которые допускают начинающие пользователи при составлении сценариев в многофреймовых средах, заключается в следующем: сразу создаются сценарии, в которых другие фреймы вызываются еще при загрузке страницы. Проблема состоит в том, что нельзя предусмотреть последовательность загрузки объектов документа исходя из того, как расположены соответствующие операторы многофреймовой страницы. Вы должны знать, что родительский документ начинает загружаться 158 Часть //. Руководство по JavaScript
первым. Независимо от последовательности дескрипторов <frame>, загрузка дочерних фреймов начинается в любое время. Более того, время загрузки фреймов зависит от других элементов документа — изображений или аплетов Java. Настроить загрузку сценария можно только после успешной зацэузки всех документов фреймов. Точно так же, как при полной загрузке документа запускается обработчик события onload, в многофреймовой структуре выполнение обработчика события onload в дочернем окне определяет его готовность к использованию в родительском окне. Задать настройки обработчика onload можно в дескрипторе <f rameset>. Этот обработчик вызывает функцию в многофреймовом документе, после чего можно использовать объекты, функции или переменные во всех фреймах иерархической структуры объектов. Обратите внимание, что ссылка на фрейм как на специальный тип объекта окна существенно отличается от ссылки на объект элемента frame. Элемент объекта представляет собой отдельный узел в объектной модели документа (глава 4). Свойства и методы этого узла отличаются от свойств и методов объекта окна (указанной разницей весьма удобно пользоваться при решении сложных задач программирования). Способ обращения к фрейму — объект окна или узел — определяет используемые в сценарии свойства и методы. В главе 15 приведено более полное описание характеристик объектов и узлов. Если вы решили использовать объект frame, то вполне можете обратиться к объекту document, в который загружен фрейм. При этом синтаксис ссылки будет значительно отличаться — в IE4+ и Safari объект document представляет окно; в Mozilla-совместимых браузерах поддерживаются стандарты W3C DOM, которые обуславливают использование свойства contentDocument. Чтобы обеспечить поддержку обоих вариантов синтаксиса, применяется следующий код. var docObj; var frameObj = document.getElementById("myFrame"); if (frameObj.contentDocument) { docObj = frameObj.contentDocument; } else { docObj = frameObj.document; } Элемент iframe Элемент iframe поддерживается в браузерах ГЕ4+, Safari и Mozilla в виде отдельного объекта. Обычно он используется для загрузки HTML- или XML-документа в отдельном окне, которое отображается в пределах текущей страницы. Тем не менее, часто объект iframe умышленно не отображают, чтобы скрыть от пользователя сценарий. Элемент iframe включается в коллекцию frames окна текущего документа. Но вы можете обратиться к нему как к отдельному элементу объекта, воспользовавшись методом document. getElementById () в W3C DOM. В отличие от стандартной иерархической структуры типа кадр-окно, объект элемента требует использования специального кода для обращения к документу, расположенному в объекте iframe (см. главу 16). Способы управления многофреймовыми документами Если с помощью фреймов вы организуете сложные Web-страницы, то вам понадобится постоянная навигационная панель (чтобы совершать переходы от одних фреймов к другим). Ниже представлена концепция такого средства управления, реализуемая с помощью приложения Глава 11. Работа с окнами и фреймами 159
Decision Helper (Помощник принятия решений) (его вы найдете на компакт-диске, прилагаемом к книге; см. также главу 55). Приложение состоит из трех фреймов (рис. 11.3). Фрейм в верхней левой части состоит из одного изображения, на котором расположены четыре графические кнопки. Вы должны включить это изображение в карту изображения клиента и создать такой сценарий, который в правом и нижнем фреймах изменял бы соответствующие страницы. В правом верхнем фрейме сценарий загружает полностью произвольный документ из набора пяти разных используемых документов. В нижнем фрейме сценарий переходит к одному из пяти анкеров для отображения фрагмента инструкций, которые применяются к документу, загруженному в правом верхнем фрейме. Fte Edt Vtew Favorite* Tods Hrfp a a # £ о Stop fUfrwh Search Favorites Made * в S8 Buying a FAX machine Results ! Fax-O-Matic 1000 47 2 ] InkyFax300 :!55.6 \ : LazyFaxLX ;Г?2 Loose Cannon M-200 72 A io i Ranking Step 5: Viewing Results Results are calculated based on the various weights and rankings you entered in previous screens Trie specific numbers are''not particularly Important their relative positions, however, are what youYe looking for. The highest number represents the alternative rating the highest based on your Input. Values are shown to four decimal places In case of close races. Unfortunately, this results screen cannot be printed or sawed. If you want to preserve this information take a screen shot using your operating system's screen capture utility (e.g., Windows 95: Press PrtSc, MacOS: Press Cmd-Shift-3). ajQ Dona *j| Local intranet Puc. 11.3. Так выглядит приложение Decision Helper В листинге 11.1 приведена несколько измененная версия настоящего файла навигационного фрейма приложения Decision Helper. В данном листинге были использованы новые объекты и концепции, с которыми мы еще не знакомились. Для того чтобы облегчить процесс восприятия нового материала, код сценария и HTML для верхней и нижней кнопок мы решили не приводить. Опишем только навигационные кнопки со стрелками. Листинг 11.1. Графинеасая наш*гацнонная панель <html> <head> <title>Navigation Bar</title> <script type="text/javascript"> <!-- start function goNextO { var currOffset = parselnt(parent.currTitle) if (currOffset < 5) { currOffset + = 1; 160 Часть II. Руководство по JavaScript
parent.entryForms.location.href ■= "dh" + currOffset + ".htm"; parent.instructions.location.hash = "help" + currOffset; } else { alert("This is the last form."); } } function goPrevO { var currOffset = parselnt(parent.currTitle); if (currOffset > 1) { currOffset -= 1; parent.entryForms.location.href = "dh" + currOffset + ".htm"; parent.instructions.location.hash = "help" + currOffset; } else { alert("This is the first form."); } } // end --> </script> </head> <body bgColor="white"> <map name="navigation"> <area shape="rect" coords="25,80,66,116" href="javascriptigoNext()"> <area shape="rect" coords="24,125,67,161" href="javascript:goPrev()"> </map> <img src="dhNav.gif" height="240" width="96" border="0" usemap="#navigation"> </body> </html> Начать лучше с первого раздела HTML — с раздела body. Практически весь приведенный выше код предназначается для объявления стандартных карт изображений. Примененные координаты определяют рамки вокруг каждой стрелки большего изображения. Использованный для двух областей атрибут href указывает на функцию JavaScript, определяемую в разделе head документа. В настройках приложения Decision Helper каждому фрейму присваивается имя. Верхний правый фрейм называется entryForms;. Нижнее окно называется instructions. Для того чтобы совершить переход от определенной страницы к той, что загружена в верхнем правом фрейме, нужно знать, какая страница загружена там в текущее время. С этой целью как в родительский документ, так и в дочерние, встроен специальный сценарий, который загружается в указанный фрейм. В родительском документе определена глобальная переменная — currTitle. Ее значением является число в диапазоне от 1 до 5, которое и определяет, какая из набора страниц загружена на текущий момент в фрейме. Обработчик события onLoad каждого из пяти документов (dhl. htm, dh2 . htm, dh3 . htm, dh4 . htm и dh5 . htm) присваивает номер своей страницы этой глобальной переменной. Такая организация позволяет легко использовать значение переменной для всех фреймов. Когда пользователь щелкает на кнопке со стрелкой "вправо" для перехода на другую страницу, вызывается функция goNext (). Первое выражение используется для получения значения переменной currTitle из родительского окна и с целью присвоения этого значения локальной переменной currOffset. Конструкция if. . .else используется для проверки того, является ли номер страницы числом, меньшим 5. Если это так, оператор приращения добавляет единицу к локальной переменной, которая потом может использоваться в следующих двух командах. Глава 11. Работа с окнами и фреймами 161
В следующих двух выражениях обрабатывается содержимое двух правых фреймов. Используя parent, можно получить доступ к обоим фреймам. Свойству location.href правого верхнего фрейма назначается имя следующего по порядку файла (благодаря вставке соответствующего номера в имени файла). В следующем выражении свойство location.hash (которое управляет анкером начала перехода) сохраняет анкер в фрейме instructions (имена анкеров helpl, help2, help3, help4 и help5). Щелчок на кнопке со стрелкой "влево" приведет к противоположному результату. От номера текущей страницы единица уже отнимается (с использованием оператора понижения) с соответствующей заменой страниц. Пример, приведенный в листинге 11.1, является только одним из многих способов создания сценариев для навигации по окнам в JavaScript. Независимо от того, какой подход используется, взаимодействие между фреймами в сложном документе будет весьма значительным. Дополнительные сведения о ссылках В главе 8 показано, как можно создать новое окно и затем обратиться к нему с использованием ссылки на объект window, возвращаемой методом window. open (). В этом разделе вы узнаете о том, как подокна взаимодействуют с объектами, функциями и переменными окна или фрейма, создающими это подокно. В сценарных браузерах (кроме NN2) каждое окно имеет свойство, которое называется opener. Это свойство содержит ссылку на окно или фрейм, которые вмещают в себя сценарий, оператор window. open () которого использован для генерирования подокна. Для главного окна браузера и расположенных в нем подокон значение этого свойства равно null. Поскольку свойство opener является допустимым в данном контексте, то его можно использовать в начале ссылки на элемент исходного окна — точно так же, как сценарий в дочернем окне использовал parent для получения доступа к элементам в родительском документе. Терминология родительских и дочерних окон, тем не менее, к подокнам не применима. В листингах 11.2 и 11.3 приведены документы, которые взаимодействуют в разных окнах. Листинг 11.2 отображает кнопку, открывающую меньшее окно и загружающую в него документ с листингом 11.3. В документе основного окна также есть текстовое поле, которое заполняется при введении соответствующего текста в поле подокна. В документе основного окна функция newWindow () генерирует новое окно. Поскольку больше ни в одном операторе в документе не используется ссылка на только что открытое окно, то возвращаемое значение ни одной переменной не присваивается. Подобная ситуация в JavaScript крайне редкая — возвращаемое функцией или методом значение никому не нужно. <html> <head> <title>Main Document</title> <script type="text/javascript"> function newWindow() { window.open("subwind.htm", "sub", "height=200,width*200") ; } </script> </head> <body> <form> <input type="button" value="New Window" onelick="newWindow()"> 162 Часть II. Руководство по JavaScript
<br> Text incoming from subwindow: <input type="text" name="entry"> </form> </body> </html> Все, что происходит в документе подокна, относится к обработчику события onchange текстового поля. Значению поля окна документа opener присваивается значение текстового поля подокна. При этом не следует забывать, что содержимое каждого окна и подокна относится к документу. Поэтому, даже если ссылка на какое-то конкретное окно или подокно была успешной, этого недостаточно. Нужно, чтобы она точно указывала браузеру, что именно нужно найти. Как правило, это один из элементов документа <html> <head> <title>A SubDocument</title> • </head> <body> <form onsubmit="return false"> Enter text to be copied to the main window: < input type="text" onchange="opener.document.forms[0].entry.value = this.value"> </form> </body> </html> Осталось осилить еще одну главу, и уже после этого можно смело браться за изучение любого материала. В следующей главе вы узнаете о том, как изменить изображение, когда пользователь наводит на него указатель мыши. Упражнения Перед тем как ответить на первые три вопроса, следует внимательно изучить структуру приведенного ниже многофреймового документа Web-страницы, в котором отображается список читаемых в колледже предметов. <frameset rows*"85%/15%и> <frameset cols="20%,80%"> <frame name="mechanics" src="historyl01M.html"> <frame name ="description" src=,,historyl01D.html"> </frameset> <frameset cols="100%"> <frame name="navigation" src="navigator.html"> </frameset> </frameset> </html> 1. Когда бы документ ни загружался в описываемый фрейм, в нем задается обработчик события onload, содержащий в глобальной переменной currCourse многофреймового документа идентификатор курса. Напишите обработчик события onload, который устанавливает это значение равным " historyl 01". Глава 11. Работа с окнами и фреймами 163
2. Нарисуйте блочную структуру, которая описывает иерархию окон и фреймов, определяемую приведенным выше многофреймовым документом. 3. Напишите операторы JavaScript, которые будут размещаться в навигационном фрейме, выполняющем загрузку файла "french201M.html" в фрейм для курса механики (mechanics), а файла " f rench201D. html" — в фрейм описания (description). 4. Пока загружается многофреймовый документ, неожиданно появляется сообщение JavaScript об ошибке: window. document. navigation. form. selector is undef ined (не определен объект window.document.navigation.form.selector). Что могло произойти в сценарии приложения и как устранить эту проблему? 5. Сценарий в дочернем подокне главного окна использует метод window. open () для создания другого окна. Как сценарий в этом втором окне может получить доступ к объекту location родительского окна в главном окне браузера? 164 Часть II. Руководство по JavaScript
Изображения и динамический HTML редыдущие восемь глав были весьма насыщенными; в них были рассмотрены как основные принципы программирования, так и особенности JavaScript. Теперь настало время применить эти фундаментальные познания для изучения более совершенных методов. В данной главе мы уделим внимание особенностям использования ролловеров для создания динамических изменений изображения при наведении на него указателя мыши. Также речь пойдет об основных принципах динамического управления кодом. Объект изображения Одним из объектов, которые содержатся в документе, является объект изображения. К сожалению, этот объект поддерживается не всеми браузерами, управляющими сценариями. Самыми старыми версиями браузеров, которые еще работают с такими объектами, являются NN3 и Ш4. Поскольку документ может содержать больше одного изображения, то ссылки на объект изображения для документа в объектной модели представлены в виде массива, включенного в объект document. Поэтому ссылаться на изображения можно либо по индексу в массиве, либо по имени. Более того, индекс массива может быть строковой версией имени изображения. Поэтому все, что написано ниже, является вполне приемлемым способом задания ссылок. document. images [h] document. images ["имяИзображения" ] document. имяИзображения Если вашей целью является управление в сценариях изображениями, то будьте готовы к тому, что браузеры NN3 hNN4 весьма ограничены в соответствующих средствах. В частности, диапазон свойств изображений, которые поддерживаются в этих браузерах, ограничен — абсолютно доступным считается только стандартное свойство src. К тому же, до появления Ш4+ и NN6+ объекты изображений не п
имели собственных обработчиков событий. Чтобы сделать изображение интерактивным в ранних версиях браузеров нужно было добавить к ним гиперссылки, удалить рамки или создать карты изображения. Сейчас связь типа изображение-гиперссылка используется только для добавления на страницы графических кнопок. Изменяемые изображения Преимущество использования управляемых в сценариях объектов изображений заключается в том, что сценарий может изменять изображения, уже занимающие прямоугольную область на странице. В браузерах Ш4+ и NN6+ можно даже изменить размер таких изображений с выполнением соответствующего обтекания остального содержимого страницы. Сценарий таких изменений изображения достаточно прост. Он лишь присваивает свойству src объекта изображения новый адрес URL. Размер изображения на странице регулируется с помощью атрибутов height и width, которые устанавливаются в дескрипторе <img> при загрузке страницы. В самом простом случае для каждого изображения используются одинаковые размеры. В браузерах NN3 и NN4 размер изображения на странице изменить нельзя, что приводит к масштабированию изображений, когда они имеют разные размеры. Предварительная загрузка изображений Загрузка изображений с Web-сервера может занять некоторое время. Если страница организована так, что в ответ на действия пользователя изображения на странице изменяются, желательно, чтобы скорость выполнения этих операций была не ниже, чем в остальных мультимедийных программах. Если пользователю придется подолгу ждать, пока будет изменено изображение, он вряд ли получит от этого удовольствие. JavaScript приходит в этом случае на выручку. С его помощью можно предварительно загрузить изображения в кэш-память браузера без их отображения на странице. Такой подход называют предварительным кэшированием изображений. Наилучшей тактикой при этом является предварительная загрузка изображений в используемую для этих целей кэш-память браузера в момент первоначальной загрузки страницы. В таких случаях пользователи не очень нервничают по поводу нескольких лишних секунд, затрачиваемых при загрузке главной страницы на то, чтобы загрузить все изображения. Наряду с этим "накал страстей", который возникает при загрузке тех же самых изображений в режиме реального времени в процессе выполнения сценария, несравненно больше. Для того чтобы загрузить изображения, нужно создать в памяти объект этого изображения. Объект изображения, создаваемый в памяти, в некотором отношении отличается от объекта изображения документа, создаваемого с помощью дескрипторов <img>. Те объекты, которые создаются сценариями и размещаются только в памяти, на странице не отображаются вообще. Но их присутствие в коде документа приводит к тому, что при загрузке страницы эти изображения также будут загружаться. В объектной модели есть функция-конструктор объекта Image, с помощью которой можно в памяти создать объекты изображений. var mylmage = new Image(ширина, высота); Параметрами функции-конструктора является ширина и высота изображения в пикселях. Эти размеры должны соответствовать настройкам атрибутов width и height в дескрипторе <img>. Если только объект изображения существует в памяти, свойству src этого объекта можно присвоить имя файла или адреса URL. mylmage.src = "someArt.gi f"; Если браузер обнаруживает указание присвоить свойству src объекта URL-адрес, то браузер загружает соответствующее изображение в кэш-память. Все, что при этом видит 166 Часть II. Руководство по JavaScript
пользователь, — это дополнительная информация о загрузке в строке состояния (как если бы изображение отображалось на странице). К тому времени, когда будет загружена вся страница, сгенерированные таким способом изображения будут занесены в кэш-память. После этого свойству src изображения документа, созданного с помощью дескрипторов <img>, можно присвоить значения кэшированных в памяти изображений или реальных изображений с предопределенным URL. document.images[0].src = mylmage.src; Изменяются изображения в документе таким же способом. Код в листинге 12.1 является достаточно простым примером описания страницы. В нем используется дескриптор <img> и список выбора, позволяющий перемещать изображение в документе на место одного из четырех, загруженных в кэш браузера (включая и исходное изображение, описанное в дескрипторе). После того как этот листинг будет вами введен (вдумчиво и аккуратно), в папке с листингами главы 12 на компакт-диске следует найти четыре файла с используемыми в данном документе изображениями (однако сам код, включая и HTML-дескрипторы, придется ввести вручную). <html> <head> <title>Image Object</title> <script type="text/javascript"> // инициализация пустого массива var imageLibrary = new Array(); // предварительной загрузка изображений imageLibrary["imageIм] = new Image(120,90); imageLibrary["imagel"].src = "deskl.gif"; imageLibrary["image2"j = new Image(120,90); imageLibrary [" image2 "]. src = "desk2.gif"; imageLibrary["images"] = new Image(120,90); imageLibrary["image3"].src = "desk3.gif"; imageLibrary["image4"] = new Image(120,90); imageLibrary["image4"] .src = "desk4.gi f"; // загрузка выбранного в списке изображения function loadCached(list) { var img = list.options[list.selectedlndex].value; document.thumbnail.src = imageLibrary[img].src; } </script> </head> <body> <h2>Image Object</h2> <img src="deskl.gif" name="thumbnail" height="90" width="120"> <form> <select name="cached" onchange="loadCached(this)"> <option value="imagel">Bands <option value="image2">Clips <opt ion value="image3">Lamp <option value="image4">Erasers </select> </form> </body> </html> Глава 12. Изображения и динамический HTML Ц7
Как только страница загружается, сразу начинают выполняться всевозможные операторы. Эти операторы создают в памяти четыре новых объекта изображения и присваивают свойствам src этих объектов имена соответствующих файлов. Изображения будут загружены в кэш-память при загрузке страницы. Дальше в теле документа с использованием дескриптора <img> реализуется представление на странице одного из изображений в качестве начального. Элемент select используется для задания списка с понятными для пользователя именами рисунков, которые уже загружены в кэш-память. Когда пользователь выбирает один рисунок из предложенного списка, функция loadCached () находит значение выбранного элемента, которое является строковой версией имени объекта изображения в массиве imageLibrary. Свойство src выбранного объекта изображения присваивается свойству src отображаемого изображения на странице, в результате чего на странице незамедлительно будет представлен сохраненный в памяти рисунок. Создание ролловеров Самым простым способом повышения привлекательности страницы является использование ролловеров, изменяющих свой внешний вид при наведении на них указателя мыши. Вносить изменения в изображение вы можете в соответствии с вашим вкусом. Эффект может быть едва заметным — легкая подсветка или выделение границ исходного изображения, или крайне радикальным — полное изменение цветовой гаммы. Какой бы вариант ни был избран, писать сценарий придется все равно один и тот же. Если несколько подобных кнопок объединены в группу, то удобно организовать такую структуру в памяти в виде массива объектов изображений с соответствующими вариантами их нумерации и именования, необходимыми при управлении массивами. В листинге 122 приведен пример упорядочения массива для четырех управляющих кнопок. Приведенный в листинге код используется в рамках приложения, выполняющего подкачку изображений. Это один из наиболее сложных и длинных листингов в руководстве, поэтому он требует некоторых пояснений. Такие пояснения будут приведены непосредственно по ходу отображения листинга. <html> <head> <title>Jukebox/Image Rollovers</title> <script type="text/javascript"> Только браузеры, работающие с объектами изображений, могут выполнять загрузку изображений в кэш. Поэтому вся соответствующая последовательность находится внутри конструкции if, в условном операторе которой проверяется наличие массива document. images. В браузерах старых версий это значение не может быть определено, что соответствует значению false при проверке условия в блоке if. if (document.images) { Загрузка изображений в память начинается с создания двух массивов объектов изображений. В одном массиве хранится информация об изображениях, которые используются для кнопок в неактивном состоянии (off). В другом содержатся изображения активных кнопок (в состоянии on). В этих массивах в качестве индексов вместо целых чисел используются строки. Строковые названия соответствуют тем именам, которые присвоены видимым графическим объектам (их дескрипторы приведены в исходном коде ниже). В этом случае код более прост для восприятия. Например, запись of f ImgArray [ "play" ] вполне определенно дает понять, для чего нужен данный элемент. Как можно будет в дальнейшем увидеть из 168 Часть II. Руководство по JavaScript
листинга, подкачиваемые изображения не конфликтуют с прочими отображаемыми на странице рисунками (такое возможно, если в ссылке на отображаемые изображения при подкачке используются исключительно числовые индексы). После создания массива и присвоения первым его четырем элементам новых пустых объектов изображений, элементы этого массива просматриваются заново, чтобы указать в свойстве эгс каждого объекта, записанного в массив, путей к графическим файлам. Соответствующие строки кода выполняются при загрузке страницы, поэтому сразу производится загрузка изображений в соответствующую область кэш-памяти. // Запись в кэш всех неактивных кнопок var offlmgArray = new. Array(); offImgArray["play"] = new Image(75,33); offImgArray["stop"] = new Image(75,33); pffImgArray["pause"] = new Image(75,33); offImgArray["rewind"] = new Image(86,33); // Массив изображений - указывается путь к неактивному изображению для каждой кнопки offImgArray["play"].src = "images/playoff.jpg"; offImgArray["stop"].src = "images/stopoff.jpg"; offImgArray["pause"].src = "images/pauseoff.jpg"; offImgArray["rewind"].src = "images/rewindoff.jpg"; // Запись в кэш всех активных кнопок var onlmgArray = new Array(); onlmgArray["play"] = new Image(75,33); onlmgArray ["stop"] =* new Image (75, 33) ; onlmgArray["pause"] = new Image(75,33); onlmgArray["rewind"] = new Image(86,33); // Массив изображений - указывается путь к активному изображению для каждой кнопки onlmgArray["play"].src = "images/playon.jpg"; onlmgArray["stop"].src = "images/stopon.jpg"; onlmgArray["pause"].src = "images/pauseon.jpg"; onlmgArray["rewind"].src = "images/rewindon.jpg"; } Как можно увидеть из следующего фрагмента HTML-кода, при наведении пользователем указателя мыши на любой из отображаемых графических объектов документа, обработчик события onmouseover (в объекте документа) вызывает функцию imageOn (), передавая ей имя конкретного изображения. Функция imageOn () использует это имя для синхронизации записей массива document. images (отображаемые изображения) и массива размещенных в памяти изображений активных кнопок onlmgArray. Свойство src элементов этого массива присваивается соответствующим свойствам src изображений документа. // Функция, которая выполняет подкачку изображений function imageOn(imgName) { if (document.images) { document.images[imgName].src = onlmgArray[imgName].src; } } To же происходит при использовании обработчика события onmouseout, который переводит изображение в "выключенное'* состояние, для чего использует функцию imageOf f () с тем же индексным значением в качестве параметра. Глава 12. Изображения и динамический HTML 169
function imageOff(imgName) { if (document.images) { document.images[imgName].src = offImgArray[imgName].src; } } Оба обработчика событий onmouseover и onmouseout настраивают строку состояния так, чтобы там не отображались инструкции javascript: URL при наведении пользователем указателя мыши на изображение. В обработчике события onmouseout сообщение, отображаемое в строке состояния, выставляется равным пустой строке. function setMsg(msg) { window.status = msg; return true; } В данном примере функции управления, приведенные ниже, не задействованы, но все же они содержат пустые операторы. Это сделано для того, чтобы функции отлавливали все вызовы, которые выполняются при активизации ссылок, указывающих на изображения. // Функции управления (не задействованы) function playltO { } function stopItO { } function pauseltO { } function rewindltO { } </script> </head> <body> <center> <form> Jukebox Controls<br> Каждое изображение заключается в объект ссылки. Подобная конструкция необходима, поскольку в объекты ссылки включены обработчики события, применяемые для задания ответной реакции сценария на манипуляции пользователя с мышью (а это позволяет поддерживать совместимость документа с NN3). Каждый обработчик события onmouseover вызывает функцию imageOnO, передавая при этом имя подкачиваемого объекта изображения. Поскольку в обоих обработчиках (onmouseover и onmouseout) необходимо использовать выражение return true, для запуска процесса, вызов второй функции setMsg () необходимо объединить с требованием return true. Функция setMsg () всегда возвращает значение true, а наличие ключевого слова return перед вызовом этой функции обеспечивает нужный результат. В результате вы сможете уменьшить объем используемого кода. # При введении этого листинга с последующим его использованием следует вни- /mnmtij( мательно следить за тем, чтобы каждый дескриптор <а> вместе с его атрибута- * <**** ми располагался в одной строке. Либо следует вставить символ возврата каретки перед именем любого обработчика событий. <а href="javascript:playltО" onmouseover="imageOn('play'); return setMsg('Play the selected tune')" onmouseout="imageOff('play*); return setMsg('f)"> <img src="images/playoff. jpg" name="play" height="33" width="75" border="0"> </a> 170 Часть II. Руководство по JavaScript
return setMsg(•Pause return setMsg('')"> <a href= "javascript:stopIt()" onmouseover="imageOn(•stop'); return setMsg(•Stop the playing tune')" onmouseout="imageOff('stop'); return setMsg('') " > <img src="images/stopoff.jpg" name="stop" height="33" widths"75" border="0«> </a> <a href="javascriptipauselt ()" onmouseover="imageOn('pause'), the playing tune■)" onmouseout="imageOff('pause1) <img src="images/pauseoff.jpg" name="pause" height="33" width="75" border="0"> </a> <a href="javascriptrrewindlt()" onmouseover="imageOn('rewind'); return setMsg('Rewind back to the beginning')" onmouseout="imageOff(•rewind'); return setMsg('')"> <img src="images/rewindoff.jpg" name="rewind" height="33" width="86" border="0"> </a> </form> </center> </body> </html> На рис. 12.1 приведен пример выполнения этого длиннющего сценария. Когда пользователь наводит указатель мыши на одно из изображений (изображениями являются кнопки музыкального проигрывателя), оно изменяет свой цвет на более темный, что выполняется путем подкачки нового изображения. Файлы с изображениями можно найти на прилагаемом к книге компакт-диске. Листинг же лучше ввести самостоятельно. Только тогда можно будет ощутить всю прелесть создания сценария. Jukebox Controls RAY STOP REWIND 1шшйшшш Рис. 12.1. Так выглядят кнопки музыкального проигрывателя на странице Оператор javascript: псевдо-URL В предыдущих главах было приведено несколько примеров использования оператора javascript: в атрибуте href таких дескрипторов, как <а> и <агеа>. Это весьма удобный элемент языка, поскольку он поддерживается даже теми браузерами, которые не могут управлять сценариями. Указанный оператор обычно используется для задания обработчика события щелчка в таких объектах, которые выступают на странице в. качестве гиперссылок. На ранних этапах развития языка и браузеров объекты изображения вообще не поддерживали обработчики событий, Глава 12. Изображения и динамический HTML 171
хотя их всегда можно было включить в интерактивные элементы. Если разработчику нужно было назначить для изображения определенное динамическое действие (попросту выполнить какую-либо функцию, вместо перехода по указанному URL), то он заменял в операторе j avascript: URL-адрес на имя функции. В результате в атрибуте href можно было указать действие, выполняемое при щелчке на текущем элементе даже в браузерах, которые не обеспечивают обработку событий для объектов этого типа. Например, в конце листинга 12.2 все четыре дескриптора <а> содержат оператор j avascript:, который вызывает функцию, созданную в сценарии. <а href= "javascript:playlt()" ...> Обратите внимание на следующую особенность описанной выше методики. Несмотря на явное указание в сценарии текста, отображаемого в строке состояния, в ней всегда будет представлен псевдо-URL, заданный в операторе javascript: (что не может не удивлять пользователей). Поэтому старайтесь не использовать текущую методику в случае работы с браузерами, поддерживающими обработчики событий для объектов. Больше динамизма в HTML Поскольку современные браузеры предоставляют в сценарии доступ к любому элементу документа и позволяют обновлять содержимое страницы даже при малейших его изменениях, разрабатываемые приложения получают весьма широкие возможности по динамическому управлению. Тем не менее, технология Dynamic HTML не столь проста в использовании, как кажется, так как требует использования огромного количества специфических для каждого типа браузеров элементов. В последнем разделе этого занятия вы изучите некоторые специальные методики, поддерживаемые только W3C DOM-совместимыми браузерами. Следует обратить ваше внимание на две самые распространенные задачи, решаемые в помощью DHTML, — изменение стиля элементов и изменение содержимого тела документа. Изменение настроек таблицы стилей Каждый отображаемый на странице элемент (и даже некоторые скрытые элементы) имеют свойство style. Оно предоставляет в сценарии доступ ко всем свойствам каскадных таблиц стилей (CSS) элемента, поддерживаемым текущим браузером. Значения этих свойств те же, что указываются в спецификации таблиц стилей — обычно они задаются с помощью специальных дескрипторов, атрибуты которых отличаются в разных браузерах. Например, для изменения цвета текста элемента с идентификатором FranklinQuote используется следующий синтаксис. document.getElementById("FranklinQuote").style.color = "rgb(255/ 255, 0)"; Поскольку свойство color таблицы стилей позволяет применять другие методы определения цветов (например, с помощью гексагонального триплетного значения #ffff00), то в вашем конкретном случае указанное выражение может несколько отличаться. Имена отдельных свойств CSS-стилей, тем не менее, не соответствуют именам, принятым в JavaScript. В частности, некоторые свойства CSS-стилей содержат в именах дефисы. В таком случае в сценарии используется имена без дефисов (имена вводятся слитно), а отдельные слова начинаются с большой буквы. Например, свойство font-weight в сценарии реализуется следующим образом. document.getElementById("highlight").style.fontWeight - "bold"; Подобное поведение сценариев накладывает серьезное ограничение на код, задающий спецификации CSS-стилей. Например, если вы определили CSS-правила для двух различных 172 Часть II. Руководство по JavaScript
классов, то можете легко изменить определение класса, примененного к элементу, воспользовавшись свойством className объекта этого элемента. Далее мы рассмотрим ситуацию определения двух CSS-классов для различных фоновых цветов. .normal {background-color: #ffffff} .highlighted {background*color: #ff0000} В HTML-документе элементу сначала назначается класс по умолчанию. <р id="news" class="normal">...</р> В сценарии можно легко изменить назначенный элементу CSS-класс на highlighted. document.getElementById("news").className = "highlighted"; Изменив CSS-класс, назначенный элементу, вы изменяете его внешний вид и поведение. Этот метод удобно использовать для быстрого изменения сразу нескольких свойств элемента. Динамическое содержимое узлов W3C DOM В главе 8 вы ознакомились с методами document .createElement () и document. createTextNode (). Они используются для создания новых объектов, которые впоследствии будут настраиваться с помощью свойств (атрибутов) перед добавлением в целевой документ. В качестве введения в рассматриваемую методику я предлагаю вам ознакомиться с примером добавления элемента span, содержащего текст, на Web-страницу, В данном случае элементу абзаца с идентификатором placeholder назначен класс centered. Часть текста абзаца (имя посетителя страницы) заимствует из текстового поля, содержащегося в форме. var newElem = document.createElement("р"); newElem.className = "centered"; var newText = document.createTextNode("Thanks for visiting, " + document.forms[0].firstName.value); // вставка в абзац текстового узла newElem.appendChild(newText); // вставка абзаца в заполнитель document.getElementByld("placeholder").appendChild(newElem); Подход к программированию подобного поведения страницы в спецификации W3C DOM весьма сложен. Он требует выполнения несравненно большого количества действий, которые не всегда очевидны. После создания элемента и текстового узла последний требуется вставить в узел элемента. Поскольку новый узел элемента при создании не содержит данных, для вставки текстового узла в элемент необходимо выполнить метод appendChildO (между открывающим и закрывающим дескрипторами). После создания элемент абзаца располагается в конце исходно пустого элемента span. Специальные методы в W3C DOM (описанные в главах 15 и 16) позволяют быстро вставлять, удалять и заменять узлы. Свойство innerHTML До разработки спецификации W3C DOM компания Microsoft снабжала каждый объект свойством HTML. Впервые это свойство стало поддерживаться в браузере Ш4 и вскоре приобрело большую популярность благодаря свой высокой практичности. Это свойство принимает в качестве значений дескрипторы и другое содержимое, расположенное в HTML-документе и представляющее текущий элемент. Хотя в W3C DOM этому свойству не уделено должного внимания, оно до сих пор настолько популярно, что его поддержка реализована во всех современных браузерах. Вы даже сможете воспользоваться им в Mozilla-совместимых браузерах и Safari. Глава 12. Изображения и динамический HTML 173
Чтобы продемонстрировать преимущества этого свойства, рассмотрим два примера кода, выполняющих одну и ту же задачу. var newHTML = "<р class='centered'>Thanks for visiting, "; newHTML += document.forms[0].firstName.value; newHTML += "</p>"; document.getElementByld("placeholder").innerHTML = newHTML; Второй вариант несколько проще для понимания, да и его синтаксис значительно легче для ввода. Первый подход, заключающийся в управлении узлами, требует более внимательного изучения, хотя его код выполняется намного дольше. Зачастую самый простой код не всегда самый эффективный с точки зрения выполнения его компьютером. Итак, будем считать, что вы успешно изучили основы языка, выполнили все упражнения и прекрасно подготовились к дальнейшему знакомству с возможностями объектной модели и специальными методами программирования на JavaScript. Можете смело приступать к изучению материала частей Ш и IV, но перед этим ознакомьтесь с главой 45 на прилагаемом к книге компакт-диске, в которой рассказывается об отладке программного кода. Упражнения 1. Объясните различия между объектом изображения документа и объектом изображения в памяти. 2. Введите команды JavaScript, необходимые для предварительной загрузки в кэш-память изображения jane.jpg, которое потом будет использовано для замещения объекта изображения документа, определяемого следующим кодом HTML. <img name="people" src="John.jpg" height=120 width=100 alt="people"> 3. С помощью кода, созданного для ответа на второй вопрос, нужно определить JavaScript- операторы, используемые для замены изображения документа на изображение в памяти. 4. Совместимые со старыми версиями браузеров объекты изображений не имеют своих обработчиков событий. Как в этом случае реализуется процесс подкачки изображений в ответ на действия мышью? 5. Предположим, что элемент table содержит пустой элемент ячейки (td), имеющей идентификатор f orwardLink. Воспользовавшись спецификацией W3C DOM, напишите операторы, которые добавляют в ячейку таблицы следующую гиперссылку. <а href="page4.html">Next Page</a> 174 Часть II. Руководство по JavaScript
Объекты документа
Основы JavaScript еред разработчиками часто возникает проблема, связанная с четким разграничением базового языка создания сценариев JavaScript и теми объектами, которые должны управляться с помощью этого языка. Поэтому имеет смысл сразу провести разделительную черту между языком программирования и объектной моделью. В дальнейшем это будет способствовать облегчению процесса принятия решении при оформлении страниц с использованием JavaScript. Если когда- нибудь придется использовать JavaScript с другими объектными моделями (как, например, при программировании задач для серверов), четкое разграничение вам тоже пригодится. Основы языка при этом неизменны — изменяются только объекты. В этой главе рассматриваются многие вопросы использования базового языка JavaScript, о которых речь уже шла в предыдущей части (например, создание страниц, рассчитанных на широкий круг пользователей и всевозможные типы используемых ими браузеров). Кроме того, будут описаны новые возможности самого языка программирования. Детальную информацию о синтаксисе базового языка JavaScript можно найти в следующей части. Версии JavaScript Язык JavaScript имеет собственную систему нумерации версий, которая абсолютно независима от нумерации поколений браузеров. Компания Netscape, создавшая этот язык, во многом и определила принцип нумерации версий. Первой версией, логически завершенной, была 1.0 (она встроена в Navigator 2 и в первое издание Internet Explorer 3). По мере развития языка и разработки новых версий браузеров номера версий JavaScript увеличивались весьма умеренными темпами. Например, в Internet Explorer 6 и Mozilla- совместимых браузерах используется JavaScript версии 1.5. Каждое успешное поколение браузеров применяло новые возможности языка. Например, в JavaScript 1.0 концепция массивов не была доработана полностью, что привело к невозможности отслеживания всех элементов в массиве. В JavaScript 1.1 этот промах был устранен путем введения функции-конструктора для генерации массивов и свойства length для каждого созданного массива. п
На практике, тем не менее, встроенная в браузер версия JavaScript далеко не всегда может реализовать весь набор своих возможностей, поскольку не все ее средства доступны для управления в данной версии браузера. Например, JavaScript 1.2 (который используется в NN4) включает широкую поддержку регулярных выражений, однако не все они доступны для использования в Microsoft JavaScript 1.2, поддерживаемом в Ш4. Кроме того, Microsoft включила в JScript (IE5) систему отслеживания ошибок try-catch, в то время как Netscape не использовала эту возможность вплоть до JavaScript версии 1.5 в NN6. Поэтому при определении тех средств, которые допускается использовать, определяющей является не версия самого языка, а, скорее, используемого браузера. Стандарт базового языка - ECMAScript Несмотря на то, что компания Netscape и разработала язык JavaScript первой, Microsoft включила этот язык в Internet Explorer 3. Поскольку Microsoft не имела желания лицензировать название "Java" у владельца этой торговой марки — компании Sun Microsystems, язык в среде IE стал использоваться под названием JScript. За исключением специфических характеристик и некоторых нововведений, оба языка практически идентичны. Если сравнивать степень совместимости базовых языков и соответствующих типов браузеров, то для языков уровень совместимости намного выше (в отличие от ряда несогласованностей в реализации объектных моделей, обсуждаемых в следующей главе). Как уже отмечалось в главе 2, были предприняты серьезные попытки по созданию общих стандартов для разработчиков браузеров. Последние разработки призваны облегчить.жизнь разработчикам программных продуктов для Web. Новые веяния в первую очередь привели к изменению базовых принципов языка. При содействии европейской организации по стандартизации — ЕСМА, формальный стандарт для языка был согласован и представлен общественности. Первая версия стандарта языка, названная группой разработчиков ECMAScript, была, фактически, точной копией версии JavaScript 1.1, использованной в Netscape Navigator 3. В стандарте определялись способы трактовки различных типов данных, принципы работы операторов, особенности синтаксиса и ряд других характеристик. В более новой (третьей) версии базового языка многое было усовершенствовано (вторая версия представляла собой первую, с исправленными ошибками). Описание текущей спецификации ЕСМА-262 можно найти по адресу http://www.ecma-international.org. Студенты, изучающие языки программирования, найдут для себя этот документ весьма занимательным. Те же, кто просто решил научиться писать сценарии для страниц, могут испытать легкое замешательство. Как Netscape, так и Microsoft, обязались придерживаться при разработке своих браузеров стандарта ЕСМА. Вся широта возможностей стандарта ECMAScript была реализована уже в Netscape Navigator 3 и Internet Explorer 4. По мере того, как в стандарт ЕСМА добавляются новые характеристики, они сразу же находят себе применение в новых версиях браузеров. На данный момент ECMAScript имеет версию 3, которая поддерживается в JavaScript 1.5 (Mozilla) и JScript (Ш6). Встроенные в HTML-документы сценарии В браузерах, поддерживающих JavaScript, существуют различные способы включения сценариев или элементов сценариев в документы HTML. He каждый из таких методов может быть использован в любой версии браузера, но в этом плане, начиная с браузеров Navigator версии 3 и Internet Explorer версии 3, поддерживается достаточная степень гибкости. На данный момент достаточно предположить, что большинство пользователей работают в браузерах Глава 13. Основы JavaScript 177
не старше Ш4. В результате вы автоматически исключаете поддержку ваших сценариев в весьма небольшом кругу старых браузеров. Редкое исключение составляют пользователи, которые работают в браузерах с отключенной функцией выполнения сценариев. Дескриптор сценария <script> Самый простой способ использования операторов сценария в документе HTML состоит в том, чтобы заключить их в дескрипторы <script >. . . </script >. Язык сценария при этом указывается с помощью атрибута language. В документе можно использовать произвольное количество таких пар дескрипторов. Например, в разделе заголовка можно определить несколько функций, которые потом будут вызываться обработчиками событий в теле документа HTML. Другие дескрипторы могут использоваться в блоке тела документа для выполнения той части сценария, которая активизируется при загрузке страницы. Все операторы и комментарии сценария следует размещать между открывающими и закрывающими дескрипторами. В них не стоит использовать дескрипторы HTML, если только они не являются частью параметра оператора document. write (), который используется для отображения содержимого страницы. В каждом открывающем дескрипторе сценария <script> должен быть указан используемый язык (для этого используется атрибут language). Дескриптор <script> применяют для указания браузеру того, что содержащиеся внутри дескрипторов операторы являются частью выполняемого сценария и не должны интерпретироваться как обычный код HTML. В этом дескрипторе также можно указать любой язык, который доступен для интерпретации браузером. Задание версии языка Начиная с Ш5 и Mozilla-совместимых браузеров, дескриптор <script> поддерживает атрибут type. Например, для определения MIME-типа содержимого дескрипторов используется следующее выражение type=" text /javascript". Таким образом, дескриптор <script > для языка JavaScript будет иметь следующий вид. <script type="text/javascript">...</script> Атрибут type стал знаком разработчикам, начиная с ГЕ4. Старые браузеры, позволяющие использовать сценарии (в Netscape Navigator 2 и Internet Explorer 3), признают атрибут указания языка language= "JavaScript". Вместе с тем, более современные версии браузеров обычно распознают еще и версию языка, а в случае Internet Explorer, и другие языки (например, VBScript). Встроенный в Navigator 3 интерпретатор языка JavaScript знает версию языка JavaScript 1.1, a Navigator 4 и Internet Explorer 4 определяют версию JavaScript 1.2. При указании версий языка, отличных от исходного JavaScript, номер версии указывается после названия языка без пробела, как показано ниже. <script language="JavaScriptl.1">...</script> <script language="JavaScriptl.2">...</script> Обратите внимание на то, что атрибут language стал неактуальным в HTML 4 с появлением атрибута type, который точнее определяет используемый язык написания сценариев. Тем не менее, в ЕВ5+ и браузерах Mozilla первый все еще поддерживается, хотя версии языка в расчет не принимаются. Для того чтобы обеспечить совместимость со старыми браузерами и, в то же время, не отставать от последних разработок в этой области, можно использовать в дескрипторах сценария <script > оба атрибута: language и type. При использовании браузеров старых версий атрибут type будет игнорироваться. 178 Часть III. Объекты документа
Дескриптор <script for> В Internet Explorer 4 и более поздних версиях операторы, размещенные внутри дескрипторов сценария <script >, можно связать с конкретным объектом и событием, им генерируемым. В соответствии со спецификацией языка, набор атрибутов этого дескриптора должен дополнительно включать элементы for и event (которые не являются частью стандартного HTML). Значение, присваиваемое атрибуту event, является ссылкой на нужный объект. Как правило, это обычный идентификатор, присоединяемый к объекту (в IE4+ ссылку на объект можно задать либо в формате document. all. obj ectID, либо просто указав идентификатор obj ectID). Атрибут event используется для определения имени обработчика события, на которое будет реагировать сценарий. Например, если сценарий должен выполнять определенные действия в ответ на перемещение указателя мыши вниз на странице (событие mousedown) в разделе с идентификатором myParagraph, соответствующий фрагмент сценария должен будет выглядеть так. ocript for="myParagraph" event="onmousedown" type="text/j avascript"> </script> Операторы внутри дескрипторов будут выполняться только при наступлении нужного события. Для этого не следует описывать никакие дополнительные функции. Использование такого способа привязки событий объектов к сценарию означает, что можно отказаться от описания обработчиков событий в дескрипторах отдельных элементов. Эта техника доступна только в Ш4 и более поздних версиях браузеров. Ее можно быть с успехом использовано при обработке определенного типа событий. С другой стороны, существует серьезное ограничение, когда большая часть кода размещается в сценариях отдельных объектов. Такой подход вряд ли удастся использовать при задании операторов, которые вызываются несколькими объектами. Еще одним недостатком является то, что в браузерах, отличных от Ш или более ранних, чем IE4, описанные дескрипторы не могут использоваться при загрузке изображений. В таких браузерах операторы сценария выполняются при загрузке страницы, а это будет приводить к ошибкам. Особенности написания кода при работе со старыми типами браузеров Среди пользователей увеличивается количество новых версий браузеров, поддерживающих сценарии, количество устаревших их версий, соответственно, неуклонно уменьшается. Однако факт остается фактом: достаточно много посетителей Web-узлов используют браузеры, которые не имеют встроенных интерпретаторов JavaScript. К ним относятся, например, браузеры, работающие в мобильных телефонах и карманных компьютерах. Не управляющие сценариями браузеры не распознают дескриптор <script>, а потому не умеют его обрабатывать. Как правило, браузеры просто игнорируют незнакомые дескрипторы. С этим не возникает проблем, если весь код HTML помещается в одну строку. Но в дескрипторах <script > может содержаться достаточно большое количество таких строк. Браузеры старых версий не реагируют также и на добавление дескриптора завершения сценария </script>. Поэтому такие браузеры пытаются интерпретировать сценарии как обычный для них код HTML. К сожалению, операторы сценария располагаются непосредственно в документе. В результате на странице будет отображаться всякая ерунда, что может вызвать у пользователей вполне понятное недоумение. Однако существуют способы, позволяющие "перехитрить" многие браузеры старых типов и скрыть от них операторы сценария. Например, заключите команды сценария вместе с дескрип- Гпаша 13. Основы JavaScript 179
торами <script > внутрь дескрипторов комментария HTML. Комментарий HTML начинается с последовательности символов < ! - - и заканчивается последовательностью - - >. <script type="text/javascript"> Здесь размещаются операторы сценария II --> </script> Интерпретатор JavaScript будет игнорировать строку, которая начинается с символов комментария HTML. Сложнее дела обстоят с интерпретацией последовательности окончания такого комментария. Последовательность, закрывающая комментарий HTML, начинается с символа комментария JavaScript (//) — JavaScript должен проигнорировать данную строку. Однако не поддерживающие сценарии браузеры распознают последовательность окончания комментария HTML и поэтому начинают обрабатывать код HTML уже со следующего дескриптора или текстового фрагмента в документе. Поскольку этим браузерам дескриптор </script > не знаком, то они его просто игнорируют. Однако зачастую даже такие замысловатые приемы не всегда эффективны. Некоторые совсем старые браузеры (America Online) будут отображать на странице фрагменты кода сценария, несмотря на все попытки разработчиков страницы помешать этому. К счастью, такого типа браузеры встречаются крайне редко. Если разрабатываемая страница предназначена для широкого круга пользователей, в комментарий HTML всегда следует заключать весь код сценария, размещенный между дескрипторами <script > (см. выше). Указанные дескрипторы также должны заключаться в комментарий— ни в коем случае не наоборот. В данной книге в большинстве приведенных примеров такого рода методология не используется, однако мы делаем это исключительно в целях экономии места. Что значит "спрятать" сценарий Было бы не совсем правильным утверждать, что описанная выше процедура использования комментариев HTML помогает "спрятать" сценарий от старых браузеров. На самом деле таким образом сценарий можно предохранить только от обработки его браузером. Дескрипторы и операторы сценария при этом загружаются в браузер, и если пользователь захочет просмотреть исходный код страницы, он увидит и этот сценарий. Разработчики страниц всегда мечтали "по-настоящему" скрыть сценарии от посторонних глаз. Рассчитанный на управление на стороне клиента, код JavaScript должен загружаться на страницу. Как результат, он будет отображаться при просмотре пользователем исходного кода. Существуют, конечно, хитрости, позволяющие скрыть этот код от любопытных глаз. Самое простое, что можно сделать в такой ситуации, —загружаемая страница не должна содержать отображаемых элементов, а только сценарии, вызывающие отображаемую страницу. В этом случае код отображаемой страницы содержит только дескрипторы HTML, но никак не операторы сценария. Такая страница не будет интерактивной, поскольку в ней нет ни одной строки сценария. Это само по себе лишает смысла "скрытие" кода сценария. Все попытки скрыть исходный код с помощью сценариев могут быть сведены на нет, если пользователь при загрузке страницы временно отменит выполнение сценариев. И тогда абсолютно весь исходный код снова будет виден, как на ладони. Если кто-то беспокоится о том, что другие разработчики смогут "украсть" его сценарии, то советуем разместить предупреждение о соблюдении авторских прав прямо в исходный код страницы. Ведь не только злоумышленники могут просматривать чужие сценарии. С таким же успехом их собственные сценарии также могут быть просмотрены. Так можно отлавливать тех, кто использует чужие разработки. 180 Часть III. Объекты документа
Одним из способов предотвращения использования чужими людьми созданного вами JavaScript-кода является использование специальной программы шифрования кода, что делает его значительно сложнее для понимания. На первый взгляд, код выглядит абсолютно правильным, но при анализе он оказывается весьма сложным для изменения. Шифрованный файл можно смело размещать в Web, но при этом не забывайте хранить исходную версию кода в своем компьютере на случай, если вам понадобится когда-либо его изменить. Одну из условно- бесплатных программ шифрования кода сценариев (JavaScript Scrembler) вы найдете на узле www. quadhead. de. Библиотеки сценариев (файлы .js) Тем, кто уже работал со сценариями или в свое время трудился над разработкой страниц для сложных Web-приложений, должно быть известно, что можно разработать набор функций и фрагментов сценариев, которые впоследствии будут использоваться в разных приложениях. Вместо того чтобы каждый раз копировать такой код в соответствующие документы (а потом пройти через кошмар внесения изменений в каждую отдельную версию при добавлении новых средств или при отладке ошибок), можно создать специальную библиотеку файлов, которую впоследствии следует подключить к нужной странице. Такого рода внешние файлы не содержат ничего, кроме кода JavaScript, — никаких дескрипторов <script >, никаких HTML-элементов. Создаваемый файл с фрагментом кода сценария должен быть текстовым, но его имя должно иметь расширение . j s. Чтобы браузер загрузил его в определенном месте структуры HTML, в дескриптор <script> добавьте атрибут src, как показано ниже. <script type="text/Javascript" src="hostscript. jsMx/script> Такие дескрипторы должны размещаться в самом начале документа перед всеми остальными дескрипторами <script>, поэтому они загружаются в первую очередь. Если загружается несколько внешних библиотечных файлов, то все соответствующие дескрипторы должны размещаться в начале документа. Работая с внешними файлами, помните о следующем. Во-первых, нужно в любом случае использовать пару дескрипторов <script > . . . </script >, даже если между ними ничего нет. При этом используются как внешние сценарии, так и сценарии в самом документе. Во- вторых, если дескриптор начала сценария содержит атрибут src, то между дескриптором начала и завершения сценария другие команды размещать нельзя. Способ ссылки на внешний файл в атрибуте src зависит от размещения этого файла и стиля работы автора сценария. В предыдущем примере предполагалось, что внешний файл находится в той же папке, что и файл HTML, содержащий данный дескриптор. Но если нужно сослаться на адрес URL, то сделать это можно с помощью записи протокола http: // (по аналогии с файлами HTML). <script language="JavaScript" src="http://www.cool.com/hostscript.j s"> </script> Важным условием для управления документами из внешних библиотек сценариев является возможность программного обеспечения используемого Web-сервера сортировать файлы с расширением . js для обработки их с помощью приложения application/x- javascript. Поэтому перед тем, как применить с помощью JavaScript внешние библиотеки, следует проверить, как на это среагирует сервер, затем внесите, если нужно, коррективы в его настройки. Если пользователь захочет просмотреть исходный код загруженной страницы, в которой использованы внешние библиотеки, то код, содержащийся в j s-файле, отображен не будет (однако браузер трактует его как составную часть текущего документа). При этом имя или /• тзмлку Глава 13. Основы JavaScript 181
URL использованного j s-файла будут видны (именно в том месте, где они расположены в исходном коде). Таким образом, любой желающий сможет отключить в браузере JavaScript, открыть соответствующий j s-файл (используя протокол http: //) и просмотреть исходный код. Другими словами, код JavaScript, содержащийся во внешнем файле, не более защищен от нежелательного просмотра, чем тот, который находится непосредственно в HTML-файле. Определение версии браузера Вне всяких сомнений, наибольшие трудности у разработчиков сценариев связаны с созданием таких приложений, которые бы работали с достаточно большим набором браузеров разных типов и версий. Каждый такой браузер имеет свои особенности. В этом отношении счастливчиками являются разработчики, работающие в локальных сетях компаний, в которых все компьютеры используют один стандартный тип и версию браузера. Но это, скорее, исключение из правил, когда получают широкое развитие частные корпоративные сети, где приложения используются как компаниями, так и клиентами. Описываемая проблема возникла после выхода версии браузера NN2, который был на то время единственным браузером, работающим со сценариями. Решать ее можно по-разному. Можно либо строго определиться с типом используемого браузера, либо пойти на компромисс. Можно уменьшить требования к функциональности страницы. Вы также можете использовать на Web- узле разные страницы для браузеров разных типов. В этом разделе будет рассказано о некоторых приемах, позволяющих решать проблемы, связанные с фрагментацией рынка браузеров. I Как только популярность языка JavaScript достигла определенного уровня, его /на заметку поддержка стала считаться неотъемлемым атрибутом не только браузеров для * „.-""' настольных компьютеров, но и для мобильных устройств. Уже сегодня отдельные версии браузеров для мобильных устройств поддерживают JavaScript. Проверка поддержки JavaScript Часто наиболее важным условием в работе приложения является определение доступности JavaScript для клиента, посещающего узел. Все браузеры, не поддерживающие JavaScript, можно разделить на две категории: а) браузеры, которые JavaScript поддерживает (просто у них в соответствующих установках выключен режим поддержки JavaScript); б) браузеры, в которых поддержка JavaScript не предусмотрена вообще. Использование дескриптора <noscript> За исключением некоторых ранних выпусков NN2, все поддерживающие JavaScript браузеры в настройках (Preferences) имеют опцию, позволяющую отключать режим поддержки JavaScript (и аналогичную опцию для Java). Как правило, по умолчанию такой режим включен, однако при установке в компьютер клиента браузера этот режим иногда не работает. Причиной могут стать меры безопасности, предпринимаемые для исключения возможных конфликтов с Java, или попытки некоторых брандмауэров отследить код JavaScript во входящих HTML-потоках. Все совместимые с JavaScript браузеры поддерживают пару дескрипторов <noscript>. . .</noser ipt>, которые полностью противоположны дескрипторам <script>. . . </script>. Если в таком браузере режим поддержки JavaScript отключен, то дескрипторы <script >, в отличие от <noscript>, игнорируются. Как это происходит с дескрипторами <noframes>, дескрипторы <noscript> можно использовать для того, чтобы с помощью HTML вывести сообщение, что JavaScript отключен (поэтому все возможности страницы не могут быть задействованы, если JavaScript не подключить). В листинге 13.1 приведен пример такого кода HTML. 182 Часть III. Объекты документа
<html> <head> <title>Some Document</title> <script type="text/javascript"> // операторы сценария </script> </head> <body> <noscriptxb>Your browser has JavaScript turned off.</bxbr /> You will experience a more enjoyable time at this Web site if you turn JavaScript on <hr /></noscript> <h2>The body of your document.</h2> </body> </html> В дескрипторе <noscript> можно использовать любой стандартный код HTML. Чтобы привлечь внимание пользователя к советам в верхней части страницы, используйте цветные значки. Если в определенных местах документа содержимое управляется динамически, то можно сразу после соответствующих дескрипторов <script > использовать дескрипторы <noscript >. Тогда пользователь сразу увидит, где и что пропущено. При этом комментарии HTML, которые использовались ранее с целью скрыть сценарий от браузеров старых версий, в данном случае использовать не нужно. Их наличие в дескрипторе <noscript> не позволит нормально обработать код HTML. Браузеры других типов Приступая к изучению принципов создания сценариев, необходимо знать, как написать такой сценарий, который бы определял, включен или выключен в браузере режим поддержки JavaScript. Разработчики пытаются составлять такие сценарии, которые могли бы работать в самых разных ситуациях и программных средах. Поэтому сложно представить, что поддерживающий JavaScript браузер не может выполнить сценарий: если в браузере нет интерпретатора JavaScript (или он отключен), то сценарий игнорируется. Существуют, тем не менее, методы определения поддержки Java в JavaScript (например, метод navigator. javaEnabled ()), которые вселяют определенную надежду. Однако логически представить такое довольно сложно. Зачастую пользователям требуется заменить содержимое документа кодом JavaScript при включенном в браузере режиме поддержки JavaScript. Однако только в IE4+ и NN6+ сценарий может заменять стандартный код HTML своим содержимым. Если разрабатываемый программный продукт должен быть совместимым с ранними версиями браузеров, то помните, что весь код HTML в документе используется для отображения страницы, в то время как сценарий является лишь дополнительным средством управления. Сценарии могут использоваться для того, чтобы создавать необычные эффекты при отображении различных ссылок и (будьте осторожны) основного текста. Этот метод применим как при управлении браузерами, поддерживающими сценарии, так и теми, которые сценарии не выполняют. В листинге 13.2 показан небольшой документ, в котором символы комментария HTML использованы для предоставления возможности не поддерживающим сценарии браузерам отображать ссылку на Web-узел Netscape и две строки текста. Если браузер знает, как работать со сценариями, то он узнает дескрипторы <а>и</а>и выполнит операторы, включенные в них. В последнем случае ссылка на узел Netscape на странице не появится, но зато отобразится ссылка на другой Web-узел. Что касается фрагмента основного текста HTML, то сценарий Глава 13. Основы JavaScript 183
окрашивает его в тот же цвет, что и фон документа. Пока цветной текст скрыт в браузере, выполняющем сценарии (равно как и другой текст, сохраненный в документе), пользователь его не увидит. Многим приверженцам HTML такое поведение может не понравиться, поскольку оно противоречит самим принципам HTML. Однако выглядит это довольно забавно. Листинг Л$& Отображеш1в разного содержимого в <html> <head> <titlex/title> </head> <body bgcolor=M#FFFFFF"> <a href="http://www.microsoft.com"> <script type="text/javascript"> <! -- document.writeln("<a href='http://www.dannyg.com'>") //--> </script> Where?</a> <hr /> <script type="text/javascript"> < i -- document.write("Howdy from the script!<font color='#FFFFFF'>") //--> </script>If you can read this, JavaScript is not available. <script type="text/javascript"> document.write("<\/font>") //--> </scriptxbr /> Другие операторы </body> </html> Написание сценариев для разных браузеров Проблему совместимости с разными типами браузеров можно решать по-разному. Все зависит от конкретных целей и используемых типов браузеров. Можно использовать специальные ссылки на страницы со сценариями для поддерживающих сценарии браузеров. Также вы вправе применять для разных классов браузеров различные части приложения. При желании можно реализовать промежуточный вариант. Первым шагом в решении этой проблемы всегда является определение приоритетности браузеров, которыми пользуются посетители ваших Web-страниц. Определение приоритетов Если общая схема разрабатываемого приложения уже вырисовывается, можно заняться определением, браузеры каких классов могут полностью реализовать все основные возможности этого приложения. Например, если на странице проводится предварительная загрузка изображений для ролловеров, то последние доступны только в браузерах NN3+ и ГЕ4+. При использовании возможностей динамического HTML (например, перемещении элементов или динамическом изменении содержимого) по причине различий в объектных моделях документов в NN4, Ш4+ и поддерживающих стандарт W3C DOM браузерах Mozilla, IE5+ и Safari обращайтесь к разным принципам организации сценариев. 184 Часть ///. Объекты документа
В идеальном сценарии рекомендуется сделать оценку особенностей всех тех браузеров, которые используются посетителями страницы. Например, если нужно задействовать возможности DHTML, а пользователи с браузерами NN4 составляют только незначительную часть всей аудитории, то можно создавать сценарий, ориентируясь на объектные модели документов W3C DOM и Ш4+. Советуем просто "махнуть рукой" на остальную аудиторию и использовать DHTML, ориентируясь исключительно на пользователей с браузерами, поддерживающими стандарт W3C DOM. Если задействованные Web-службы регистрируют посетителей страницы, то с помощью такой статистики легко узнать, браузеры каких типов используют посетители узла. Когда основной класс используемых браузеров будет определен, решите, что же делать с теми пользователями, браузеры которых не соответствуют минимальным требованиям для посещения страницы. Например, если узел или страница полностью рассчитаны на использование совместимых со стандартом W3C DOM браузеров, то можно предусмотреть специальный способ выхода со страницы для пользователей с более старыми браузерами. Для этих целей используется наиболее простой формат представления данных, который поддерживает любой браузер от Lynx до IE4 и NN4. Специально для пользователей с браузерами старых типов можно предложить альтернативный упрощенный вариант страницы, управлять которой можно и в этих браузерах. Создание сценария или узла, в котором будет использоваться несколько способов отображения одного и того же содержимого, кажется достаточно простой задачей. На самом деле она требует серьезной и кропотливой работы. Чтобы реализовать подобную задачу и потом поддерживать функциональность такого узла, потребуется время и средства. Опыт подсказывает: какими бы благими ни были намерения дизайнера нового Web-узла, ему все же следует знать, что поддерживать iфункциональнрсть этого узла намного сложнее, чем создавать его. Использование страниц ветвления Если принято решение использовать для просмотра страницы несколько путей (в зависимости от типа используемого пользователем браузера), то разумнее всего в этом случае создать загружаемую по умолчанию страницу ветвления. Для того чтобы направить посетителя по нужному пути, существуют различные приемы. Проще всего переложить ответственность за выбор правильного маршрута просмотра содержимого узла непосредственно на пользователя. В этом случае используются специальные кнопки или ссылки с указанием того, какие требования предъявляются к браузерам для каждого конкретного случая. Такой вариант приемлем для опытных пользователей, разбирающихся в HTML и современных типах браузеров. Проблема, однако, состоит в том, что на сегодня большинство пользователей, работающих с Web, понятия не имеют об уровне поддержки их браузерами HTML и о том, поддерживают ли их браузеры JavaScript. Поэтому для разработчика такой страницы важно автоматизировать процесс выбора пути следования посетителя, насколько это возможно. В индексных страницах ветвления ничего особенного нет. Это не начальная страница, которую можно просматривать, а, скорее, шлюз к нужному Web-узлу. В задачи такой страницы входит перераспределение потока пользователей — все они должна иметь возможность оказаться на начальной странице узла. В листинге 13.3 показано, как выглядит код для такой индексной страницы ветвления. <html> <head> <title>GiantCo On The Web</title> <script type="text/javascript"> window.location = "homel.html" Глава 13. Основы JavaScript 185
</script> <meta http-equiv="REFRESH" content= URL=http://www.giantco.com/home2.html"> </head> <body> <center> <a href="home2.html"ximg src="images/giantcoLogo.gif" height="60" width="12 0" border="0" alt="Go To GiantCo Home Page" /></a> </center> </body> </html> Обратите внимание, что отображаться на странице будет только рисунок, который в листинге заключен в дескриптор стандартной ссылки. В дескрипторе <body> тоже не содержится ничего специфического. Единственный оператор сценария размещается в блоке заголовка. Дескриптор <meta> в этом же блоке используется для того, чтобы автоматизировать процесс навигации для пользователей. Чтобы выяснить, что же будет происходить при использовании этой страницы различными типами браузеров, последние следует разделить на три группы. 1. Браузеры, поддерживающие JavaScript. Несмотря на то, что вся страница целиком может загружаться за считанные секунды (может промелькнуть отображение логотипа компании), это еще не значит, что у браузера при этом мало работы. Он выполняет операторы сценария и загружает в окно документ homel. html. В то же самое время в кэш-память браузера загружается изображение. Это изображение впоследствии будет неоднократно использоваться в документе homel .html, поэтому, с точки зрения оптимизации процесса, все выполняется нормально. Если для управления страницей нужны браузеры только определенных типов или версий, то следует отфильтровать те из них, которые не соответствуют таким требованиям (в которые может потребоваться установка некоторых специальных компонентов). Для того чтобы написать сценарий проверки браузеров, можно воспользоваться соответствующими свойствами объекта navigator (глава 38 на прилагаемом к книге компакт-диске). Тогда те браузеры, которые удовлетворяют минимальным необходимым характеристикам для работы со страницей, смогут перейти к ней, а работа с остальными браузерами будет продолжена на следующем этапе выполнения сценария. 2. Современные браузеры с отключенным или отсутствующим режимом поддержки JavaScript. Некоторые современные браузеры распознают специальный формат дескриптора <meta> как такой, который используется для загрузки URL в текущее окно через указанный интервал времени (в секундах). В приведенном выше листинге 13.3 такой интервал равен нулю. Операторы дескрипторов <meta> выполняются только втом случае, если будут проигнорированы дескрипторы сценария <script>. Поэтому любой браузер, у которого отключен режим поддержки JavaScript, или браузер, распознающий дескрипторы <meta>, последует инструкциям команды обновления, размещенной в этом дескрипторе. Если такой дескриптор на странице используется, следует быть предельно аккуратным с настройками атрибута content^. После указания длительности интервала в секундах вводится точка с запятой и дополнительный атрибут URL. В этом атрибуте задается полная ссылка на адрес URL начальной страницы, в которой сценарии не используются. Помните также, что значение атрибута content должно быть заключено в кавычки. 186 Часть III. Объекты документа
3. Старые графические браузеры, браузеры PDA и Lynx. В последнюю группу входят графические браузеры, которые еще иногда называют "примитивными", а также ряд устаревших браузеров. Lynx, например, рассчитан на работу только с текстовым терминалом VT-100. Такие средства персональной цифровой поддержки PDA (Personal Digital Assistant), как компьютеры серии Palm, оснащены браузерами, рассчитанными на работу с низкоскоростными модемами и небольшими экранами. Если такой браузер не распознает дескриптор <meta> и поэтому не обновляет содержимое страницы, то в этом месте процесс получения доступа к странице для такого браузера будет остановлен. Но поскольку на странице есть изображение, которое используется в качестве ссылки, то пользователь, скорее всего, щелкнет на нем. Таким образом можно перейти к начальной странице, в которой сценарии не используются. Кроме того, следует учесть, что изображение имеет атрибут alt. Браузеры Lynx и PDA (изображения не загружают) отображают текст из описания атрибута alt вместо самого изображения. Пользователи могут, щелкнув на этом тексте, перейти к адресу, указанному в ссылке URL дескриптора. Цвет фона страницы ветвления выставлен по умолчанию не случайно. Если маршрутизация выполняется автоматически и пользователь сразу переходит к начальной странице, то фон страницы меняется от используемого по умолчанию в браузере на фон начальной страницы. Это приводит к неприятному мерцанию экрана. Оставив же на странице ветвления только логотип компании, можно частично решить эту проблему. Одна ссылка - разные страницы Еще один способ фильтрации может быть реализован непосредственно с помощью ссылок. Во всех браузерах, за исключением NN2 и ШЗ, задание ссылки на другой ресурс (если браузер поддерживает сценарии) может выполняться в обработчике события onclick или (если браузер не выполняет сценарии) проводиться в атрибуте href. Особенность заключается в том, чтобы использовать в обработчике события onclick еще один дополнительный оператор return false. Этот оператор отменяет действие атрибута href. Например, если процесс нужно организовать так, чтобы не поддерживающий сценарии браузер при использовании ссылки переходил к одному варианту страницы, а поддерживающий сценарии — к другому, то соответствующий дескриптор ссылки будет выглядеть следующим образом. <а href="nonJSCatalog.html" onclick="location.href= 'JSCatalog.html•/return false">Product Catalog</a> Теперь только те браузеры, которые не поддерживают сценарии, а также NN2 и ШЗ, будут переходить к странице nonJSCatalog.html, в то время как остальные— к странице JSCatalog.html. Определение объектов Последний способ перенаправления посетителя в зависимости от типа используемого браузера известен под названием детектирование объектов. Принцип прост: если данный тип объекта существует в объектной модели браузера, то сценарий для этого объекта можно выполнять. Возможно, самым удачным примером такого детектирования является сценарий, который выполняет предварительную загрузку изображений на странице при работе с новыми браузерами и не делает этого при использовании старых браузеров, которые не интерпретируют изображения как объекты. В этих случаях обычно обработчики событий onmouseover и onmouseout (для обеспечения совместимости), задаваемые в ссылке, вызывают функцию, которая изменяет у соответствующего изображения значение свойства src. Все такие функции могут вызываться любым поддерживающим сценарии браузером. В данном случае нужно, чтобы операторы функции выполнялись только тогда, когда изображения трактуются как объекты. Глава 13. Основы JavaScript 187
В объектных моделях, которые представляют изображения в качестве объектов, эти изображения упорядочены в виде массива, который включен в объект документа document. Массив document. images существует всегда, даже когда у него нулевая длина, что соответствует случаю, когда на странице рисунки не используются. Поэтому, если операторы для предварительной загрузки изображений вставить в условную конструкцию if, которая позволит их выполнять только при наличии массива document. images, то браузеры старых версий просто пропустят эту последовательность команд. function imageSwap(imgName, url) { if (document.images) { document.images[imgName].srс = url; Детектирование объектов рекомендуется проводить в тех случаях, когда наперед известно, как данный объект трактуется браузерами разных типов. В случае с document. images трактовка объектов изображений в разных браузерах практически идентична. Поэтому в данном примере можно уверенно использовать метод детектирования объектов в качестве условия ветвления. Однако такая ситуация имеет место далеко не всегда, и описанный метод следует использовать с большой осторожностью. Например, в Г£4 существует массив объекта документа document, который называется document .all. Он часто используется в ссылках на элементы объектов HTML. Но в NN4 этот массив не используется, а вместо него задействован массив слоев документа в иерархической структуре объектов — layers. Этот массив, в свою очередь, не используется в Г£4. К сожалению, многие авторы сценариев выполняют проверку наличия этих массивов для определения типа браузера. В данном случае тип браузера определяется по достаточно нестабильной характеристике. Это очень нежелательно, поскольку неизвестно, будут ли будущие версии браузеров разных типов иметь подобные различия, или эти различия в них будут нивелированы. К примеру, Opera полностью поддерживает массив document .all. В результате при загрузке старых страниц браузер будет трактоваться как Internet Explorer, а это ни к чему хорошему привести не может. Поэтому детектирование объектов лучше проводить не с целью определения версий браузеров, а, скорее, для определения методов обработки тех или иных объектов, как это делалось в примере с изображениями. Более того, безопасным применение метода детектирования объектов будет только в том случае, когда браузеры всех основных типов (а также стандарт W3C DOM) поддерживают используемый объект. В этом случае можно не опасаться, что в будущем страница не будет работать с браузерами новых версий. К детектированию объектов относят и проверку доступности методов объектов. Ссылка на метод объекта возвращает значение, поэтому такая ссылка может быть использована в условном операторе. Например, приведенный ниже фрагмент кода показывает, как функции передается аргумент, состоящий из строчного идентификатора элемента, который она преобразует в ссылку на объект (в зависимости от использования одного из трех типов объектных моделей документа). function myFunc(elemID) { var obj; if (document.getElementByld) { obj = document.getElementByld(elemID); } else if (document.all) { obj = document.all(elemID); } else if (document.layers) {• obj « document.layers[elemID]; } if (obj) { // операторы управления объектом } } 188 Часть III. Объекты документа ,
В данном случае не имеет значения, какой способ преобразования идентификатора элемента в ссылку на объект используется в определенной версии браузера и операционной системе. Для выполнения преобразования будет использован тот метод или свойство объекта document, который поддерживается браузером. Если браузер поддерживает больше одного свойства, то использовано будет первое доступное из приведенного выше перечня. Если браузер не поддерживает вообще ни одного свойства, то и выполняться ничего не будет. Если в сценарии выполняется проверка наличия того или иного свойства объекта, то разумно предварительно проверить, используется ли в браузере такой объект вообще. Подобная проверка выполняется в том случае, если заранее известно, что данный объект используется не во всех объектных моделях браузеров. Если в условном операторе будет сделана попытка сослаться на свойство или метод несуществующего объекта, это приведет к ошибке выполнения сценария. Чтобы избежать этого, можно каскадно объединить операторы проверки нескольких условий, для чего используется оператор &&, В приведенном ниже фрагменте кода проверяется наличие как объекта document. body, так и его свойства document. body. style. if (document.body && document.body.style) { // Операторы для работы со свойством style объекта body ) В данном случае если объект document. body не существует, то JavaScript второе условие проверять не станет. При использовании условных операторов для проверки существования свойства объекта вы столкнетесь с одним "но". Проблема заключается в следующем: если свойство существует, но его значение равно нулю или пустой строке, то это будет интерпретироваться в ^услов- ном операторе как отсутствие свойства. Чтобы избавиться от этой неприятности, в условном операторе нужно проверить еще и тип возвращаемых данных. В том случае, если такого свойства не существует, типом возвращаемых данных является undefined (неопределенный). Для проверки типа данных используется оператор typeof (глава 32). if (document.doby && typeof document.body.scroll != "undefined") { // Операторы для работы со свойством style объекта body } За детектированием объектов — будущее программирования, поэтому этот прием можно с успехом использовать в сценариях. Методы использования программируемых характеристик в браузерах постоянно расширяются и используется в разных вычислительных приложениях. Нет уверенности в том, что в будущем новые классы и версии браузеров будут так же успешно работать со сценариями, как это делают современные браузеры. Если в сценарии процессы обработки данных организованы на основе проверки функциональных возможностей используемого браузера, то в будущем это избавит от серьезных проблем с совместимостью. В главах 47 и 56, приведенных на прилагаемом к книге компакт-диске, вопросы детектирования объектов рассмотрены более детально. Обеспечение совместимости Каждое новое поколение браузеров имеет новые проблемы совместимости. Старые сценарии будут работать в браузерах новых типов. Хорошо написанный сценарий редко дает сбои при переходе на новую версию браузера. Исключением является, пожалуй, только ситуация с переходом от NN4 к новому программному ядру Mozilla. Но проблемы начинаются не здесь. Все дело в том, что разработчиков быстро привлекают новые возможности браузеров последних версий. При этом они не всегда принимают во внимание, что пользователи далеко не сразу переходят к использованию браузеров новых версий и типов, а продолжают пользоваться старыми. В этих старых браузерах такие дополнительные свойства не доступны. Это нужно помнить. Также следует напомнить о всевозможных недоработках в браузерах "первой волны". Глава 13. Основы JavaScript 189
Можно, конечно, ориентироваться на использование только тех характеристик, которые будут доступны самому широкому кругу пользователей. Однако для этого придется удвоить свои усилия и погрязнуть в море рутинной работы. Поэтому придется выбирать между функциональностью страницы и ее общедоступностью. Если есть желание задействовать какие-то свойства, которые доступны только в браузерах последних версий, значит, пользователей с браузерами более старого образца придется отсеивать и направлять к более простой версии страницы, с которой они смогут работать. Еще один подход состоит в том, чтобы сделать часть страницы доступной для многих (если не для всех типов браузеров), а затем, по мере дальнейшего перемещения "в дебри" страницы, отсеивать тех пользователей, которые работают с более старыми типами браузеров. В этом случае положительным моментом является то, что практически все пользователи смогут в определенных рамках работать со страницей, а для тех из них, кто использует браузеры, скажем, стандарта W3C DOM, она засияет новыми красками. Идеальной страницей считается такая, которая содержит полезную информацию и отображается всеми без исключения браузерами, а также предлагает наиболее совершенные средства навигации и интерактивное содержимое. Сделать подобную страницу весьма сложно. Но даже если это удастся в каком-то конкретном случае, следует продумать способы сортировки пользователей по типам используемых браузеров и заняться поддержкой путей ветвления. Независимо от того, насколько разные технологи используются в браузерах, со временем количество потенциально возможных проблем постепенно уменьшится. Выработанные за прошедшие годы стандарты прошли успешную "обкатку", а потому разработчики окончательно определились с теми спецификациями, которые стоит включать в свои программы или которые лучше избегать. Более того, большинство пользователей спешит воспользоваться последними версиями браузеров, а потому поддержка старых программ становится не столь актуальным занятием. Использование экспериментальных версий браузеров Иногда так случается, что при использовании экспериментальных версий браузеров (так называемых бета-версий) в работе с уже опробованными Web-страницами или узлами возникают ошибки при выполнении сценариев или другие проблемы, связанные с совместимостью. Скорее всего, это является следствием недоработок в браузере. Если сценарий написан грамотно, он должен работать и с последующими поколениями браузеров. Если код не работает корректно, следует что-то делать с браузером. Разработчику данного браузера нужно сообщить об имеющихся недостатках, при этом желательно привести в качестве примера упрощенный код, при управлении которым возникает ошибка. Исключением из правила, когда причиной несовместимости являются не недоделки браузера, а сценарий, может быть конфликт версий NN4 и NN6. Как отмечается в главе 14, сознательные попытки убрать одно из средств NN4 (объект, соответствующий дескриптору <1ауег>) привели к тому, что в бета-версии NN6 (и в конечной версии тоже) многие сценарии, написанные для NN4, перестали выполняться. Взаимодействие авторов страниц с разработчиками браузеров (особенно новых, вроде Mozilla) является взаимовыгодным; оно позволяет изучить политику компании-производителя и учесть возможные ее изменения. Ситуация, при которой в новых браузерах резко отбрасываются какие-то часто используемые средства, крайне маловероятна, но все же возможна. И это следует учесть. Зачастую сложно бывает удержать себя от соблазна идти в ногу с разработчиками новых; версий браузеров. Только не следует при этом забывать, что бета-версия — это еще не конечная версия браузера. Если пользователи бета-версий браузеров при посещении страницы получают ] сообщения об ошибках, то их причиной, скорее всего, являются недоделки в программе браузера. \ 190 Часть ///. Объекты документ*]
Это не вина разработчика страницы. Однако и закрывать на это глаза не стоит. В такой ситуации следует связаться с компанией-разработчиком и выяснить, будет ли конечная версия браузера выдавать ту же ошибку, или эта недоработка в бета-версии будет устранена. Проблемы с браузерами Internet Explorer Как будет подробно рассказано в главе 38 при описании объекта navigator, в сценарии довольно просто определить тип используемого браузера. Но, несмотря на это, реальная картина положения дел с Internet Explorer далеко не ограничивается различием версий. В главе38 показано, что при использовании свойства navigator.appVersion в IE5 для Windows возвращаемое значение соответствует четвертой версии (т.е. точно то же, что и в IE4). До истины, тем не менее, можно докопаться (свойством navigator. userAgent возвращается значение msie 5), но сам этот процесс далеко не так прост, как должен быть, — особенно если требуется определить последующие версии, а не только пятую. Советуем не терять бдительность, следить за появлением новых версий браузеров и использовать методы детектирования объектов. Приложение The Evaluator Sr. В главе 6 в несколько упрощенном варианте было описано приложение The Evaluator Jr., которое позволяет в интерактивном режиме проводить вычисление выражений и проверку объектов. В дальнейшем при изучении базового языка JavaScript и терминологии DOM это приложение будет использоваться часто, поэтому с ним стоит познакомиться поближе. По сравнению с версией, которая описывалась в главе 6, полная версия имеет два важных отличия (рис. 13.1). И тт. ш щщтщт реиншщщццеди Flit Edit Vlow Favorites Tools Holp o^ о айи: />*«* ■&■*«■■■ <»"•* ®^';i' j s ys * The Evaluator Enter an expression to evaluate (QUse NN Code Base Security): Idoaifnent.getElemBntByldfnriyP^.innerHTML Evaluate Results: (0Use tab delimiters) Nov is the time for <EH id-myEM>all</EH> good men to come to the aid of their country. Enter a reference to an object: list .Properties Now is the time for all good men to come to the aid of their county. This is a table caption. This is a positioned element with jjj My Computer Рис. 13.1. Приложение The Evaluator St. Глава 13. Основы JavaScript 191
Во-первых, если в браузере включен режим Code Base Principles и выбрана опция (только в NN4+) Use Code Base Security, то можно проверить некоторые свойства безопасности Netscape. Во-вторых, на странице установлено несколько элементов HTML, которые используются для исследования свойств и методов модели DOM. Как и в упрощенной версии приложения, в данном случае инициализировано 26 глобальных переменных (символы от а до z), которым можно присваивать значения и использовать во всевозможных выражениях. Для использования этого приложения нужно скопировать файл evaluator. html с компакт- диска на жесткий диск и добавить на него соответствующую закладку во всех используемых браузерах. Если необходимо, на странице приложения добавьте дополнительные элементы. Принципы использования приложения The Evaluator в качестве средства отладки описаны в главе 45. Принципы совместимости При создании программного продукта важно знать, какие особенности языка, объектной модели, свойства, методы и обработчики событий доступны в той или иной версии браузеров. В дальнейшем для указания совместимости (или несовместимости) будут использоваться специальные обозначения. Совместимость: WinIE5+, MacIE5+, NN4, Mozl.01+, Safari Знак "плюс" после названия браузера указывает на то, что данный элемент языка впервые был реализован в указанной версии и продолжает поддерживаться в последующих версиях. Знак "минус", наоборот, указывает на отсутствие поддержки в браузере текущей возможности. Мы тестировали сценарии в таких браузерах, как Internet Explorer (для Windows и Mac), Netscape Navigator, Mozilla (включая браузеры на его основе) и Apple Safari. Хорошо было бы, распечатать справочное руководство по JavaScript и объектам браузеров. Соответствующий файл в формате Adobe Acrobat находится в папке приложения А на компакт-диске. В этом руководстве четко указаны все свойства объектов, их методы, обработчики событий и ключи с указанием того, какие свойства в каких типах браузеров поддерживаются. Данное пособие может стать отличным настольным справочником. Особенности языка JavaScript Этот раздел адресован опытным JavaScript-программистам. Новичкам и тем, кто не работал со сценариями, многое может быть непонятно. Данные раздел также предназначен тем, кому часть П показалась слишком легкой. Ниже кратко описаны наиболее современные средства языка JavaScript. ■ Язык написания сценариев JavaScript. Язык используется в среде поддержки узлов (пример — Web-браузер), отображающей объекты, свойства и поведение которых мо-1 гут управляться с помощью операторов, написанных на этом языке. Сценарии выпол- < няются в контексте среды. Среда поддержки узлов управляет тем, как задаются ссылки j на внешние объекты (в результате выполнения операторов языка). В целях соблюде- j ния прав интеллектуальной собственности и для поддержки необходимого уровня.] безопасности Web-браузеры, как правило, не предоставляют прямой (или обеспечива- j ют ограниченный) доступ JavaScript к настройкам браузера, операционной системы] или внешних программ, запускаемых вне браузера. Исключением из этого правила яв- j ляются самые последние браузеры, предоставляющие клиенту более полный доступ] (с разрешения пользователя) с помощью механизма доверительных отношений— зшщИ щенных сценариев (Netscape Navigator) или элементов управления ActiveX (Windows), j 192 Часть III. Объекты документа j
Date Math ReferenceError2 TypeError2 Error Number1 RegExp3 URIError2 JavaScript — язык объектный. Хотя между JavaScript и Java с точки зрения синтаксиса много общего, JavaScript не настолько объектно-ориентирован, как Java. Базовый язык включает в себя несколько встроенных статических объектов, с помощью которых генерируются все рабочие объекты. Объекты создаются путем вызова функции- конструктора встроенного объекта и оператора new. Например, чтобы сгенерировать объект String и получить ссылку на этот объект, нужно сделать следующее. new String ("Hello") В табл. 13.1 приведен список встроенных объектов, с которыми взаимодействуют сценарии. Array1 Boolean EvalError2 Function1 Object1 RangeError2 String1 SyntaxError2 1 — несмотря на то, что объекты и определены в первом стандарте ЕСМА, они стали доступны, только начиная с NN3 и IE3/J2; 2 — определяются в ЕСМА 3, реализованы в Mozl; 3 — определяются в ЕСМА 3, полностью реализованы в NN4 и IE6. ■ Свободное определение типов. Тип данных, которые возвращают переменные, массивы и функции, в JavaScript не предопределяются. Фактически, одна и та же инициализированная переменная может в разных операторах сценария содержать данные самых разных типов (не всегда это хорошо, но всегда возможно). Аналогично массив может содержать значения разных типов. Диапазон встроенных типов данных первоначально ограничен таким набором: • Boolean (значения true или false); • Null; • Number (64-битовые значения двойной точности в формате ШЕЕ 734); • Ob j ect (включая и объект Array); • String; • Undefined. ■ Среда определяет глобальную область. Традиционно браузеры трактуют окно браузера или фрейм как глобальную область задания операторов сценария. При выгрузке документа все глобальные переменные, определяемые в документе, уничтожаются. ■ Глобальные и локальные переменные. Глобальные переменные в Web-браузере обычно декларируются с использованием оператора var, выполняемого при загрузке документа. Такие глобальные переменные доступны для чтения и использования в любом месте документа. Локальные переменные определяются внутри функций (также с использованием оператора var). Однако доступ к этим переменным можно получить только в рамках данной функции. ■ Доступ к свойствам и методам статических объектов JavaScript Некоторые статические объекты позволяют получать прямой доступ к их свойствам и методам. Например, Глава 13. Основы JavaScript 193
все свойства объекта Math используются как математические константы (число я определяется так: Math. PI). ■ Добавление свойств и методов. Для того чтобы добавить объекту свойство, ему следует присвоить значение любого типа. Например, чтобы добавить свойство author строчному объекту myText, можно использовать такую команду. myText.author = "Jane"; Если свойству объекта присвоить ссылку на функцию, то таким образом будет определен новый метод этого объекта. // Описание функции function doSpecial(argl) { // Операторы } // Задание ссылки на функцию по названию метода myObj.handlespecial = doSpecial; // Вызов метода myObj.handleSpecial(argValUe); Внутри самой функции ключевое слово this используется для ссылки на объект, которому принадлежит метод. ■ Объекты наследуют прототипы. Все конструкторы объектов создают рабочие объекты, свойства и методы которых наследуют свойства и методы, определенные в прототипе этого объекта. Начиная с NN3 и ШЗ, в сценариях можно добавлять и удалять некоторые свойства и/или методы, связанные с прототипом статического объекта. Новый рабочий объект наследует свойства текущего прототипа. В сценариях можно свободно переопределять значения свойств прототипа или присваивать различные функции в качестве методов прототипа. Если даже наследованное свойство или метод в текущем рабочем объекте не меняются, то изменения, внесенные в прототип статического объекта, отразятся и на рабочем объекте. (Принцип, согласно которому реализуются ссылки на свойства объекта, состоит в том, что путь к свойству определяется через совпадение имен свойств в наследованном прототипе.) ■ Большое количество операторов. В JavaScript представлены практически все операторы, которые есть в других языках. ■ Управляющие структуры. Во всех версиях JavaScript есть такие конструкции, как if, if-else, for и while. В JavaScript 1.3 (NN4+ и Ш4+), кроме прочего, используется еще и конструкции do-while и switch. В таких итерационных структурах управления процессом выполнения операторов предусмотрено использование операторов break и continue. ■ Функции могут возвращать, а могут и не возвращать значение. В JavaScript есть только один тип функций. Значение функцией возвращается только в том случае, если в ее составе есть ключевое слово return, после которого следует значение, которое должно быть возвращено в качестве результата. Возвращаемые значения могут быть любого типа. ■ Функции нельзя перезагружать. Функции JavaScript, в зависимости от числа определенных переменных-параметров, могут или использовать аргументы, или не использовать их вообще. Все аргументы автоматически записываются в массив arguments, который является свойством объекта функции. Данные переменных-параметров не предопределяются. ■ Значения присваиваются "по ссылке" и "по значению". Функции может передаваться ссылка на объект, предоставляя при этом полный доступ к свойствам и методам 194 Часть III. Объекты документа
объекта, для чтения и записи. Но значения других типов (включая и свойства объекта) могут передаваться по значению, не используя никаких ссылок на объекты. В приведенном ниже примере выполняется очистка текстового поля при обработке события onchange. function emptyMe(argl) { argl.value = ""; } <input type=Mtext" value="Howdy" onchange="emptyMe(this)"> В следующем примере ничего не происходит. function emptyMe(argl) { argl = ""; } <input type="text" value="Howdy" onchange="emptyMe(this.value)"> Локальная переменная (argl) просто заменяет значение с "Howdy" на пустую строку. ■ Способ обработки ошибок зависит от используемой версии JavaScript В браузерах NN2 и ШЗ способы отслеживания ошибок не предусмотрены. Отслеживание ошибок в NN3, NN4 и ТЕЛ выполняется в рамках объектной модели Web-браузера. JavaScript, используемый в Ш5, Mozl и Safari имеет операторы try-catch и throw, а также встроенные объекты для обработки ошибок, которые являются независимыми от среды. ■ Управлять памятью с помощью сценариев нельзя. Среда управляет распределением памяти. Разные браузеры делают это по-разному. ■ Пробелы во внимание не принимаются. Пробелы и символы табуляции можно использовать для разделения лексических единиц (ключевых слов, идентификаторов и т.д.). ■ Символ окончания строки обычно трактуется как разделитель операторов. За очень редким исключением, JavaScript автоматически при синтаксическом анализе вставляет точку с запятой (используется для разделения операторов) в местах с символами окончания строки (например, символы возврата каретки и разрыва строк). Разделитель в виде точки с запятой используют между двумя операторами в одной строке исходного кода. Далее символы, используемые в строках, не должны содержать символов возврата каретки (но символ перехода на новую строку (\п) использоваться может). Вперед, к объектным моделям документов! При работе с Web-страницами базовый язык является только маленькой частью того, что нужно знать. Также вы должны знать и понимать принципы организации объектных моделей документа в браузерах разных типов. Этому будет посвящена следующая глава. Глава 13. Основы JavaScript 195
Основы объектной модели документа не всяких сомнений, в короткой истории развития браузеров, поддерживающих сценарии, самым захватывающим и запутанным процессом является эволюция объектных моделей документов. Первая такая модель была предложена в браузере NN2. С того времени и вплоть до разработки четвертого поколения браузеров исходная объектная модель приобрела много новых характеристик, общих для браузеров разных типов, а также ряд средств, которые являются просто уникальными с точки зрения первых браузеров как Netscape Navigator, так и Internet Explorer. По сравнению с исходными объектными моделями, в последующие их версии постоянно вносились новые изменения, что добавило головной боли разработчикам страниц— ведь сценарии нужно составлять так, чтобы они могли использоваться в самых разных типах браузеров. Свет в конце туннеля появился, когда консорциум World Wide Web Consortium (W3C) приступил к разработке стандарта объектной модели документа (DOM— Document Object Model). Новые подходы позволили по-новому взглянуть на проблему. В стандарте предусмотрены альтернативные способы адресации к объектам документа. В этой главе описываются различные объектные модели. Будут проанализированы перспективы их использования, а также преимущества и недостатки их использования для создания Web-приложений. Но перед тем, как приступить к изучению специфических аспектов объектных моделей, рассмотрим ту роль, которую объектные модели играют при создании сценариев и приложений. Иерархическая структура объектной модели В руководстве по основам программирования в части П изложены основные идеи, определяющие в поддерживающих сценарии браузерах иерархию объектов документа. В других программных средах, по сравнению с использующими JavaScript
браузерами, такая иерархия имеет более важное значение. В JavaScript, например, нет никакой необходимости при написании сценария знать, что такое классы, наследование и экземпляры объектов. Тем не менее, полностью игнорировать иерархическую организацию элементов не получится, поскольку в сценарии как минимум нужно будет использовать ссылки на объекты. А для этого необходимо знать, как они соотносятся друг с другом. Упомянутые объекты не являются объектами JavaScript в полном смысле этого слова. Это самые настоящие объекты браузера: для того, чтобы их запрограммировать, используется JavaScript. Однако те создатели сценариев, которые для решения тех же задач и программирования объектов документа привлекает браузеры Microsoft Internet Explorer, могут также использовать и язык VBScript. Формально JavaScript по отношению к документу является внешним средством, используемым для обработки данных разных типов и прочих объектов. Поэтому следует четко понимать, что между документом и базовым языком есть принципиальная разница. Это важно для анализа задач, связанных с совместимостью разных типов браузеров. Иерархия и структурная схема объектов Программист должен знать иерархическую структуру организации объектов в первую очередь потому, что она применяется в сценарии при задании ссылок на объекты, содержащиеся в окне браузера. Такая иерархическая структура играет роль схемы, следуя которой сценарий точно определяет нужный объект. Рассмотрим такой пример. Два друга — Петров и Васечкин — находятся в классной комнате. Полуденное солнце уже находится с западной стороны, и в комнате начинает припекать. Петров просит Васечкина: "Открой, пожалуйста, окно", — указывая при этом на то окно, которое нужно открыть. Если провести параллель с программированием, то это будет аналогично команде объекту (независимо от того, откроет Васечкин окно или нет). По сравнению с программированием, такой пример человеческого общения имеет много преимуществ. Во- первых, еще до того, как Петров высказал свою просьбу, уже по его взгляду Васечкин смог бы догадаться, что его о чем-то попросят. Во-вторых, язык жестов является достаточно красноречивым для того, чтобы безошибочно и однозначно указать на нужное окно. Если теперь представить, что директор школы из своего кабинета по общешкольной системе оповещения попросит: "Пожалуйста, откройте окно", то каждый будет думать, что обращение направлено не к нему, и окно так и не будет открыто. Если же директор скажет: "Петя Васечкин из 312 комнаты, открой, пожалуйста, среднее окно с западной стороны", то Васечкин вряд ли посмеет ослушаться. Теперь посмотрим, как описанная процедура выглядела бы в JavaScript (с использованием уже знакомого точечного синтаксиса, описанного в главе 4). Вызов нужного объекта через систему ссылок начинается с самого высокого уровня и затем, проходя последующие уровни в иерархии объектов, производится все более точная локализация объекта. Высшим уровнем является кабинет директора. классЗ12.Васечкин.Петя Можно также, продолжая аналогию, сказать, что тот запас знаний и навыков, которые позволяют Пете открыть окно, является методом Пети. Поэтому полная ссылка на Петю и его метод выглядит так. классЗ12.Васечкин.Петя.открытьОкно() На этом работа по составлению ссылки еще не завершена. Чтобы использовать метод, ему нужно указать параметры. Эти параметры определяют, какое именно окно следует открыть. В данном случае речь идет о среднем окне с западной стороны класса 312. На языке объектных ссылок получим. класс312.западнаяСторона.среднееОкно Глава 14. Основы объектной модели документа 197
Эта ссылка является параметром для метода Пети от крыть Окно (). Вся команда целиком выглядит так. класс312.Васечкин.Петя.открытьОкно(класс312. западнаяСторона.среднееОкно) Теперь представьте, что нужно отдать такое распоряжение не из кабинета директора, а из резиденции Президента страны. Представляете, какими длиннющими при этом будут ссылки? Полная ссылка на метод Пети открытьОкно О с указанием окна, которое нужно открыть, составит не один десяток уровней. Мораль сей басни такова — чем меньше объектов, которыми управляют программы, тем легче задавать на них ссылки. Для клиента JavaScript диапазон возможного расширения программной среды ограничен браузером. Другими словами, любой объект в JavaScript может быть задействован в рамках приложения браузера. За некоторым исключением, в сценариях доступ к аппаратному обеспечению компьютера, операционной системе, другим приложениям, рабочему столу и всем прочим программным средствам за пределами браузера не предоставляется. Структура объектной модели документа На рис. 14.1 показана упрощенная иерархическая структура объектов документа, которая лежит в основе всех поддерживающих сценарии браузеров. Вершиной всей структуры является объект окна window. Все объекты, которыми можно управлять в JavaScript, располагаются в окне браузера. В показанной иерархической структуре каждый объект принадлежит определенному иерархическому уровню. Объекты, отображенные в одной строке, принадлежат одному иерархическому уровню по отношению к объекту window. Связи между объектами показаны в виде соединяющих их линий. Объекты на более высоком уровне содержат в себе те объекты, которые расположены ниже и соединены с первыми линиями. Так, объект окна window содержит в себе объект документа document. В свою очередь, объект документа document содержит объект формы form. Объект формы содержит в себе много различных элементов управления формы, которые также являются объектами. window frame self top parent history link XL- text textarea password document location form ZT anchor radio button checkbox select reset option submit Рис. 14.1. Общая схема иерархической структуры объектов Модель, изображенная на рис. 14.1, продемонстрирована с целью обрисовать в общих чертах базовые элементы Web-страницы, для которых пишутся сценарии. В современных типах 198 Часть III. Объекты документа
браузеров используются более сложные иерархические структуры. Однако "фундамент" остается неизменным. Чтобы такая иерархическая объектная модель не казалась чем-то ужасным, следует написать с ее использованием несколько сценариев (в процессе работы с такими моделями они станут вполне привычными и понятными). Совсем не обязательно помнить конкретные детали (свойства, методы или обработчики событий) каждого объекта. В конце концов, под рукой всегда найдется справочник. Создание объектов в документе Большинство объектов, создаваемых браузером, генерируются, когда документ с кодом HTML загружается в браузер. Похожий код HTML используется для создания в памяти поддерживающих JavaScript браузеров объектов ссылок, анкеров и элементов ввода данных. Эти объекты размещаются в памяти независимо от того, будут они использоваться в дальнейшем или нет. Единственное отличие в таком коде HTML состоит в том, что дополнительно задействуются некоторые специфические для JavaScript атрибуты. В основном, такие атрибуты используются для организации ответной реакции элементов страницы на действия пользователя. С помощью JavaScript программируется последовательность операций, выполняемых при этом сценарием. Создание объектов также выполняется с помощью специального кода документа HTML. Кроме того, здесь же определяется поведение создаваемых объектов и выполняемые ими задачи. Следует иметь в виду, что объекты создаются согласно очередности их загрузки. Если используется многооконная среда, то объекты одного подокна не взаимодействуют с объектами другого подокна до тех пор, пока оба эти подокна не загружены. На этой почве у многих программистов и создателей сценариев для многооконных сред возникают серьезные проблемы (детальнее об этом — в главе 16). Свойства объектов Обычно свойства определяют текущие настройки объекта. Зачастую эти настройки вполне понятны — например, описывающие состояние элемента управления (активен или нет). Но иногда в них содержится информация более абстрактного характера, например, сведения о действиях или методах предоставляемой формы. Большинство свойств объектов устанавливаются с помощью атрибутов дескрипторов HTML при создании этих объектов. Свойством может быть слово (например имя) или число (например размер). Если в документе HTML некоторые атрибуты не определяются, то браузер присваивает этим атрибутам и соответствующим свойствам JavaScript значения, используемые по умолчанию. При использовании имен свойств в операторе сценариев следует иметь в виду, что они чувствительны к состоянию регистра. Другими словами, имеет значение, строчные или прописные буквы использованы в имени. Таким образом, если в сценарии определено имя bgColor, то вводить его нужно именно так, как оно задано вначале — с учетом прописных и строчных букв. Но при начальной установке свойств атрибутов HTML состояние регистра в имени атрибута во внимание не принимается. С этой точки зрения, описания <body bgColor= "white"> H<body bgcolor=Mwhite" >, устанавливающие значение свойства bgColor, являются эквивалентными. Хотя XHTML не выдвигает жестких требований к регистру символов, которыми вводятся дескрипторы и имена переменных, большинство браузеров чувствительны к регистру символов, независимо от того, назначено атрибуту doc type значение HTML или XHTML. У каждого свойства есть свой статус чтения/записи. Некоторые свойства могут только считываться. Другим свойствам можно присваивать еще и новые значения. Например, чтобы Глава 14. Основы объектной модели документа 199
текстовому объекту в качестве значения присвоить новый текст, свойству объекта value присваивается такая строка. document.forms[0]phone.value = "555-1212" Если объект размещен в существующем документе (это значит, что код HTML загружен в документ), то этому объекту можно добавить несколько новых свойств. Поступают так в тех случаях, когда с объектом нужно связать определенные данные, которые будут использоваться в дальнейшем в сценарии. Для того чтобы добавить объекту новое свойство, достаточно просто указать его при присвоении значения этому свойству. document.forms[0]phone.delimiter = "-" Каждое такое свойство, добавленное к объекту, будет доступно до тех пор, пока документ загружен в окно, а сценарий не переопределит данный объект. Тем не менее, следует иметь в виду, что при перезагрузке страницы все добавленные к объекту свойства обычно удаляются. Специально для тех, кто имеет опыт в объектно-ориентированном программировании Несмотря на то, что в иерархии приведенной объектной модели прослеживается принцип классовой организации, многие традиционные для такого объектно-ориентированного подхода аспекты к данной модели неприменимы. Исходная иерархия объектов документа JavaScript является иерархией структуры, а не иерархией наследования. Ни один из объектов, расположенных на более низких ступенях иерархической структуры, не наследует свойства объектов, расположенных на более высоких уровнях. Между объектами в данном случае, в отличие от структур с иерархическим наследованием, сообщения автоматически не передаются. Поэтому задействовать метод объекта окна, отправив последнему сообщение с помощью объекта документа document или формы, не удастся. Все ссылки на объекты придется делать в явном виде. Предопределенные объекты документа генерируются при загрузке кода HTML, содержащего описания этих элементов, в браузер. В браузерах самых первых версий после загрузки документа, изменять многие свойства, методы и обработчики событий не представляется возможным. В главе 33 речь пойдет о том, как создать собственные объекты. Однако такие объекты на странице определяют только те отображаемые элементы, которые задаются средствами HTML, аплетами^ауа или другими программными методами. Наследование становится актуальными, как показано далее в этой главе, при использовании 'объектной модели стандарта W3C. В этом стандарте иерархия имеет более общий характер. Такая система взаимосвязи объектов позволяет наряду с HTML использовать и XML. Тем не менее, иерархические структуры объектов HTML, описываемые в данном разделе, могут быть успешно задействованы и в браузерах стандарта W3C DOM. Методы объекта Методом объекта называется команда, которую сценарий дает объекту. Некоторые методы возвращают значение, хотя это и не обязательно. Более того, некоторые объекты вообще не имеют методов. В большинстве случаев вызов в сценарии метода объекта подразумевает выполнение некоторых действий. Иногда такие действия являются вполне конкретными и понятными (например, если изменяется размер окна). Бывает, что выполняются и более замысловатые процедуры (как при сортировке в памяти массива). Все методы при указании ссылки на них после своего имени требуют введения скобок; в ссылках они всегда задаются в конце выражения. Если метод используется вместе с параметрами, эти параметры указываются в скобках после имени метода. Если параметров несколько, они друг от друга отделяются запятой. 200 Часть ///. Объекты документа
Методы для каждого объекта предопределяются в используемой объектной модели. Уже существующим объектам после загрузки их кода HTML в документ можно присваивать новые методы. Для этого в сценарии документа (другого окна или подокна, доступного документу) следует описать функцию JavaScript, а потом присвоить эту функцию в качестве имени нового метода объекта. В приведенном ниже примере функция fullscreen () вызывает один из методов объекта window. При этом задействовано два метода объекта window. Функция maximize () объекта window определяется в результате задания ссылки на функцию новому методу window.maximize () объекта окна. После этого обработчик события кнопки сможет напрямую вызвать этот метод. Сценарий рассчитан на использование браузеров, начиная с четвертой версии и выше. // Определение функции function fullscreen() { this.moveTo(0,0); this.outerWidth = screen.availWidth; this.outerHeight = screen.availHeight; } // Присвоение функции свойству window.maximize = fullscreen,- <!-- Вызов нового метода --> <input type="buttort" value="Maximize Window" onclick="window.maximize()" /> Обработчики событий объектов В обработчике события объекта определяется, как должен реагировать объект на соответствующее событие, инициированное пользователем (например, щелчок на кнопке) или браузером (например, окончание загрузки документа). В самых первых версиях браузеров, поддерживающих JavaScript, обработчики событий определялись как дополнительные атрибуты в дескрипторах HTML. Они состоят из имени атрибута, после которого следует знак равенства (используемый в качестве оператора присвоения) и строки, содержащей оператор сценария или имена функций, которые следует выполнить при наступлении события (глава 5). Обработчики событий могут иметь и другой вид. В браузерах NN3+ и ГЕ4+ обработчики событий используют соответствующие методы своих объектов, и каждый такой обработчик события является свойством этого объекта. Обработчики событий как методы Рассмотрим объект кнопки. У этого объекта есть очень важный обработчик события onclick. При щелчке объект кнопки запускает этот обработчик события. В результате будут выполнены те команды и функции JavaScript, которые присвоены обработчику события при его описании в документе HTML. <input type="button" name="clicker" value="Click Me" onclick="dolt ()" />~ Как правило, под событием "щелчок " подразумевается ситуация, когда пользователь щелкает мышью на кнопке страницы. В браузерах NN3+ и Ш4+ обработчик события можно вызывать из сценария так, как если бы это был самый обычный метод объекта. document.formName.clicker.onclick(); Глава 14. Основы объектной модели документа 201
Следует обратить внимание на следующий факт: если обработчик события вызывается в качестве метода объекта, то имя этого обработчика события состоит исключительно из строчных букв независимо от способа определения атрибута этого обработчика события в дескрипторе HTML. Это обязательное условие. Такое использование обработчика события принципиально отличается от использования метода для эмулирования действия для события. Например, представим, что страница содержит три текстовых поля, одно из которых имеет обработчик события onf ocus, который отвечает за активизацию поля. Если в этом поле щелкнуть мышью или перейти к нему с использованием клавиатуры, то поле активизируется и будет задействован обработчик события onf ocus. Но даже если поле неактивно, обработчик события onf ocus можно вызвать, щелкнув на кнопке, которая и вызовет обработчик события в качестве метода объекта текстового поля. document.formName♦fieldName.onfocus(); В данном случае поле не активизируется. Но с помощью сценария метод поля onf ocus () все же будет вызван. В результате использования обработчика события в качестве метода появляется возможность задания последовательности действий, выполняемых обработчиком события, в функции, имеющей имя обработчика события. Например, вместо того чтобы описывать обработчик события onload в дескрипторе документа <body>, достаточно описать следующую функцию. function onload() { Команды функции ) Это очень полезная возможность, особенно если нужно задействовать обработчики событий в сценариях для браузеров NN3, Ш4 или более поздних версий. В случае использования Netscape Navigator 2 или Internet Explorer 3 в сценарии изменения вносить не придется. Обработчики событий как свойства Несмотря на то, что обработчики событий обычно определяются в дескрипторах объектов HTML, при использовании браузеров NN3+ и ЕЕ4+ существует возможность изменять или присваивать обработчики событий объектам в полной аналогии со свойствами, которые также могут изменяться и присваиваться. Значение свойства обработчика события внешне похоже на описание функции. Например, рассмотрим следующее описание в HTML. <input type="textM name=Mentry" onfocus="doIt()" /> Значением свойства объекта onf ocus () (все буквы строчные) является function onfocus() { dolt(); } Существует возможность присвоить обработчику события совершенно другую функцию; при этом свойству присваивается ссылка на данную функцию. Скобки, являющиеся частью определения функции, в ссылке не используются. Более подробно метод присвоения объектам свойств в качестве значений функций рассматривается в главе 33. Если у вас возникает ситуация, когда в зависимости от отображаемых данных текстовое поле при активизации ведет себя иначе, то обработчику события поля можно присвоить другую функцию. Выполняется эта задача с помощью оператора определения функции. function doSomethingElse() { Команды функции } Вы можете присвоить эту функцию полю с помощью оператора присвоения. document.formName.entry.onfocus = doSomethingElse; 202 Часть III. Объекты документа
Поскольку используется функция JavaScript, в ее имени следует строго соблюдать строчные и прописные буквы. В версии NN4 имена обработчиков событий вводятся в так называемом слитном формате (interCap). Тем не менее, во избежание проблем при использовании браузеров других версий в именах обработчиков событий, используемых в качестве свойств объектов, рекомендуется использовать только строчные буквы. Помните: как и для многих настраиваемых свойств объектов, которые в явном виде на странице не проявляются, изменения, вносимые в свойства обработчиков событий, при перезагрузке документа не восстанавливаются. Поэтому подобной практики лучше избегать и вносить описанные изменения только в крайних случаях: например, когда обработчики событий вызываются в сценарии в качестве методов. Если в вашем сценарии новые объекты элементов создаются динамически, то вы можете назначить этим объектам обработчики событий с помощью свойств. Например, следующий код написан в соответствии со спецификацией W3C DOM — он создает новую кнопку и назначает в качестве обработчика событий onclick этой кнопки некую функцию, определенную далее в сценарии. var newElem = document.createElement("input"); newElem.type = "button"; newElem.value = "Click Here"; newElem.onclick = dolt; document.forms[0].appendChild(newElem); Таким образом, обработчики событий могут использоваться и в качестве методов, и в качестве свойств объектов. В следующих главах при описании свойств и методов различных объектов этот факт специально подчеркиваться не будет. Тем не менее, можно быть уверенным, что такая техника успешно применяется ко всеми объектами JavaScript, имеющим обработчики событий, начиная с браузеров Netscape Navigator 3 и Internet Explorer 4. Разнообразие объектных моделей В процессе эволюции браузеров, поддерживающих сценарии, начиная с NN2 и ГЕЗ и заканчивая ГЕ5.5 и Mozilla, было разработано шесть (именно шесть!) различных типов объектных моделей. Даже в самом простом случае, когда создаваемая страница рассчитана на использование только одного типа браузеров, будут задействованы, скорее всего, элементы и объекты разных объектных моделей. Изучение различных объектных моделей — занятие весьма поучительное для начинающих программистов. Освоение объектной модели последней версии браузера не займет много времени. Это простой путь. Однако потом, как правило, при использовании браузеров более старых версий, возникают серьезные проблемы с использованием программных продуктов, написанных в расчете на эту объектную модель. Поэтому стоит потратить время на то, чтобы ознакомиться с историей развития объектных моделей, начиная с самой первой версии, и понять главные их особенности. В табл. 14.1 перечислены разные типы (или семейства) объектных моделей (в хронологическом порядке их появления) вместе с указанием типа браузеров, в которых эти модели используются. Позже в этой главе будут описаны критерии, по которым выбирается оптимальная для того или иного случая объектная модель. Базовая объектная модель В первом поддерживающем сценарии браузере Netscape Navigator 2 использовалась достаточно простая объектная модель. На рис. 14.1 представлены объекты этой модели, которыми управляли сценарии. Иерархическая структура начинается с объекта окна, ниже расположены Глава 14. Основы объектной модели документа 203
документ, формы и их элементы. При этом документ, определяющий основное содержимое страницы, практически не программируется. Объектами (с их свойствами, методами и обработчиками событий) являются только такие интерактивные по своей природе элементы, как ссылки, текстовые поля, кнопки и т.д. Тип объектной модели Версия браузера Базовая объектная модель NN2, NN3, IE3/J1, IE3/J2, NN4, IE4, IE5, IE5.5, IE6, Moz1, Safari 1 Основная модель, NN3, IE3.01 (только для Mac), NN4, IE4, IE5, IE5.5, IE6, Moz1, Safaril поддерживающая изображения Расширенная модель NN4 NN4 Расширенная модель IE4 IE4, IE5, IE5.5, IE6 (для использования некоторых характеристик во всех версиях нужна операционная система Win32) Расширенная модель IE5 IE5, IE5.5, IE6 (для использования некоторых характеристик во всех версиях нужна операционная система Win32) W3C DOM (уровней I и II) IE5 (частично), IE5.5 (частично), IE6 (частично) Moz1 (практически полностью), Safari (частично) Использование объектной модели открыло широкие возможности, которые были не доступны ранее и на то время казались чем-то исключительным. Поскольку сценарии могли управлять значениями элементов форм, последние предварительно проверялись клиентом на корректность введенных пользователем данных. Если страница содержит сценарии, выполняющие определенные расчеты, то результаты таких вычислений и другие данные можно отображать в редактируемых текстовых полях. Дополнительные объекты (window, history и location), которые выведены за рамки документа, позволяю^ получить доступ к некоторым достаточно простым свойствам браузера, выполняющего загрузку страницы. Наиболее общим с этой точки зрения является объект navigator, свойства которого позволяют узнать тип и версию браузера. Когда появился Internet Explorer 3, Netscape Navigator 2 отошел на второй план. Несмотря на то, что уже достаточно широко использовалась экспериментальная версия Netscape Navigator 3, в ШЗ применялась базовая модель из NN2 (и еще одно свойство объекта window, представленное в NN3). Поэтому если судить по объектной модели, то NN2 и ШЗ находятся на одном уровне, хотя и имеют разную нумерацию версий. На этом непродолжительном этапе развития браузеров между Microsoft и Netscape существовала практически полная гармония — хотя и на уровне достаточно простых объектных моделей. Базовая объектная модель, поддерживающая изображения Практически сразу после выхода в свет ШЗ компания Netscape представила завершенную версию Netscape Navigator 3. Объектная модель этого браузера базировалась на объектной модели предыдущей версии. В старые объекты были добавлены новые свойства, методы и обработчики событий. Это относится в первую очередь к объекту window. В сценариях стало возможно обращаться к аплетам Java как к объектам. Но самым важным усовершенствованием стало создание объекта изображения Image и поддержка массивов объектов изображений, размещенных в объекте документа document. 204 Часть III. Объекты документа
В NN3 большинство свойств объектов изображений были доступны только для чтения. Как правило, значения этих свойств устанавливались в атрибутах дескриптора <img>. Одно свойство объекта изображения можно было изменять и после загрузки страницы — речь идет о свойстве src. Теперь сценарии в области фиксированных размеров могли выполнять предварительную загрузку изображений. Хотя эти новые объекты изображений не имели своих собственных обработчиков событий, их можно было размещать внутри ссылки (для которой задается обработчик события onmouseover и новый обработчик onmouseout). Последнее позволяет изменять изображения на другие объекты при наведении на них указателя мыши. Таким образом, страница становилась более интересной с точки зрения ее оформления. По мере того, как разработчики страниц знакомились с возможностями JavaScript, популярность последнего росла. Однако возникала серьезная проблема, связанная с тем, что предварительная загрузка изображений, описанная выше и успешно используемая в NN3, не срабатывала в браузере ШЗ. Разумеется, несложно написать такой сценарий, который при использовании ШЗ не будет вызывать ошибки (глава 12). Однако при этом не будут задействованы и новые возможности по изменению изображений, доступные в NN3. Последнее многих разочаровало. Также следует учесть и то, что достаточно большое количество пользователей еще не перешли с NN2 на NN3. Если, к тому же, принять во внимание тот факт, что вШЗ.01 (второй выпуск браузера IE3 для Мае) использовались управляемые сценариями объекты изображений, то можно было легко запутаться во всем этом. Несмотря на такие серьезные проблемы с совместимостью, объектная модель, использованная в NN3, стала основой для разработки последующих объектных моделей документа. За редким исключением, любой код, написанный для этой модели, будет выполняться во всех браузерах, начиная с NN3 и IE4 вплоть до самых последних версий браузеров обоих производителей. Упомянутые редкие исключения касаются, в основном, объектной поддержки апле- тов Java в версиях Ш4+, рассчитанных на отличные от Windows операционные системы. Расширенная модель NN4 Следующим браузером, представленным на суд общественности, стал NN4. Внесенные изменения в уже существующие объекты добавили больше свободы для разработчиков сценариев. Была предусмотрена возможность с помощью свойств объекта screen перемещать и изменять размеры окна браузера (хоть на весь экран). Две новые концепции существенно расширили представление об объектной модели — это расширенная модель событий и объект layer. Модель перехвата событий В NN4 был существенно расширен диапазон обрабатываемых событий. События, связанные с действиями пользователя на клавиатуре, и новые добавленные события, относящиеся к мыши (onmousedown и onmouseup), значительно расширили возможности сценариев. Все эти события обрабатывались так же, как в предыдущих объектных моделях, где обработчики событий, как правило, присваивались в виде атрибутов дескрипторов соответствующих элементов (хотя обработчики событий можно использовать в операторах сценария в качестве свойств). Для того чтобы в полной мере реализовать потенциал динамического HTML в объектной модели NN4, модель событий была существенно доработана. Главная идея, положенная в основу обработки событий, выглядит так: когда пользователь выполняет действия над объектом (например, щелкает на кнопке формы), то текущее событие передается этому объекту (кнопке) в соответствии с иерархической структурой документа (начиная с самого высшего ее уровня). Если используется несколько объектов и один и тот же общий обработчик события, то вместо присвоения этого обработчика события каждому элементу Глава 14. Основы объектной модели документа 205
в отдельности, удобно было бы перехватить событие заранее, на самом высшем уровне иерархической структуры документа — на уровне window или document. По умолчанию в Netscape Navigator 4, как и во всех предыдущих версиях браузеров, события из вершины иерархической структуры отправлялись непосредственно к объекту назначения. Однако в объектах window, document и layer была предусмотрена возможность использования режима перехвата событий. После перехвата событие может использоваться на высшем уровне, обработано перед отправкой объекту назначения или перенаправлено к другому целевому объекту. Независимо от того, используется или нет режим перехвата событий, в NN4 для каждого события создается объект event (в данном случае первая буква "е" — строчная, чтобы отличить этот объект от статичного объекта Event). В этом объекте хранятся свойства, которые подробно описывают каждое конкретное событие (как, например, символ клавиши, нажатой на клавиатуре, или расположение на странице указателя мыши при щелчке). Поэтому каждый обработчик события перед началом обработки внимательно исследует свойства объекта event. Объект Layer Самым существенным новшеством в объектной модели NN4 стало, пожалуй, использование принципиально нового объекта, отвечающего абсолютно новому в HTML элементу — элементу слоя layer. Объект слоя layer является контейнером, в котором может содержаться собственный документ HTML, располагающийся на фоне главного документа. С помощью сценария его можно перемещать, изменять размеры и скрывать. Этот новый элемент на первых этапах позволял выполнять наложение элементов HTML на странице. Для того чтобы в иерархической структуре документа для объекта layer нашлось место, он был помещен в объект документа. В результате объект document приобрел новое свойство document. layers. Данное свойство является массивом объектов layer документа. В массиве отображаются только объекты layer первого уровня текущего объекта document. Для ссылки на объект слоя layer в основном документе подойдет любая из следующих команд. document.имяСлоя document.layers[n] document.layers[имяСлоя] У каждого ббъекта слоя layer есть собственный объект документа document, поскольку каждый объект layer в случае необходимости может выполнять загрузку внешнего документа HTML. Таким образом, если сценарию нужен доступ, скажем, к элементу формы внутри объекта layer, ссылка будет выглядеть так. document.имяСлоя.document.forms[0]... Если объект layer содержит внутри себя очередной слой, ссылка станет длиннее. document. имяВнешнегоСлоя, document. имяВнутреннегоСлоя. document. forms[0]... Как позиционируемый элемент, объект слоя layer имеет целый ряд свойств и методов, позволяющих сценариям перемещать его, скрывать и снова отображать, а также изменять порядок расположения в стеке. Недостатком для Netscape Navigator является то, что дескриптор <layer> в стандарт HTML 4.0 включен не был; потому используется он только в NN версии 4 (в NN6 и более поздних версиях от его использования отказались). Это же замечание относится и к сценариям, использующим объект слоя и ссылки на него. В NN4, с другой стороны, для позиционируемых элементов в незначительной степени была реализована поддержка спецификации HTML 4.0 и таблиц стилей CSS. Причина состоит в том, что таблицы стилей можно задавать (вместе с указанием расположения на странице и прочими атрибутами) элементам div 206 Часть III. Объекты документа
и span, также используемым в NN4. Позиционируемый элемент div или span трактуется Netscape Navigator, с точки зрения сценария, практически эквивалентно объектам layer. Таким образом, даже если с помощью HTML можно заставить браузер выполнить поставленную задачу с использованием элементов div и span (не всегда успешно, поскольку в NN4 и IE4 существуют различия в настройках позиционирования элементов), написание сценариев для NN4 подразумевает использование синтаксиса, аналогичного тому, который используется для объектов слоев. Этот синтаксис отличается от используемого в ГЕ4 для CSS. Расширенная модель IE4+ Браузером Ш4, выпущенном через несколько месяцев после NN4, компания Microsoft начала новый этап в развитии браузеров. Основные изменения касались способа отображения элементов HTML, поддержки в сценариях CSS-стилей и новой модели событий. Некоторые другие усовершенствования были доступны только при использовании 32-разрядной операционной системы Windows. Объекты элементов HTML Самое серьезное новшество объектной модели состоит в том, что теперь все элементы HTML стали объектами, которыми можно управлять из сценария. Microsoft предложила массив document .all (так называемую библиотеку объектов). Этот массив содержит ссылки на все элементы в документе, независимо от места размещения этого элемента в иерархии объектов. Если атрибуту ID элемента присвоен идентификатор (имя), то ссылку на этот элемент можно делать по его значению (в данном случае идентификатор — ИдентификаторЭлемента). document. all. ИдентификаторЭлемента В большинстве случаев полную ссылку из массива document.all можно упростить и использовать только идентификатор элемента. Каждый объект элемента имеет совершенно новый набор свойств и методов, предоставляющих создателям сценариев такие полномочия по управлению содержимым документа, которые им и не снились. В табл. 14.2 приведен список свойств и методов, которыми в совокупности обладают элементы HTML в ГЕ4 (свойства, после имен которых идут квадратные скобки, являются массивами). Свойства , all[] children [] className document filters [3 id innerHTML innerText isTexEdit Методы click() contains() getAttribute() insertAdj acentHTML() insertAdj acentText.() removeAttribute() scrollIntoVeiw() setAttribute 0 Глава 14. Основы объектной модели документа 207
Окончание табл. 14.2 Свойства Методы lang language offsetHeight offsetLeft offsetParent offsetTop offsetWidth outerHTML outerText parentElement parentTextEdit sourceIndex style tagName title Детальное описание приведенных в табл. 14.2 свойств и методов можно найти в главе 15. Однако некоторые важные характеристики, будут описаны в этой главе. Получить доступ к содержимому документа для чтения и записи можно с помощью четырех свойств: innerHTML, innerText, outerHTML и outerText. В результате отпадает необходимость в использовании текстовых полей для отображения результатов вычислений в сценариях. Стало возможно редактировать содержимое абзацев и таблиц непосредственно в процессе работы. Браузер автоматически изменяет содержимое документа при изменении содержимого элементов. Это свойство добавило больше "динамизма" в и без того "динамический" HTML. Для тех, кто начинал с создания статичных страниц для браузеров первых версий, такие широкие возможности казались просто фантастическими. Группа свойств с префиксом offset предназначена для изменения размещения элементов на странице. Эти свойства отличаются от тех, которые используются при позиционировании с использованием CSS-стилей. Возможность определения места расположения элементов на странице весьма полезна. В зависимости от размера окна браузера, позиционируемые элементы на странице могут отображаться в разных местах. Зная размеры и расположение таких элементов, их легче перемещать по странице. Наконец, свойство style используется для получения доступа к спецификации CSS-элемен- тов. Важно также то, что в сценарии можно изменять многочисленные свойства объекта style. Поэтому после загрузки страницы существует возможность изменить характеристики шрифтов, цветов, границ и расположение элементов на странице. Все изменения выполняются динамически в процессе работы (например, изменение размера шрифта). Иерархия содержимого элементов Несмотря на то, что TEA поддерживает исходную объектную модель (см. рис. 14.1), собственная объектная модель Г£4 несколько отличается от базовой. Речь идет, в основном, об организационной структуре элементов модели. Если бы это было так, то, скажем, адресация на 208 Часть III. Объекты документа
элементы таблицы td выполнялась бы через внешний для них элемент tr или table. Точно так же сослаться на элемент управления формы можно, если указать в ссылке форму form. На рис. 14.2 показана схема организации элементов HTML в объекте документа document. В массиве document.all содержатся ссылки на каждый из элементов иерархической структуры (рис. 14.2). Ссылка даже на самый "глубоко спрятанный" в иерархической структуре элемент td будет выглядеть как document. all. ИдентификаторЯчейки. Последний способ задания ссылок на объекты в Ш4 является преобладающим. window _L frame self top parent navigator screen history X document X location X event H link X stylesheets applets form anchor selection TT text П I images X plugins embeds all radio textarea XL button checkbox select reset I [elements] option style password submit Puc. 14.2. Иерархия объектов документа в 1Е4 Система организации элементов в ТЕЛ важна и с другой точки зрения. Элементы могут наследовать некоторые атрибуты таблиц стилей тех объектов, которые содержат в себе данные элементы. Поэтому в коде документа HTML содержимое страницы рекомендуется разбить на фрагменты и заключить в контейнеры. Это значит, что абзацы являются контейнерами для текста (используются дескрипторы начала и конца абзаца), а не фрагментами текста на странице. В IE4 вводится понятие о взаимодействии объектов на уровне родительско-дочерних отношений. Такого типа взаимодействие осуществляется между контейнерами и содержащимися в них элементами. Таким образом, расположение элемента можно вычислить по отношению к расположению содержащего его объекта. Вывод из всего выше сказанного следующий: в отличие от исходной объектной модели, в данном случае иерархическая структура определяется путем установки системы отношений одного объекта относительно другого. Каскадные таблицы стилей На рынке программных продуктов четвертая версия браузера Microsoft появилась несколько позже, чем Netscape Navigator 4. Поэтому Microsoft получила преимущество в том смысле, что смогла использовать в своем браузере более совершенную первую версию таблиц стилей CSS. Отсюда и более полная совместимость со стандартом CSS по сравнению с NN4 (хотя и не абсолютная). Следует о_тметить, что в первом поколении CSS-стилей попытки использования сценариев для программирования свойств стилей осуществлялись с некоторой несогласованностью. В результате разработчикам не удалось реализовать весь потенциал JavaScript. Многие имена атрибутов CSS содержат дефисы (например, text-align или z- index). Но дефис в именах объектов JavaScript использовать запрещено. Имена атрибутов CSS, состоящие из нескольких Глава 14. Основы объектной модели документа 209
слов, необходимо преобразовывать к именам свойств JavaScript в слитном виде (interCap). Поэтому text-align превратится в text Align, a z- index станет z Index. Доступ к этим свойствам осуществляется с помощью свойства style элемента. document. all. ИдентификаторЭлемеита . style. ИмяСвойстваСтиля Побочным эффектом использования таблиц стилей в сценариях, выполняемых в IE4 и более поздних версиях браузеров, является так называемый синдром блуждающего элемента. Такая ситуация имеет место при изменении формата страницы после загрузки ее исходного кода HTML в браузер. При загрузке страницы не все элементы отображаются (или они отображаются не в очередности загрузки). После загрузки страницы обработчик события onload запускает сценарий, изменяющий стиль или содержимое страницы. В результате элементы на странице меняют свое расположение. Нетрудно представить удивление пользователя, который собрался щелкнуть мышкой на ссылке, а эта ссылка начала перемещаться по странице в другое место. Специально для пользователей 32-разрядных операционных систем Windows в объектной модели IE4 был предложен ряд дополнительных расширений. Целый ряд интересных визуальных эффектов стал доступен с использованием фильтров. Фильтры — это такие дополнительные таблицы стилей, которые предназначены для управления основным текстом страницы. Например, эффект тени или подсветки текста достигается применением к этому тексту фильтра стилей. Поскольку синтаксис фильтров выдержан в духе CSS, то они не являются частью стандарта W3C. При переходе от скрытого к видимому содержимому страницы используются два анимационных фильтра. Например, нужно создать слайдовую презентацию. Каждый слайд содержится в позиционируемом элементе div. При отображении (с помощью сценария) следующего слайда (т.е. элемента div) анимационные фильтры могут просто удалять предыдущий слайд или заменять один слайд на другой с эффектом кругового вытеснения одного другим. о событиях Точно так же, как компания Netscape разработала модель событий для своего браузера NN4, Microsoft сделала то же самое для ЕЕ4. К огромному сожалению тех создателей сценариев, кто разрабатывает свои продукты в расчете на использование браузеров обоих типов, модели эти совершенно разные. Вместо того чтобы отправлять события вниз по иерархической структуре к элементу назначения, в ТЕ событие "начинает свой путь" с элемента назначения, и (если явно не указана ссылка в обратном направлении) "всплывает" вверх по иерархической структуре, вплоть до объекта window. При перемещении события по объектам в иерархии объектной модели обработчики события текущего объекта могут выполнять определенные действия. Поэтому, чтобы назначить для обработки всех щелчков мыши на странице один обработчик события, достаточно присвоить этот обработчик объекту body или window. Если при всплывании событие не будет перехвачено другим объектом, оно достигнет вершины иерархической структуры, что приведет к выполнению сценарием нужного обработчика. В ТЕ включен объект event (свойство объекта window). В нем содержится детальная информация о конкретном событии. В частности, для события нажатия клавиши в нем предусмотрен символ нажатой клавиши. При щелчке кнопки мыши в нем записываются координаты указателя. Имена этих свойств полностью отличаются от аналогичных свойств объекта event в NN4. Вопреки складывающемуся впечатлению о невозможности совместить несовместимое (речь идет об отличии моделей событий в NN4 и Ш4), выход можно найти в использовании специального набора сценариев для обработчиков событий (примеры таких сценариев приведены в главах 25 и 56). Фактически, две описанные модели событий объединены в одну во второй версии стандарта W3C DOM (об этом речь пойдет несколько позже). / Назммпцг И еще 210 Часть III. Объекты документа
События и сценарии В IE предложен дополнительный способ привязки событий к объектам. Он выполняется посредством дескриптора <script> и двух дополнительных, не поддерживаемых в стандарте W3C, атрибутов — for и event (примеры их использования можно найти в главе 13). В качестве значения атрибуту for присваивается идентификатор id объекта элемента, для которого вызывается сценарий. Значение атрибута event — это имя обработчика события (например onclick), с помощью которого запускаются операторы сценария указанного выше дескриптора. Внутри дескрипторов находятся операторы сценария. Однако, когда браузер обнаруживает там специальные атрибуты, выполнение операторов отменяется до того момента, пока не будет сгенерировано нужное для данного объекта событие. Объекту передается экземпляр события, после чего выполняются операторы сценария, размещенные в дескрипторе. Обработчику события можно присвоить и определение функции. Иногда это целесообразно делать; в таком случае используется специальная форма записи дескриптора. Эта так называемая, концепция "строгого запуска" получила применение в DHTML в браузерах ЕЕ5 для Windows (см. следующий раздел). Такой специальный способ привязки событий к объектам можно использовать только в браузере IE4+. Все прочие браузеры, включая и ТЕЗ, игнорируют специальные атрибуты и трактуют операторы сценария, размещенные в дескрипторе, как такие, которые должны выполняться при загрузке страницы. Расширенная модель IE5+ Начиная с Ш5, компания Microsoft доработала объектную модель, использованную в IE4. Хотя основной набор объектов остался практически тем же, что и в предьщущей модели, однако количество свойств, методов и обработчиков событий этих объектов возросло невероятным образом. Некоторые новшества были направлены на то, чтобы обеспечить совместимость со стандартом W3C DOM (см. следующий раздел). В результате возникли некоторые проблемы совместимости с Ш4. Была также усилена тенденция по предоставлению пользователям операционной системы Windows особых привилегий. Последние, однако, совсем не обязательно должны стать стандартом для всей индустрии — речь идет о поведениях DHTML и приложениях HTML. Поведения DHTML — это фрагменты сценариев, которые сохраняются как внешние файлы и определяют разного рода последовательность действий. Обычно эти действия направлены на изменение одного или более свойств стиля. Такие фрагменты сценария могут применяться к самым разнообразным элементам. Соответствующий файл сценария называется компонентом HTML и имеет расширение . htc. Идея состоит в том, чтобы создать многократно используемый компонент, который потом можно будет загружать в документ каждый раз, когда элемент этого документа должен выполнять предопределенную в компоненте последовательность действий. Компоненты являются документами XML, в дескрипторах XML которых определены события и программы обработки этих событий, выполняемые независимо от типа используемого элемента. Операторы сценария в htc-документах размещаются, как и в обычном документе HTML, — внутри дескрипторов <script >. В качестве примера использования поведений DHTML можно привести ситуацию, когда текст элемента страницы при наведении на этот элемент указателя мыши становится красного цвета, а когда сводится с элемента— восстанавливается до исходного варианта. Если такой тип поведения задать элементу документа с помощью синтаксических правил CSS, то этот элемент будет вести себя, как описано, — и не иначе. Причем такой стиль поведения можно использовать буквально для всех элементов документа. (Компания Microsoft для обеспечения совместимости с W3C предложила использовать этот метод в третьем поколении CSS.) Примеры использования Глава 14. Основы объектной модели документа 211
поведений DHTML можно найти в главе 15 при описании метода addBehavior (), а также в главе 47, где подробно проанализирован данный подход. Приложения HTML (на языке Microsoft такое приложение сокращенно называется НТА) представляют собой файлы HTML с элементами XML, известными также под именем элемента hta: application. Приложения НТА можно загрузить в Ш5 с сервера подобно тому, как загружают самые обычные Web-страницы (хотя расширение этих файлов — . htc, а не . htm или . html). Пользователь может установить приложение НТА в системе клиента так, что на рабочем столе отобразится пиктограмма этого приложения, а внешний вид окна приложения можно будет настроить по своему усмотрению. Вопрос с защитой данных в НТА решен в пользу клиента, поэтому такое приложение напоминает обычную программу. Фактически, можно отключить стандартную строку меню и, используя методы DHTML, создать собственную строку меню для приложения. Особенностей использования приложений НТА не будут рассмотрены в этой книге. Но о том, что подобные возможности существуют, нужно знать. Более подробную информацию по этому вопросу вы найдете по адресу: http: //msdn. microsoft. com. Модель W3C DOM Конфликт различных версий объектных моделей от Netscape и Microsoft усложнил жизнь разработчикам Web-страниц. Необходимость создания единого стандарта для разработчиков объектных моделей (когда стандартом для содержимого и стилей стали HTML и CSS соответственно), оказалась очевидной. Обязательства по разработке такого стандарта взяла на себя организация W3C, а разрабатываемая объектная модель получила название W3C DOM. Группа разработчиков W3C DOM имела целью создание такой объектной модели документа, которая была бы применима как к документам HTML, так и к XML. Поскольку в документах XML, фактически, могут использоваться дескрипторы с любыми названиями (это определяется в Document Type Definition — Описание типов документов), то строгой структуры или фиксированного словаря для элементов, в отличие от документов HTML, в данном случае нет. Как результат— стандарт DOM должен соответствовать и предопределенной структуре HTML (определяемой в спецификации HTML 4.0), и наперед неизвестной структуре документа XML. Для того чтобы выполнить задание качественно, рабочая группа по созданию DOM разделила саму модель на две части. Первая, базовая модель Core DOM, определяет спецификацию для оболочки и структуры документов XML и HTML. В нее входят способы включения в документ элементов, имеющих дескрипторы и атрибуты. В таких элементах могут содержаться другие элементы. Вторая часть модели DOM имеет отношение исключительно к элементам и другим характеристикам документов HTML. Эта HTML-часть "наследовала" все характеристики базовой модели DOM. Кроме того, в ней предусматривались меры по обеспечению совместимости с объектными моделями, уже использованными в браузерах, и осуществлялись наработки для дальнейших усовершенствований. Важным все же является тот факт, что не все свойства объектных моделей существующих на то время браузеров были включены в модель стандарта W3C DOM. Многие характеристики объектной модели Internet Explorer 4 (и более поздних версий) так в стандарт W3C DOM и не вошли. Таким образом, если кто-то достаточно хорошо освоился со средой Ш и решил переключиться на создание программных продуктов в стандарте W3C DOM, то ему в свой стиль работы придется внести некоторые изменения (подробнее об этом рассказывается далее). К потерям следует отнести и дескриптор <1ауёг> из Netscape Navigator 4 (поскольку он не используется в HTML 4.0, то и в стандарт вряд ли когда-нибудь будет включен), а также и соответствующий ему объект слоя layer. Во многих отношениях, особенно принимая во внимание приложения DHTML, стандарт W3C DOM является полностью новой моделью DOM со своей концепцией, которую обязательно нужно изучить перед началом работы в среде JavaScript. 212 Часть III. Объекты документа
ч Помните: если NN6 практически полностью поддерживает стандарт W3C DOM первого поколения и в значительной степени второго, то Microsoft (по разными причинам) вплоть до Ш5.5 только частично реализовала в своих браузерах средства W3C DOM. Хотя в Ш6 поддержка W3C DOM реализована на более высоком уровне, отдельные ее части, особенно касающиеся событий, браузером этой версии проигнорированы. Другие современные браузера, например Safari, поддерживают базовую модель W3C DOM, хотя все еще "не дотягивают" до уровня ее реализации в Mozilla. Поколения DOM Как и большинство программных продуктов, которые редко имеют только одну версию, существует несколько поколений DOM. Задача по разработке DOM была слишком объемной, чтобы выполнить ее за один раз. Поэтому спецификация DOM постоянно развивается. Процесс выхода в свет новых поколений DOM редко совпадает с разработкой новых версий браузеров. Поэтому нередки случаи, когда браузеры поддерживают стандарт W3C последнего поколения только частично. Формально первая версия модели DOM увидела свет уже после выпуска браузеров NN4 и IE4. В HTML-часть первого поколения модели DOM была включена нулевая версия DOM. Это, по большому счету, не что иное, как объектная модель, использованная в NN3 (и во многом в Internet Explorer 3, а также объекты изображений). Пожалуй, самым существенным недостатком модели DOM первого поколения стала модель событий, в которой игнорировались даже самые элементарные события из NN2 и ГЕЗ. Основой для второй версии DOM стала первая. Кроме существенных усовершенствований, внесенных в обе части (базовую и HTML) модели, во второй версии значительно расширена модель событий, добавлены методы отслеживания иерархической структуры документа, расширены возможности использования XML, текстов, таблиц стилей и свойств стилей. В настоящий момент не прекращается работа над третьей версией модели, хотя о реализации ее в браузерах говорить еще рано. Неизменная часть Как уже отмечалось, исходной точкой развития HTML-части модели следует считать нулевую версию DOM. Последнее в стандарте W3C сделано для того, чтобы обеспечить возможность большинству сценариев выполняться даже при использовании браузеров стандарта W3C DOM. К модели DOM нулевого уровня относятся все объекты, начиная с document (см. рис. 14.1), а также объекты изображений. Доступными будут также практически все свойства и методы этих объектов. Важными являются изменения, внесенные в W3C DOM в систему ссылок на другие элементы (будут обсуждаться в следующем разделе). Утешителен тот факт, что старые способы задания ссылок на такие объекты, как формы, элементы форм и изображения, все еще остаются доступными. Если бы рабочая группа стала создавать модель "с чистого листа", вряд ли объект document имел бы свойства, состоящие из массивов форм, ссылок и изображений. Единственная проблема, с которой можно столкнуться, состоит в том, что некоторые полезные свойства объекта document "сменили владельца". Дело в том, что четыре свойства стилей (alinkColor, bgColor, linkColor и vlinkColor) объекта document стали в модели DOM свойствами объекта body (ссылка на него выглядит как document. body). Кроме того, три свойства цвета изменили свои имена (aLink, link, vLink). Оказалось, тем не менее, что теперь в браузерах ГЕ6 и Mozilla обеспечивается совместимость со свойствами цвета объектов более старых документов. Глава 14. Основы объектной модели документа 213
Спецификация модели DOM, в основном, касается только непосредственно документов и их содержимого. Такие объекты, как window, navigator и screen (вплоть до второй версии DOM), частью модели не являются. Поэтому создатели сценариев до сих пор с надеждой взирают на разработчиков браузеров, что те решат проблему совместимости для данного конкретного случая. Есть надежда, что в будущем объект window будет добавлен в W3C DOM третьей версии. Недоступные элементы Как уже отмечалось ранее, стандарт W3C DOM нельзя рассматривать как подтверждение спецификации уже существующих браузеров. Многие полезные характеристики объектных моделей браузеров Г£ и NN в него не вошли. Интересно разработать с помощью DHTML эффектную страницу, рассчитанную на использование ГЕ4+ или NN4. Но все же нужно уметь обходиться и без некоторых специфических возможностей, предоставляемых этими браузерами и отсутствующих в стандарте W3C DOM. Эксперимент дескриптора <layer> в стандарте W3C DOM поддержки не нашел. Поэтому ни такого дескриптора, ни связанной с ним методики составления сценариев вам обнаружить не удастся. К огромной радости разработчиков сценариев, схема ссылок с использованием слоев типа document. имяСлоя (намного более сложная при использовании вложенных слоев) полностью исчезла из объектной модели. Позиционируемый элемент трактуется как просто еще один элемент, у которого есть некоторые специфические атрибуты стилей, позволяющие перемещать этот элемент по странице, размещать его среди других элементов и скрывать из поля зрения. Среди популярных свойств ГЕ4+, не задействованных в W3C DOM, можно отметить библиотеку элементов HTML document. all и четыре свойства элементов, используемых с целью придать динамизм содержимому страницы: innerHTML, innerText, outerHTML и outerText. Новая концепция W3C предусматривает способы получения массива всех элементов документа. Но генерирование кода HTML для замещения старого или простой вставки его в документ подразумевает использование сложной последовательности операторов (эта проблема обсуждается в разделе "Новые концепции DOM" далее в этой главе). В Mozilla, тем не менее, разрешено использование свойства объектов innerHTML элементов HTML. "Новая" практика HTML Для того чтобы в полной мере реализовать возможности DHTML, предоставляемые в ГЕ4+ и W3C DOM, используют метод, который для некоторых умудренных опытом HTML- разработчиков может показаться принципиально новым. В основе этого метода (выходящего за рамки спецификации HTML 4.0) заложена проверка типа содержимого контейнера HTML. Поэтому вместо использования дескриптора <р> для разделения текста на блоки, каждый текстовый абзац заключается в пару дескрипторов <р>. . . </р>. Если этого не сделать, то браузер будет трактовать каждый дескриптор <р> как начало абзаца. Заканчивается этот абзац как раз перед следующим дескриптором <р> или элементом завершения блока. Несмотря на то, что браузеры последних версий корректно воспринимают отсутствие дескрипторов завершения блоков (например для элементов td, tr или li), все же рекомендуется вводить в коде закрывающие дескрипторы — так легче представить себе блочную структуру документа. Для любого элемента, используемого в сценарии (для изменения его содержимого или свойства) желательно использовать идентификатор, присвоенный атрибуту элемента, id. Для элементов управления формы в случае предоставления содержимого формы серверу необходимым является использование атрибута name. Но атрибуту id формы можно присвоить и другой идентификатор. 214 Часть III Объекты документа
Для того чтобы корректно сослаться на объект, можно воспользоваться либо идентификатором id, либо представить ссылку в формате document. ссылкаНаФорму. ИмяЭлемента. Идентификаторы при этом, как правило, будут теми же, что и значения, которые присваиваются атрибуту name формы или элементов формы. По аналогии со значением атрибута name, идентификатор id должен состоять из единого слова (без пробелов), он не может начинаться с цифры (чтобы избежать конфликтов с JavaScript) и в нем не должны использоваться символы пунктуации, за исключением символа подчеркивания. Хотя доступ к элементу может осуществляться по числовому индексу в контексте внешнего для него элемента (такого, как body), это достаточно рискованный шаг, особенно если содержимое документа находится на стадии разработки. Персональные идентификаторы позволяют намного проще задавать в сценариях ссылки на объекты и работают надежнее. Новые концепции DOM В модели W3C DOM задействованы некоторые концепции, непосредственно относящиеся к иерархической структуре. С точки зрения традиционного подхода, они могут показаться совершенно новаторскими. С точки зрения использования этих концепций в сценарии, они определяют новые способы задания ссылок на элементы и узлы. / Ссылки на элементы Система ссылок на объекты модели нулевого уровня DOM сохранена в следующих поколениях W3C DOM с целью поддержания совместимости сценариев. Поэтому на элемент управления формы, атрибуту name которого присвоено значение имяПользователя, ссылка задается обычным образом document.forms[0] . имяПользователя или document. имяФормы. имяПользователя Поскольку все элементы в документе подчинены объекту document, то для получения доступа к элементу с известным идентификатором id можно использовать новый метод объекта document. Это метод document .getElementById (), параметром которого является строковая версия идентификатора объекта, ссылку на который нужно задать. Для того чтобы воспользоваться этим методом в контексте применяемой в ГЕ4 объектной модели, необходимо рассмотреть следующий дескриптор абзаца HTML. <р id="myParagraph">...</р> ВIE4+ ссылки на элементы можно задавать и так. var elem = document.all.myParagraph; Поскольку библиотека document. all в стандарте W3C DOM не поддерживается, получить доступ к любым элементам по его идентификатору ID можно с помощью упомянутого выше нового метода (доступен в IE5+, Mozl+ и Safari). var elem = documnt.getElementByldC'myParagraph"); • К сожалению, создателям сценариев этот метод не покажется простым (в том смысле, что придется следить за состоянием регистра букв в его имени). Обратите внимание, что последняя буква ("d") в имени метода — строчная. Иерархия узлов Для того чтобы понять принцип организации модели W3C DOM, следует рассмотреть, как одни объекты в этой структуре вложены в другие. Каждый элемент или фрагмент текста в документе HTML (или XML) является объектом, который содержится в определенном контейнере, Глава 14. Основы объектной модели документа 215
тоже являющимся объектом. Чтобы понять принцип функционирования такой структуры, рассмотрим простой документ HTML. В листинге 14.1 представлена иерархическая структура из вложенных друг в друга элементов и фрагментов строк. ^ -ПГлЬ- Л. <html> <head> <title> A Simple Page </title> </head> <body> <p id= "paragraphia This is the <em id="emphasisl"> one and only </em> paragraph on the page. </p> </body> </html> To, что отображено в листинге, является объектом document. Объект document создается автоматически при загрузке страницы в браузер. Важно то, что объект document охватывает все, что содержится в листинге 14.1. Поэтому в данном случае объект document содержит один вложенный элемент — HTML. Элемент HTML, в свою очередь, содержит в себе два вложенных элемента: head и body. В элементе head содержится элемент title, а элемент title включает фрагмент текста. В элементе body есть элемент р, который состоит из трех частей: фрагмент в виде строки, элемент em и еще одна срока. Следуя терминологии W3C DOM, каждый контейнер, отдельный элемент (как элемент BR в приведенном примере) или фрагмент текста называется узлом. Это фундаментальный строительный блок модели W3C DOM. Когда один контейнер содержит в себе другой, говорят, что один узел является родительским, другой — дочерним. Как и в реальной жизни, система взаимоотношений родительский-дочерний распространяется только на смежные поколения. Узел может иметь несколько дочерних узлов или не иметь таковых вообще. Количество узлов третьего уровня (колена), размещенных далее в генеалогическом дереве никак не влияет на число дочерних узлов, связанных с родительским узлом. Поэтому согласно листингу 14.1, узел HTML имеет два дочерних узла, a head и body являются узлами-"сестрами" одного и того же родительского узла. Элемент body имеет один дочерний элемент (р) несмотря на то, что этот дочерний элемент имеет, в свою очередь, три дочерних элемента (два текстовых узла и один узел элемента em). Если графически представить иерархическую структуру, заданную в листинге 14.1 , то выглядеть она должна так, как показано на рис. 14.3. В модели W3C DOM, начиная со второй версии, определено 12 типов различных узлов, семь из которых напрямую document +--<html> +~<head> | +--<title> | +--"A Simple Page" +--<body> +-<p ID="paragraph 1 "> +--This is the " +--<em ID=nemphasis1"> | +--"one and only" +--" paragraph on the page Рис. 14.3. Дерево структуры узлов документа из листинга 14.1 216 Часть III. Объекты документа
используются в документах HTML. Последние приведены в табл. 14.3 (остальные относятся kXML). Из этих 12 типов три являются наиболее общими: документы, элементы и фрагменты текста. В W3C браузерах (Ш5+, Mozl и Safari) задействованы все указанные типы узлов. I Если исходный код документа перед дескриптором <html> содержит описание /назмшкг типа документа Document Type Definition (DTD), то браузер будет трактовать узел ' ^-*>* DTD как узел-"сестру" элемента HTML. В этом случае родительский узел document содержит два дочерних узла. ШШШШШШШШШШ^ Тип Номер Имя узла Значение узла Описание IE5+ Moz1 Safari Элемент Атрибут Текст Комментарий Документ Тип документа Фрагмент 1 2 3 8 9 10 11 Имя дескриптора Имя атрибута #text #comment #document DOCTYPE #document- fragment i null Значение атрибута Содержимое текста Текст комментария null null null Любой элемент HTML или XML, имеющий дескрипторы Пара атрибутов элемента имя-значение Текстовый фрагмент, содержащийся в элементе Документ HTML Родительский объект document Спецификация DTD Да Нет Да Нет Нет Нет Серии из одного или более Нет узлов вне документа Да Да Да Да Да Да Да Да Да Да Нет Да Нет Да Сравнивая диаграмму структуры страницы, показанной на рис. 14.3, с типами узлов из табл. 14.3 приходим к выводу, что страница состоит из одного узла документа, шести узлов элементов и четырех текстовых узлов. Свойства узлов Узлы имеют широкий набор свойств, большинство из которых являются ссылками на другие узлы, связанные с данным. В табл. 14.4 приведен полный перечень свойств всех типов узлов модели DOM второго поколения. Свойство Значение Описание WinlE5+ Mac IE5+ Moz1 Safari nodeName nodeValue nodeType parentNode Строка Строка Целое число Объект Зависит от типа узла (см. табл, 14.3) Зависит от типа узла (см. табл. 14.3) Константа, представляющая типы Ссылка на следующий внешний контейнер Да Да Частично Да Да Да Да Да Да Да Да Да Да Да Да Да Глава 14. Основы объектной модели документа 217
Окончание табл. 14.4 Свойство childNodes firstChild lastChild previousS ibling nextSibling attributes owne rDocument namespaсeURI prefix localName Значение Массив Объект Объект Объект Объект Карта узлов NodeMap Объект Строка Строка Строка Описание Все дочерние узлы в исходном порядке Ссылка на первый дочерний узел Ссылка на последний дочерний узел Ссылка на предыдущий узел-йсеструя Ссылка на следующий узел-исеструя Массив атрибутов узлов Объект, содержащий документ URL для определения имени (только узлы атрибутов и элементов) Префикс имени (только узлы атрибутов и элементов) Применимо к узлам с пробелами в имени WfnlE5+ Да Да Да Да Да Нет Нет Нет Нет Нет Mac IE5+MOZ1 Safari Да Да Да Да Да Да Да Нет Нет Нет Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да Да / Свойства, отображенные в табл. 14.4, вы найдете в главе 15 в списке свойств, На замену которыми в совокупности обладают объекты элементов HTML и которые реали- *-" зованы в IE5+ и Mozilla. Это происходит потому, что элементы HTML, являющиеся в то же время и узлами, наследуют все свойства прототипа узла. Для того чтобы вам было легче разобраться с ключевыми свойствами узлов, в табл. 14.5 приведены значения для некоторых узлов страницы, описанной в листинге 14.1. Данные этой таблицы следует изучать параллельно со структурой страницы, изображенной на рис. 14.3. Это поможет отследить значения разных узлов. Свойства Узлы nodeType nodeName nodeValue parentNode previousSibling nextSibling childNodes document 9 #document null null null null html html 1 html null document null null head P 1 P null BODY null null "This is the " "one and only" 3 #text "one and only" em null null 218 Часть III. Объекты документа
Окончание табл. 14.5 Свойства firstChild lastChild Узлы html html body head body em " paragraph on the page." "This is the " 11 paragraph on the page." null null Свойство nodeType является целым числом; его удобно использовать в сценариях при просмотре набора неизвестных узлов. Большинство из того, что используется в документах HTML, относится либо к типу 1 (элемент HTML), либо к типу 3 (текстовый фрагмент). Внешним контейнером при этом для них является документ (тип 9). Свойство узлов nodeName, как правило, совпадает с именем дескриптора узла HTML (для элементов HTML) или является константой (перед которой стоит символ # — см. табл. 14.3). Что довольно неожиданно, значение свойства nodeValue равно null для всех узлов, кроме узла фрагмента текста. В последнем случае значение указанного свойства равно фактическому содержимому текстовой строки узла. Другими словами, в модели W3C DOM контейнер элементов HTML в виде текстовой строки не используется. Весьма маловероятно, что вы будете задействовать все объектно-ориентированные свойства узла. В основном, дело касается способов получения доступа от одного узла к другому. Важное значение имеет свойство parentNode, поскольку оно является ссылкой на содержащий данный узел контейнер. Свойства firstChild и lastChild указывают на первый и последний дочерние узлы внутри контейнера соответственно. Однако в сценариях для просмотра дочерних узлов, как правило, используется свойство childNodes и цикл повторения for. Если дочерних узлов нет вообще, то длина массива childNodes равна нулю. Методы узлов Действия, приводящие к изменению содержимого узлов в стандарте W3C DOM, подразумевают вызов методов, предопределенных для прототипа объекта узла Node. В табл. 14.6 перечислены такие методы с указанием степени совместимости с браузерами стандарта W3C DOM. щ4А^фШ^ уж- Метод Описание IE5+ Moz1 Safari appendChild (новыйДочернийУзел) cloneNode (Уровень) hasChildNodes () insert Before [новый, Узел) removeChild (старый) replaceChild (новый, старый) isSupported (свойство, версия) В конец текущего узла добавляется Да Да Да дочерний узел Создается копия текущего узла (возможно, Да Да Да с дочерним узлом) Определяется, содержит ли текущий узел Да Да Да дочерние (логический ТИП Boolean) Выполняется вставка одного дочернего Да Да Да (новый) узла перед другим Удаляется дочерний узел (старый) Да Да Да Старый дочерний (старый) узел замещается Да Да Да НОВЫМ (новый) Определяется, поддерживает ли узел данное Мет Да Да СВОЙСТВО (свойство) Глава 14. Основы объектной модели документа 219
Объектно-ориентированная модель W3C DOM Тем, кто знаком с основами объектно-ориентированного программирования, будет приятно узнать, что в модели W3C DOM объектно-ориентированная тенденция выдержана в полной мере. Объект узла Node имеет ряд свойств (табл. 14.4) и методов (табл. 14.6), которые могут наследоваться любым объектом, производным от объекта Node. Большинство объектов, которые наследуют характеристики Node, имеют собственные свойства и методы, определяющие особенности их поведения. На следующем рисунке показано (с использованием терминологии W3C DOM) структуру дерева наследования, начиная с корневого объекта Node. Большинство элементов этого рисунка определены в базовой части модели DOM. Те же, что выделены полужирным шрифтом, определяются в разделе модели, относящемся исключительно к HTML. Node ♦-Document | +--HTMLDocument +--CharacterData | +--Text | | +--CDATASection | +--Comment +--Attr +--Element | +--HTMLEIement | +-- (Each specific HTML element) +--DocumentType +--DocumentFragment ♦--Notation ♦-Entity ♦-Entity Reference ♦--Processinglnstruction Как видно из этого рисунка, отдельные элементы HTML наследуют свойства и методы общего для них элемента HTML, который, в свою очередь, является наследственным элементом от базового объекта Element. Последний наследуется от объекта узла Node. При написании сценариев совсем не обязательно помнить структуру наследования объекта узла Node. Она нужна для того, чтобы в дальнейшем легче было разбираться с документацией по W3C DOM. Кроме того, теперь понятно, как самые заурядные объекты элементов справляются с таким огромным количеством свойств и методов. Наиболее важными методами, используемыми для изменения содержимого, можно назвать appendChildO, insertBefore О , removeChildO и replaceChild (). Обратите внимание на следующее: если один из этих методов применяется по отношению к определенному узлу, то данный метод рассматривается как относящийся к родительскому узлу. Например, при удалении узла используется метод remove Chi Id () не удаляемого узла, а его родительского узла. Эту особенность можно использовать для создания библиотеки полезных функций, которые определяются без жесткой привязки к иерархической структуре элемента. Ниже приведен пример такой достаточно простой функции, выполняющей в сценарии удаление элемента из родительского узла. function removeElement(elemID) { var elem = document.getElementByld(elemlD); elem.parentNode.removeChild(elem); } 220 Часть III. Объекты документ»
По сравнению со стандартной в таких случаях процедурой очистки свойства outerHTML соответствующего объекта в Ш4+, предложенный выше метод удаления элементов выглядит несколько мудреным. Хотя такой подход иногда и оправдывает себя в XML, следует признать, что группа разработчиков W3C DOM в данном случае интересы сторонников HTML во внимание не приняла. Тем не менее, как будет показано в дальнейшем, не все еще потеряно. Создание содержимого узла Далее мы рассмотрим вопрос о том, как в рамках модели W3C DOM в содержимое страницы вносятся изменения. Способы добавления или замены содержимого с помощью сценариев легкими назвать нельзя. Если подобные изменения касаются только тЛсста (например, изменение текстового содержимого ячейки таблицы), то существует два пути: простой и сложный. При внесении изменений в HTML можно пойти только по сложному пути (несколько полезных советов по этому поводу приведены ниже). Сначала рассмотрим сложные методы, а потом вернемся к наиболее простым способам изменения текстового содержимого. При создании нового узла в модели DOM используется целый ряд методов объекта document, определяемых в базовой части модели W3C DOM (поэтому они наследуются объектом HTML document). В DOM методы создания узлов определены практически для каждого их типа. При создании документов HTML наиболее важными следует назвать два метода— createElement () и createTextNode (). Первый генерирует элемент с любым дескриптором, имя которого в виде строки передается как параметр метода, а второй создает текстовый узел с текстом, указанным в качестве параметра. Созданный элемент хранится в памяти браузера. В иерархической структуре документа его еще нет. Результатом выполнения метода createElement () будет ссылка на пустой элемент, содержащий, пожалуй, только имя дескриптора. Например, для того чтобы создать элемент Р, нужно использовать такие операторы. var newElem = document.createElement("p"); У нового элемента не будет ни идентификатора id, ни атрибутов, ни содержимого. Для присвоения этому элементу атрибута можно использовать метод setAttribute () (этот метод применим к любому объекту) или присвоить соответствующему свойству объекта значение. Например, чтобы присвоить новому элементу идентификатор, следует воспользоваться оператором newElem.setAttribute("id", "newP"); или newElem.id = "newP"; Оба способа можно использовать. Но даже теперь, когда элемент имеет собственный идентификатор, он не является частью документа. Извлечь его с помощью метода document. get Element By Id () вам не удастся. Чтобы добавить в абзац содержимое, сгенерируем в виде отдельного объекта текстовый узел. var newText = document.createTextNode("This is the second paragraph. ") ; Опять же, этот узел размещается в памяти; подразумевается, что он будет добавлен в качестве дочернего к другому узлу. Чтобы введенный таким образом текст стал содержимым абзаца, его можно добавить в качестве дочернего к элементу, размещенному в памяти. newElem.appendChiId(newText); Соответствующий код HTML, описывающий новый элемент абзаца, будет иметь такой вид. <р id="newP">This is the second paragraph.</p> Глава 14. Основы объектной модели документа 221
Теперь новый элемент абзаца готов к вставке в документ. В документе со структурой, показанной в листинге 14.1, этот дочерний элемент можно добавить к элементу body, document.body.appendChild(newElem); Наконец, новый элемент стал частью иерархической структуры документа. На него теперь можно ссылаться так же, как и на все другие элементы документа. Замена содержимого узла Описанная в предыдущем разделе процедура добавления абзаца приводит к изменению первоначального содержимого страницы — абзац "one and only" теперь далеко не единственный на странице (one and only — один-единственный). Как уже отмечалось ранее, изменить текстовое содержимое можно либо с помощью метода replaceChildO, либо присвоив новый текст в качестве значения свойства текстового узла nodeValue. Ниже приведен пример использования обоих подходов для изменения содержимого текста элемента ЕМ первого абзаца с "one and only" на "first" (первый). Для того чтобы задействовать метод replaceChild (), сначала в сценарии необходимо сгенерировать текстовый узел с новым текстом. var newText = document.createTextNode("first"); Теперь можно воспользоваться методом replaceChildO . He забывайте, что этот метод является методом родительского узла по отношению к удаляемому дочернему узлу. В данном случае в качестве родительского узла выступает текст в элементе em. Таким образом, следует вызвать метод replaceChildO элемента em. В методе используется два параметра: первый является именем нового узла, а второй представляет собой ссылку на удаляемый узел. Поскольку такого рода ссылки в операторах сценария являются достаточно громоздкими, то на промежуточном этапе с помощью метода getElementByldO эта ссылка сохраняется в переменной, которая будет затем использована в качестве параметра. var oldChild = document .getElementByld ("emphasisl") .childNodes [0 ] ; Теперь в результате вызова метода replaceChild () элемента em старый текст узла будет заменен новым. document.getElementByld("emphasisl").replaceChild(newText, oldChild); В том случае, если старый узел перед полным удалением нужно перехватить, метод replaceChildO в качестве значения возвращает ссылку на удаляемый узел (который на данном этапе размещается в памяти и не может рассматриваться как часть иерархической структуры документа). Если оператор с методом присвоить переменной, то этот старый узел можно будет в случае необходимости использовать в сценарии. Описанный подход многим покажется слишком нерациональным, особенно если код HTML и так достаточно запутан. К счастью, существует более простой способ заменить один текст в элементе на другой. Для этого понадобится только ссылка на замещаемый текстовый узел. Свойству узла nodeValue присваивается строка с новым значением. document.getElementByld("emphasisl").childNodes[0].nodeValue = "first"; Бели содержимым элемента является исключительно текст (например, ячейка таблицы всегда содержит в себе текстовый узел), этот метод вставки текста в W3C DOM будет наиболее удобным. Однако в том случае, если необходимо создать второй абзац (как это требовалось ранее) данный подход не сработает. Причина в том, что для использования этого метода нужно, чтобы узел уже существовал. Поэтому для его создания должен быть задействован метод createTextNode(). 222 Часть III. Объекты документ*
Следует также помнить, что текстовый узел не имеет наследованных стилей. Стиль текста определяется стилем содержащего его элемента HTML. Если у вас есть желание изменить не только сам текст, но и то, как этот текст выглядит, следует внести изменения в свойство Style родительского элемента текстового узла. Браузеры, выполняющие такого рода форматирование текстового содержимого и изменение стилей, в этом случае автоматически обновят содержимое страницы. Чтобы подвести черту под всем вышесказанным, приведем листинг 14.2, в который по сравнению с оригиналом документа из листинга 14.1 были внесены определенные изменения. В новой версии есть специальная кнопка и сценарий, предназначенные для внесения описанных выше изменений в текстовые узлы. Чтобы увидеть изменения, достаточно перезагрузить страницу. <html> <head> <title>A Simple Page</title> <script type="text/javascriptM> function modify() { var newElem = document.createElement("p"); newElem.id = "newP"; var newText = document.createTextNode("This is the second paragraph."); newElem.appendChild(newText); document.body.appendChild(newElem); document.getElementByldC'emphasisl").childNodes[0].nodeValue = "first"; } </script> </head> <body> <button onclick="modify()">Add/Replace Text</button> <p id="paragraphl">This is the <em id="emphasisl">one and only</em> paragraph on the page.</p> </body> </html> В главе 15 детально рассматриваются свойства и методы, наследуемые элементами HTML. Большинство из них реализовано в браузерах ГЕ5+ и W3C DOM. Справку относительно других методов W3C DOM можно найти в разделах главы 18, посвященных объекту document. Фактический стандарт: innerHTML Свойство innerHTML впервые было представлено Microsoft в браузере Г£4. Хотя оно и не включено в стандарт W3C DOM, многие пользователи и разработчики успешно применяют его в своих документах. Это свойство позволяет динамически изменять содержимое элементов, представленных HTML-дескрипторами, без необходимости создания и настройки текстовых узлов и узлов элементов. Как это ни парадоксально, но большинство браузеров W3C, включая Mozl и Safari, полностью поддерживают свойство innerHTML во всех объектах. При назначении в качестве значения свойства innerHTML уже существующего элемента строки, содержащей дескрипторы HTML, браузер автоматически вставит в дерево узлов новые Глава 14. Основы объектной модели документа 223
элементы. Вы также можете назначать этому свойству строки, не содержащие HTML-дескрипторы, — таким образом вы приравняете его к свойству innerText, представленному в Ш. Несмотря на кажущееся преимущество использования свойства innerHTML, методика поэтапного добавления и изменения текстовых узлов и узлов элементов, с точки зрения браузера, кажется более эффективной. Это именно тот случай, когда простой для разработчика код оказывается сложным для браузера. Статичные объекты В объектной модели NN6 DOM (к сожалению, об Ш5.х так сказать нельзя) выдержан стиль базового языка JavaScript, обеспечивающий наследование прототипов объектной модели. При загрузке страницы в NN6, основываясь на прототипах каждого из определенных в W3C DOM объектов, браузер создает объекты HTML. Предположим, что для определения типа объекта абзаца туР используется приложение The Evaluator (глава 13). В этом случае в верхнем текстовом поле следует ввести document. getElementByld ("myP") и щелкнуть на кнопке Evaluate. В результате будет выведено сообщение о том, что основой для данного объекта является HTMLParagraphElement — объект модели DOM. Каждый экземпляр объекта элемента Р на странице наследует по умолчанию свойства и методы HTMLParagraphElement (который, в свою очередь, наследует их от объектов HTMLElement, Element и Node — все они детализированы в JavaScript для спецификации W3C DOM). Прототипам некоторых из этих статичных объектов с помощью сценариев могут быть добавлены новые свойства. Для этого используются новые характеристики, добавленные bMozI. Два новых метода— _defineGetter_() и _def ineSetter_() — позволяют присвоить объектам в качестве свойств функции. # Эти методы характерны только для Mozilla-совместимых браузеров. Для того /наэамтуг чтобы предотвратить возможные коллизии в случае, если в ECMAScript в буду- * >*<* щем будут разработаны стандартизованные версии этих характеристик, в их именах (вначале и в конце) необходимо поставить символы подчеркивания. Эти функции будут выполняться каждый раз при вызове свойства (функция, присваиваемая методом _defineGetter_()) или его изменении (функция, присваиваемая методом _def ineSetter_ ()). Общим способом использования этих функций является определение их в качестве анонимных функций (глава 33). Ниже приведен пример использования соответствующего синтаксиса для задания прототипам объектов нужного поведения. объект.prototype._defineGetter_(" имяСвойства", function ( {параметр! [,...[, параметра ] ] ) { II Операторы return возвращаемоеЗначение; }> object.prototype._defineSetter_("имяСвойства", function([параметр![,...[,параметра ]]) { // Операторы return возвращаемоеЗначение; Приведенный в листинге 14.3 пример показывает, как в текущем документе элементу HTML добавить свойство (доступное только для чтения). Свойство, в данном случае называемое childNodeDetail, в качестве значения возвращает объект. Объект имеет два сво& ства: одно определяет количество дочерних узлов элемента, а второе — количество дочерни* ■ ■«■ 14 ■■■ ■■!■■ II И —————— 224 Часть III. Объекты документ
текстовых узлов. Ключевое слово this в описании функции является ссылкой на объект, для которого и определяется свойство. Поскольку функция запускается каждый раз при обращении к свойству, то все вносимые в сценарии изменения в содержимое страницы после ее загрузки будут отображаться в возвращаемом свойством значении. <script type="text/javascript"> if (HTMLElement) { HTMLElement.prototype. defineGetter ("childNodeDetail", function() { var result = {elementNodes:0, textNodes:0 } for (var i = 0; i < this.childNodes.length; i++) { switch (this.childNodes[i].nodeType) { case 1: result.elementNodes++; break; case 3: result.textNodes++; break; } } return result; } </script> Принцип использования этого свойства точно такой же, как и прочих свойств объекта. var BodyNodeDetail = document.body.childNodeDetail; Возвращаемое в данном случае в качестве результата значение свойства является объектом. Таким образом, для получения доступа к одному из значений свойств можно задействовать самый обычный синтаксис JavaScript. var BodyElemNodesCount = document.body.childNodeDetail.elementNodes; Двунаправленная модель событий Несмотря на явное и радикальное отличие моделей событий в NN4 (движение вниз по иерархической структуре) и в Ш4 (события всплывают вверх по структуре), в модели W3C DOM (вторая версия) сделана серьезная попытка применить обе эти модели. В результате вы сможете обрабатывать события независимо от того, в каком направлении они перемещаются. Для того чтобы избежать конфликтов с уже существующей в моделях событий терминологией, в модели W3C для свойств и методов введено много новых терминов. В некоторых случаях приходится использовать характеристики нескольких объектных моделей. В модели событий W3C представлена новая концепция приемника событий. Механизм приема событий основан на указании объекту типа ответной реакции в случае возникновения событий определенного рода (это очень напоминает ситуацию, когда атрибуты обработчиков событий в дескрипторах HTML отвечают на события). Однако в стандартах DOM подчеркивается, что при определении приемников событий желательно использовать методы, больше ориентированные на сценарии. Так, метод addEventListener () доступен для каждого узла в иерархии документа. С помощью этого метода браузеру можно указать, следует ли событие отправить дальше вверх по иерархической структуре (такое поведение задается по Глава 14. Основы объектной модели документа 225
умолчанию и при использовании обработчиков событий HTML атрибутивного типа), или оно должно захвачиваться на определенном более высоком уровне. Вызываемые приемником событий функции получают всего один параметр, состоящий из объекта события, свойства которого содержат необходимую информацию о событии (например, такие данные, как расположение указателя мыши при щелчке, код нажатой на клавиатуре клавиши или ссылка на объект назначения). Например, если форма содержит кнопку, которая, в свою очередь, вызывает функцию, выполняющую определенные вычисления, то в W3C DOM наиболее приемлемым будет следующий способ определения обработчика события. document.getElementByldC'callButton").addEventListener("click", doCalc, false); Методу addEventListener () передаются три параметра. Первый параметр является строкой с указанием события, которое отслеживается. Второй параметр определяет функцию, вызываемую при наступлении события. Третий параметр — это значение логического типа. Если такое значение равно true, то это значит, что должен производиться перехват указанного события, когда бы оно ни было направлено к данному объекту. В этом случае вызываемая функция получает нужные данные из передаваемого ей в качестве параметра объекта события. function doCalc(evt) { // Ссылка на форму, содержащую элемент кнопки var form = evt.target.form; var results = 0; // Операторы для выполнения вычислений form.result.value = results; } Чтобы изменить приемник события, сначала используйте метод removeEventListenert) для очистки старого приемника, а затем для присвоения нового примените (с указанием параметров) метод addEventListener (). По сравнению с D34, в модели событий W3C другой является и процедура блокировки выполнения событием действий по умолчанию. В Ш4 (так же, как и в NN3, и NN4) можно отменить предусмотренные по умолчанию действия, заставив обработчик события сгенерировать результат return false. Данный подход остался доступным и в Ш5+, однако компания Microsoft предложила использовать новое свойство объекта window, event с именем returnValue. Если где-либо в функции, вызываемой обработчиком события, установить это значение равным false, то событие будет отменено обработчиком прежде, чем обработчик успеет что-нибудь выполнить. В модели событий W3C для подобных целей используется метод pre vent De fault () объекта события. Метод отменяет выполняемые событием по умолчанию операторы. Он может использоваться в функциях, вызываемых при наступлении события. Детальная информация о событии содержится в объекте события, который подставляется в функцию обработчика события. Если назначить обработчик событий с помощью метода W3C DOM addEventListener () или свойства обработчика событий, то объект события будет передан в обработчик автоматически (как единственный параметр функции обработки события). function swap(evt) { // операторы обработки объекта события в W3C DOM } Если же события задаются с помощью атрибутов дескриптора, то объект события обязательно необходимо включить в вызов функции обработки события. <а href="http://www.example.com" onmouseover="swap(event)"> К сожалению, ни в ГЕ5, ни в Ш6 для Windows, а также Ш5 для Мае синтаксис W3C DOM описания событий применения не нашел. Но вы можете комбинировать в создаваемых документах обе модели обработки событий. Небольшие примеры подобного поведения сценарш приведены далее в этой главе и в главе 25. 226 Часть III. Объекты доктет
Комбинирование объектных моделей Необходимость создания таких страниц, которые могли бы просматриваться максимально возможным числом браузеров различных типов, находится в прямой зависимости от того разнообразия моделей браузеров, которые задействованы потенциальными пользователями. Из уже сказанного ранее в этой главе можно сделать вывод, что сценарии, написанные для более старых версий браузеров (Netscape Navigator 2 или Explorer 3), будут, скорее всего, работать и в браузерах самых последних версий. При этом в них даже не придется вносить изменения. Однако, если ориентироваться при создании программных продуктов на браузеры старых версий, будет невозможно в полной мере задействовать уникальные возможности, в частности, DHTML, предоставляемые в браузерах последних типов. Поэтому приходится выбирать "золотую середину" между, как минимум, четырьмя классами браузеров (не поддерживающие DHTML, NN4, IE4/5 и браузеры стандарта W3C DOM, который реализован в Ш6 и Mozl) и запросами пользователей. Более того, пользовательские запросы со временем изменяются. Например, число пользователей с браузерами, не поддерживающими DHTML и NN4, со временем будет уменьшаться, а доля браузеров Microsoft IE DOM (Ш4+) и браузеров стандарта W3C DOM (IE6+ и Mozl+)— увеличиваться. Если процент пользователей с браузерами NN4 относительно небольшой, то можно не беспокоиться по поводу неэффективного использования DHTML в этом браузере и отнести при анализе потенциальной аудитории пользователей с NN4 к группе пользователей с браузерами, не поддерживающими DHTML. Для каждого приложения или Web-узла следует заранее разработать стратегию использования сценариев для реализации различных характеристик. При этом помните, что в рамках одного подхода предусмотреть абсолютно все возможные ситуации не удастся. Ориентироваться следует на основные типы браузеров, используемые при посещении узла (для Web- узлов таких типов браузеров достаточно много, для локальной сети может быть и один), а также на предполагаемый уровень использования DHTML. Далее в этом разделе представлены три концептуальных подхода, призванных помочь разработчикам страниц. Они приведены по, так называемой, степени "агрессивности". Возможно, какие-то из них понравятся читателю больше, какие-то — меньше. Однако ознакомиться с ними в любом случае полезно. Консервативный подход В рамках данного подхода подразумевается задействовать относительно скромные возможности по взаимодействию пользователя со страницей с помощью форм и средств предварительной загрузки изображений. Диапазон поддерживаемых браузеров будет достаточно широк. Среди них — как браузеры, которые управляют сценариями, так и не поддерживающие сценарии программы. Одна версия страницы используется для обслуживания всех посетителей независимо от типа браузера. В том случае, если форма предоставляет информацию от пользователя для серверной CGI- программы, которая затем записывает данные в базу данных или выполняет поиск по указанным критериям, для ввода данных целесообразно использовать стандартные элементы формы. В поддерживающих сценарии браузерах можно организовать предварительную проверку корректности введенных в поля формы данных. В этом полезными станут обработчики событий текстового поля onchange и формы onsubmit. He поддерживающие сценарии браузеры проигнорируют наличие обработчиков событий и отправят такую форму серверу, какой она есть. В этом случае проверка корректности данных формы полностью возлагается на сервер. В последнем случае из-за увеличения объема передаваемых данных скорость работы падает. Для того чтобы реализовать предварительную загрузку изображений, они заключаются в дескрипторы ссылки. Функции предварительной загрузки изображений в такой ситуации Глава 14, Основы объектной модели документа 227
следует вызывать с помощью обработчиков событий ссылки onmouseover и onmouseout. Чтобы "отсеять" браузеры первого поколения, в которых изображения в качестве объектов не воспринимаются, в функциях обработчиков событий операторы необходимо задать внутри конструкции if, в условии которой выполняется проверка наличия массива document. images. Браузеры старого типа, в которых такой массив не используется, никаких действий выполнять не будут. function imageOn(imgName) { if (document.images) { document.images[imgName].src = onlmages[imgName].src; } } Подобные операторы сценария в разделе head предназначены для предварительного кэширования изображений в памяти при загрузке страницы. i f (document.images) { var onlmages = new Array(); onlmages["home"] = new Image(50,30); onlmages["home"].src = "images/homeOn.gif"; } В поддерживающих сценарии браузерах при загрузке страницы можно также с помощью метода document. write () генерировать новое содержимое, добавляемое на страницу. Например, можно сделать так, чтобы страница приветствовала пользователя в зависимости от времени суток "Доброе утро!'*, "Добрый день!" и т.д. Для не поддерживающих сценарии браузеров в этом случае в дескрипторе <noscript> указывается стандартное приветствие "для любого времени суток". Умеренная концепция В этом случае страницы используют таблицы стилей. Основная идея заключается в том, чтобы пользователи всех типов браузеров обращались, как и ранее, к одной и той же версии страницы HTML, но пользователям с браузерами последних версий предоставляются специальные возможности (поскольку их браузеры эти возможности поддерживают). Стиль объекта, если он поддерживается браузером, изменяется в ответ на действия пользователя (например, при наведении указателя мыши на ссылку ссылка и ее фон выделяются цветом). Одним из элементов дизайна страницы является форма, размещаемая в таблице. Если пользователь в определенное текстовое поле вводит значение, внизу таблицы выводится вычисленный результат, обычно в качестве содержимого ячейки таблицы (или в другом текстовом поле). При таком подходе придется в определенных местах сценария выполнять сортировку браузеров по типам и версиям в зависимости от того, как используемые свойства трактуются этими браузерами. Тем самым вы "отфильтруете" браузеры старых версий и браузеры, которые не поддерживают сценарии. Такую сортировку лучше (и нужно) проводить, частично или полностью базируясь на методе детектирования объектов (см. ниже). В табл. 14,7 представлены ключевые объекты для описанного подхода с указанием, какими типами браузеров они поддерживаются. Динамические стили Для получения доступа к динамическим стилям в объектных моделях ГЕ4+ и W3C элементы используют свойство style, с помощью которого и можно добраться до настроек таблицы стилей. Этот факт существенно упрощает жизнь разработчикам страниц, поскольку в условной конструкции if можно проверить для данного объекта наличие свойства style, а в зависимости от результата проверки выполнить разные операторы (или не выполнить вообще). 22» Часть III. Объекты документа
Характеристика Замечания Динамическая Поддерживается в IE4+ и браузерах W3C DOM с помощью свойства style поддержка объектов элементов HTML Вычисление форм Если только не требуется выполнять проверку данных (режим Y2K) или синтаксический анализ выражений, доступно во всех без исключениях поддерживающих сценарии браузерах Динамическое IE4+ и браузеры W3C DOM поддерживают возможности DHTML по управлению содержимое ячейками таблиц, но в объектных моделях IE и W3C для изменения содержимого ячеек таблицы используются разные подходы. Можно применить также нестандартное, но удобное свойство ячейки innerHTML. В более старых версиях браузеров ячейка должна содержать для отображения результата текстовое поле. Для не поддерживающих сценарии браузеров ячейка должна иметь кнопку для отправки формы в CGI-программу на сервер, в результате чего выполняются необходимые вычисления и возвращается результат на страницу function hilite(elem) { if (elem.style) { elem.style.fontWeight * "bold"; Если обработчик события, генерирующий изменения, размещается внутри обрабатываемого элемента (например, обработчик события onmouseover элемента span, содержащего какой-то текст), то соответствующее событие в браузерах, не поддерживающих свойство style, обрабатываться не будет. Хорошо, правда, что браузеры, в которых реализовано свойство style, поддерживают все элементы объектной модели. Для того чтобы обойти несовпадение в выполнении ссылок на объекты в объектных моделях ГЕ4+ и W3C, этот объект можно передать в качестве параметра функциям обработчиков событий. <span onmouseover="hilite(this)" onmouseout="revert(this)" onclick="go('...')">...</span> При таком подходе нет необходимости проводить детектирование версий браузеров, поскольку вызываемая обработчиком события функция не использует специфическую для DOM ссылку на объект. Переменные ветвления Одним больше нравится выполнять детектирование версий браузеров, другим — детектирование объектов. В умеренной концепции сортировать браузеры в зависимости от их версии можно путем организации процесса распознавания объектных моделей Ш4+ и W3C DOM. Главными действующими лицами при этом будут, как нетрудно догадаться, глобальные переменные. Для начала инициализируем две глобальные переменные. function getlEVersionO { var ua = navigator.userAgent; var IEoffset = ua.indexOf("MSIE "); return parseFloat(ua.substring(IEoffset+5, ua.indexOf(";", Ieoffset))); } var isIE4 = ((navigator.appName.indexOf("Microsoft") == 0 && parselnt (getlEVersionO ) >= 4)); var isW3C = (document.documentElement) ? true : false; Глава 14. Основы объектной модели документа 229
Функция getlEVersion () в данном случае с помощью свойства navigator. userAgent определяет точную версию браузера Ш. Обе глобальные переменные имеют значения логического типа. Хотя каждая из этих переменных хранит какую-то свою информацию, вместе они могут дать очень полезные сведения о браузере. В таблице на рис. 14.4 представлены данные выполнения оператора AND (&&) (логическое "и") в условной конструкции и значения двух глобальных переменных. Например, если нужно, чтобы операторы в условной конструкции выполнялись только для Ш4, условие для блока if будет выглядеть так. if (isIE4 && !isW3C) {...} Tsffi4 true true false false isW3C true false true false isIE4&&isW3C Ш5+ Только 1Е4 Только W3C (не IE) Старые браузеры Рис. 14.4. Таблица значений для оператора AND и двух глобальных переменных Поскольку в Ш5+ объектные модели Microsoft и W3C перекрываются, то при запуске сценария придется определить используемую модель для каждого случая. Может возникнуть необходимость организовать вложенные условные конструкции if. Если, скажем, сначала сценарий будет развиваться по варианту W3C, то IE5+ запустит ветвь сценария с синтаксисом W3C DOM. Динамическое содержимое Глобальные переменные ветвления могут использоваться как функциями, вызываемыми обработчиками событий, так и сценариями, выполняемыми при загрузке страницы. Второй вариант бывает полезен тогда, когда необходимо при загрузке страницы для пользователей одних типов браузеров показывать один документ HTML, а для пользователей других типов браузеров — другой. В таком случае вызывается ячейка таблицы, в которой отображается результат вычислений формы в HTML. В некоторых браузерах результат отображается в текстовом поле таблицы. В не поддерживающих сценарии браузерах для отправки данных формы используется специальная кнопка. В разделе Body страницы в сценарии для отображения результата применяются элемент td и метод document .write (). Для того чтобы в ранних версиях Netscape Navigator не возникало проблем, следует динамически записывать не только содержимое ячейки, но и весь элемент td. Если большое количество пользователей работает со старыми версиями Netscape Navigator, имеет смысл динамически записать всю таблицу. Ниже показано, какой будет структура соответствующей формы и таблицы. <form name="calculator" action="http://xxx/cgi-bin/calculate.pi" onsubmit="return false"> <table> <tr> <td>...</td> <script type="text/javascript"> if (isIE4 || isW3C) { document.write("<td id='result'>0</td>"); } else { 230 Часть III. Объекты документа
document.write("<td>"); document.write("<input type='text' name='result' size='10f value='0' />"); document.write("</td>"); } </script> <noscript> <td>Click 'Submit' for Results</td> </noscript> </tr> </table> <noscript> <input type="submit" /> </noscript> </form> В предыдущем программном коде предполагалось, что все другие ячейки таблицы содержат текстовые поля, обработчики событий onchange которых запускают сценарии для выполнения вычислений. Эти сценарии выполняются по-разному для браузеров двух различных классов в соответствии с их объектными моделями. function calculate(form) { var results; // Инструкции для вычисления значения переменной results if (isIE4) { document.all.result.innerText = results; } else if (isW3C) { document.getElementById("result").childNodes[0].nodeValue = results; } else { document.calculator.result.value = results; Для того чтобы добавить динамическое содержимое в NN4, придется потрудиться немного больше. Решение проблемы обычно заключается в использовании элемента div внутри элемента span. Первый позиционируется на странице жестко, второй — относительно других элементов. После этого в сценариях можно вызвать метод document. write () для создания нового содержимого глубоко вложенного элемента div. При этом система ссылок будет достаточно сложной, поскольку приходится указывать документы и слои. Однако независимо от того, как далеко разработчик страницы зайдет в своем желании добавить в NN4 динамическое содержимое, браузер NN4 не будет автоматически масштабировать таблицы или ячейки, чтобы подогнать щ размеры под размеры текста. Без автоматического воссоздания страницы, которая используется в Г£5+ и браузерах W3C DOM, запись данных на позиционируемый слой в NN4 не приведет к перемещению остального содержимого страницы. Радикальный подход Под "радикализмом" в данном случае подразумевается желание создавать страницы с наиболее полным использованием возможностей DHTML, включая позиционируемые элементы на странице. Ведь перетаскивать элементы так весело! Применение подобного рода характеристик требует предварительного анализа будущей пользовательской аудитории и используемых этой аудиторией типов браузеров. В то время как Глава 14. Основы объектной модели документа 231
некоторые средства DHTML (например, CSS) при работе с браузерами устаревших версий с трудом поддерживаются (содержимое отображается, хотя не всегда в наилучшем виде), с позиционируемыми элементами дело обстоит совсем плохо. Дело в том, что в старых версиях браузеров атрибуты CSS, отвечающие за размещение элементов на странице, порядок отображения в стеке и режим отображения полностью игнорируются. Когда такая страница загружается в браузер поколения ниже четвертого, все элементы упорядочиваются в соответствии с их размещением в исходном коде страницы. И те элементы, которые, предполагалось, будут позиционированными, скрытыми или наложенными на другие элементы, отображаются "в старом добром стиле". Для того чтобы добиться наибольшего эффекта, при попытке пользователя получить доступ к данному Web-узлу следует провести предварительное тестирование версии браузера, используемого этим пользователем. Делать это лучше "на лету"; все браузеры, которые не удовлетворяют требованиям страницы, должны отсеиваться заранее. Эти браузеры можно перенаправлять "мимо" данного узла или к другой странице, где они смогут получить необходимую информацию (хотя, наверняка, и не в таком привлекательном виде, как на основной странице). Для этих целей создаются индексные страницы ветвления. О них речь уже шла в предыдущей главе. Когда не поддерживающие режим DHTML браузеры будут отфильтрованы, ситуация станет проще, но не до конца. Положительным остается следующий момент: теперь не нужно ломать голову, как предусмотреть всевозможные проблемы с версиями старых, не всегда полностью отлаженных, браузеров. Но все равно придется решать, какую из трех моделей позиционирования элементов выбрать: Ш4+, NN4 или W3C. За редким исключением (если используются браузеры только одного конкретного типа или те, что поддерживают только один стандарт DOM), наверняка возникнет желание заручиться поддержкой хотя бы для двух из них. Из перечисленных трех моделей модель NN4, с точки зрения взаимодействия с HTML, является наилучшей. Если же использовать позиционируемые элементы div и span, то во всех поддерживающих DHTML браузерах, кроме NN4, содержимое страницы будет, скорее всего, отображаться идентично. Поэтому логично было бы в разделе Body ввести сценарий, который динамически генерирует HTML-код, используя при этом для NN4 дескриптор <1ауег> и позиционируемые элементы <div> для остальных браузеров. I Браузеры IE4+ могут использовать одну и ту же объектную модель, однако к кс- ЙНшшшщ дам DHTML в разных браузерах это не относится. Microsoft внесла изменения * ^-и* в отдельные атрибуты стилей так, что стандартам CSS больше соответствует IE5.X. В IE6 реализована полная поддержка CSS Level 1 Использование библиотек сценариев Как и с обычными страницами, при использовании динамического содержимого также можно использовать библиотеки сценариев. Библиотеками являются внешние файлы с расширением . j s и содержащие фрагменты кода сценария. Сценарии могут иметь самое разное назначение (для использования в методе document .write () в начальной странице и для организации взаимодействия с пользователем). Учитывая то, что не поддерживающие DHTML браузеры были уже отсеяны ранее, в таких сценариях остается проверить только то, для какой объектной модели следует загружать библиотеку. var isIE4 = ((navigator.appName.indexOf("Microsoft") == 0 && parselnt(navigator.appVersion) == 4)); var isW3C = (document.documentElement) ? true : false; if (isW3C) { // Приоритетность предоставляется модели W3C IE5+ document.write("<script type='text/javascript' src='page3_W3C.j s'> <" + "\/script>"f; } else if (isIE4) { 232 Часть ///. Объекты документа
document.write("<script type='text/j avascript' src='page3_IE4. j s' > <" + "\/script>"); } else { document.write("<script type='text/javascript' src='page3 generic.js'><" + "\/script>"); } В каждом операторе создания дескриптора <script> используется отдельный файл, который применим при вызове метода document .write О только в указанных браузерах (особенно в NN4). Когда эти библиотеки будут указаны в коде страницы, в операторах сценария из этих библиотек в дальнейшем можно вызывать функции генерирования конкретного элемента или набора элементов в объектной модели HTML, оптимизированной для текущего браузера. Конечно, совсем не обязательно для каждой модели использовать свою библиотеку. Может оказаться удобным хранить все сценарии в одной библиотеке и использовать индексную сортировку для разных типов браузеров. Такую сортировку в библиотеках удобно реализовать с помощью глобальных переменных сценария начальной страницы HTML. Библиотеку с помощью метода детектирования объектов можно сделать вообще самодостаточной. Обработка событий Благодаря тому, что в модели событий W3C DOM реализована схема передачи событий вверх по структуре, практически идентичная той, которая имеется в Ш4+, эта модель событий может с успехом использоваться в браузерах стандарта Ш4+ и W3C DOM. Тем не менее, незначительные различия все же есть. В Ш4+ объект события не передается в качестве параметра функции, вызываемой обработчиком события. Наоборот, объект события Ш event является свойством объекта окна window. Поэтому в функциях нужно проверять передаваемый параметр; в случае использования Ш на его место подставляют объект window. event. function calculate(evt) evt = (evt) ? evt : window.event; // Операторы обработки события } Придется проверять и другие свойства событий в сценарии. Например, в Ш целевой объект, получающий событие, называется srcElement, в то время как в W3C DOM это target. Отмена поведения, заданного объекту по умолчанию (например, отменить предоставление формы в случае отрицательного результата проверки правильности ее содержимого) в этих моделях выполняется также по-разному (хотя старый метод возвращения обработчиком события HTML результата return false будет работать). Более подробно эта тема рассмотрена в главе 25. Режимы совместимости стандартов Как Microsoft, так и Netscape/Mozilla в свое время создали и использовали в своих браузерах такие средства CSS, которые в будущих стандартах оказались неприемлемыми (в результате противостояния так и не родилась истина). Для компенсации возникшей разницы в поддерживаемых объектных моделях и обеспечения разработчика возможностью выбора рабочей среды создатели браузеров решили пополнить HTML новым дескриптором заголовка документа <!DOCTYPE>. С его помощью разработчики могут указать, каким стандартам соответствует создаваемый ими документ: старым или новым. К сожалению, элемент DOCTYPE поддерживается только современными версиями браузеров — WinIE6, МасШ5 и Mozilla. Глава 14. Основы объектной модели документа 233
Если разница между двумя описанными выше режимами программирования не очень велика, то поддерживаемые в Ш6 средства CSS и динамического HTML не всегда совместимы со стандартами. В частности, это касается элементов с рамками, полями и заливкой. К тому же, размер элементов в Ш6 изменяется несколько не так, как это принято в стандартах CSS. Чтобы перевести современные браузеры в режим поддержки стандартов, вам необходимо включить в верхнюю часть документа следующий элемент. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//ENn "http://www.w3.org/TR/REC-html40/loose.dtd"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http :.//www. w3.org/TR/REC-html40/frameset. dtd" > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtmll/DTD/xhtmll-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtmll/DTD/xhtmll-frameset.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtmll/DTD/xhtmll-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtmlll/DTD/xhtmlll.dtd"> Обратите внимание, что старые версии Winffi5, Winffi5.5 полностью игнорируют режим поддержки стандартов и работают исключительно в старом режиме, независимо от указанных в элементе <! DOCTYPE> настроек. Тем не менее, добавление этого дескриптора вполне оправдано, поскольку в современных браузерах переход в режим совместимости является целесообразным. Мы поедем, мы помчимся... В последних двух главах рассматривались вопросы, описывающие базовый язык и объектные модели. То, о чем выше шла речь, должен знать и уметь каждый, кто разрабатывает страницы с использованием JavaScript. Главная наша задача— научить читателя самостоятельно принимать решения о приоритетности факторов, влияющих на методы создания страниц. С этого момента вся ответственность при поиске "золотой середины" ложится на ваши плечи. В следующих главах частей Ш и IV более подробно будут описываться особенности базового языка и объектных моделей. Эти знания помогут вам в дальнейшем сориентироваться в том, какие объекты, свойства, методы и обработчики событий разумнее всего использовать в собственных программных разработках. Это же относится и к возможности использования браузеров разных типов. Большинство приведенных примеров являются готовыми страницами HTML. Их можно загружать в любой браузер и смотреть, как они выполняются. Используйте приложение The Evaluator (глава 13). С его помощью удобно отслеживать вносимые изменения в файлы и проверять уровень своих познаний JavaScript и характеристик браузеров разных типов. Язык и объектные модели постоянно развиваются и совершенствуются. Объем словаря терминов языка программирования растет просто фантастическими темпами. Чтобы все это освоить, нужно время. Не стоит пытаться запомнить абсолютно все термины. Главное — понять основные подходы. Терминология никуда не денется. Упорство и труд все перетрут! 234 Часть III. Объекты документа
Основные объекты HTML-элементов xplorer 4+ и Mozilla-совместимые браузеры задают большой набор объектов, представляющих собой "основные" элементы языка HTML и повсеместно применяемые в сценариях. Основные элементы можно разделить на две группы. Одна группа, в которую входят, например, элементы b и strike, определяет стили шрифтов, применяемые к вложенным текстовым последовательностям. Потребность в подобных элементах (и объектах, представляющих эти элементы) постепенно исчезает по мере того, как многие браузеры расширяют поддержку стилевых спецификаций. Вторая группа элементов контекстно изменяет содержимое, заключенное в открывающий и закрывающий дескрипторы. Примерами контекстных элементов могут служить hi, blockquote и широко используемый элемент р. Зачастую браузеры используют специальные методы представления контекстных элементов по умолчанию (например, увеличенный полужирный шрифт для дескриптора <hl>), однако нельзя считать первичной целью таких дескрипторов получение элементов определенного вида. Ни один формальный стандарт не указывает явно, что текст внутри элемента em должен быть отображен курсивом: такой стиль стал традицией лишь благодаря браузерам первых версий. Все эти основные элементы содержат большое количество используемых в сценариях свойств, методов и обработчиков событий, которые присущи не только основным элементам, но и всем элементам, отображение которых возможно. Это могут быть даже дополнительные, специфические дня данного элемента свойства, методы и/или обработчики событий, о которых будет рассказано подробно в следующих главах этого обзора. Общие свойства, методы и обработчики событий для каждого элемента будут подробно описаны лишь в этой главе (кроме случаев, когда с некоторыми объектами связано определенное поведение, ошибка или особенность применения). В последующих главах описание каждого объекта включает список тех его свойств, методов и обработчиков событий, которые являются уникальными для него и не включают общие элементы (это позволяет избежать трудностей при поиске свойств, специфических для данного объекта).
Общие объекты В табл. 15.1 перечислены все объекты, которые относятся к "основным" в JavaScript. Все они обладают общими свойствами, методами и обработчиками событий, (см. следующие разделы) и не содержат специальных элементов, требующих отдельного рассмотрения. Объекты форматирования Контекстные объекты ь big center i nobr rt ruby s small strike sub sup tt u wbr acronym address cite code dfn del div em ins kbd listing P plaintext pre samp span strong var xmp Свойства Методы Обработчики событий accessKey all attributes behaviorUrns canHaveChildren canHaveHTML childNodes children className clientHeight addBehavior() addEventListener() appendChildO applyElement() attachEvent() blurO clearAttributes() clickO cloneNode() componentFromPoint() onactivate onbeforecopy onbeforecut onbeforedeactivate onbeforeeditfocus onbeforepaste onblur onclick oncontextmenu oncontrolselect 236 Часть III. Объекты документ»
Продолжение таблицы Свойства Методы Обработчики событий clientLeft clientTop clientwidth content Ed it able currentStyle dataFld dataFormatAs dataSrc dir disabled document filters firstChild height hideFocus id innerHTML innerText isContentEditable isDisabled isMultiLine isTextEdit lang language lastChild length localName namespaceURI nextSibling nodeName nodeType nodeValue offsetHeight offsetLeft offsetParent offsetTop offsetWidth outerHTML contains() detachEvent() dispatchEvent() fireEvent() focus() getAdj acentText() getAttribute() getAttributeNode() getAttributeNodeNS() getAttributeNSO getBoundingClientRect() getClientRects() getElementsByTagName() getElementsByTagNameNS() getExpression() hasAttribute() hasAttributeNSO hasAttributes() hasChildNodes() insertAdjacentElement() insertAdj acentHTML() insertAdj acentText() insertBefore() item() isSupportedO mergeAttributes() normalize() releaseCapture() removeAttribute() removeAttributeNode() removeAttribute()NS removeBehavior() removeChildO removeEventListener() removeExpression() removeNode() replaceAdjacentText() replaceChildO oncopy oncut ondblclick ondeactivate ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop onfilterchange onfocus onhelp onkeydown onkeypress onkeyup onlosecapture onmousedown onmouseenter onmouseleave onmousemove onmouseout onmouseover onmouseup onpaste onprope rtychange onreadystatechange onresize onresizeend onresizestart onselectstart Шва 15. Основные объекты HTML-элементов 237
Окончание таблицы Свойства Методы Обработчики событий outerText owne rDocument parentElement parentNode parentTextEdit prefix previousSibling readyState recordNumber runtimeStyle scopeName scrollHeight scrollLeft scrollTop scrollWidth sourcelndex style tablndex tagName tagUrn title uniqueID replaceNode() scrollIntoView() setActive() setAttribute() setAttributeNode() setAttributeNSO setAttributeNodeNS() setCapture() setExpression() swapNode() tags() urns() Синтаксис Для доступа к свойствам или методам элемента используется следующий код. (IE4+) [document. al 1. ] идентификаторОбъекта. свойство \ метод( [параметры]) (IE5+/W3C) document. getElementByld {идентификаторОбъекта) . свойство \ метод ( [параметры] ) Описание объектов Все объекты, перечисленные в табл. 15.1, представляют в DOM элементы HTML, которые влияют или на стиль шрифта, или на контекстное содержимое части элемента HTML. Большой набор свойств, методов и обработчиков событий, связанных с этими объектами, применим, фактически, ко всем объектам DOM, представляющим элементы HTML. Все обсуждаемые в этой главе подробности применимы к десяткам объектов, описанных в последующих главах. 238 Часть III. Объекты документа
Свойства accessKey Значение: односимвольная строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Для многих элементов можно указать клавишу (букву, цифру или символ пунктуации), нажатие которой в сочетании с <Alt> (в ОС Win32) или <Ctrl> (в MacOS) активизирует этот элемент. Активный элемент — это тот, который отвечает в данный момент за действия, выполняемые с помощью клавиатуры. Если активный элемент находится за пределами видимой области, документ будет прокручен таким образом, чтобы отобразить его на экране (смотрите также метод scrollIntoView ()). Указанный символ может вводиться в верхнем или нижнем регистре, однако распознания регистра не происходит. Если один символ присвоить нескольким элементам, то значение accessKey позволит циклически просмотреть их все. В некоторых случаях браузер Internet Explorer предоставляет свойству accessKey дополнительные возможности. Например, если значение accessKey присвоить объекту элемента label, то активным станет тот элемент формы, которой связан с этой надписью. Кроме того, когда активной становится кнопка, нажатие клавиши пробела приводит к тому же эффекту, что и щелчок мыши на ней. Обратите внимание на выбор клавиш в качестве значений accessKey. Если присвоить значение, которое обычно используется для доступа к встроенным меню браузера в Windows (например <Alt+F> для обращения к меню Файл), то оно изменит поведение браузера по умолчанию. Для пользователей, которые привыкли управлять меню с клавиатуры, такое использование комбинаций клавиш может показаться неудобным. Пример В листинге 15.1 приведен пример использования свойства accessKey для управления клавиатурой при навигации по Web-странице. После загрузки этого сценария измените окно браузера таким образом, чтобы скрыть страницу под второй разделительной линией. Введите символ в раздел Settings и нажмите <Enter> (часто при этом компьютер издает гудок). Далее нажмите <Alt> (в Windows) или <Ctrl> (в Мае) и нажмите эту же клавишу. Вы должны увидеть элемент, расположенный под второй разделительной линией. <html> <head> <title>accessKey Property</title> <script type="text/javascript"> function assignKey(type, elem) { if (window.event.keyCode ==13) { switch (type) { case "button": document.forms["output"].accessl.accessKey = elem.value; break; case "text": document.forms["output"].access2.accessKey = elem.value; break; Глава 15. Основные объекты HTML-элементов 239
case "table": document.getElementByld("myTable").accessKey = elem.value; } return false; } } </script> </head> <body> <hl>accessKey Property Lab</hl> <hr /> Settings:<br /> <form name="input"> Assign an accessKey value to the Button below and press Return: <input type="text" size="2" maxlength="l" onkeypress="return assignKey('button', this)" /><br /> Assign an accessKey value to the Text Box below and press Return: <input type="text" size="2" maxlength="l" onkeypress="return assignKey (' text' , this)" /t><br /> Assign an accessKey value to the Table below (IE5.5+ only) and press Return: <input type="text" size="2" maxlength="l" onkeypress="return assignKey('table', this)" /> </form> <br /> Then press Alt (Windows) or Control (Mac) + the key.<br /> <em>Size the browser window to view nothing lower than this line.</em> <hr /> <form name="output" onsubmit="return false"> <input type="button" name="accessl" value="Standard Button" /> <input type="text" name="access2" /> </form> <table id="myTable" cellpadding="10" border="2"> <tr> <th>Quantity</th> <th>Description</th> <th>Price</th> </tr> <tbody bgcolor="red"> <tr> <td width="100">4</td> <td>Primary Widget</td> <td>$14.96</td> </tr> <tr> <td>10</td> <td>Secondary Widget</td> <td>$114.96</td> </tr> </tbody> </table> </body> </html> См. также метод scrollIntoView (). 240 Часть ///. Объекты документа
all Значение: массив вложенных объектов элементов Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство all представляет собой набор (массив) всех элементов HTML и (в Ш5+) дескрипторов XML в области действия текущего объекта. Элементы массива расположены в таком же порядке, как в исходном коде. Массив не включает в себя текстовое содержимое элементов. Для элементов-контейнеров языка HTML порядок появления в исходном коде зависит от позиции открывающего дескриптора элемента, а закрывающие дескрипторы не учитываются. Для элементов языка XML все закрывающие дескрипторы включаются в массив отдельно. Каждый набор document. all содержит объекты элементов html, head, title и body даже тогда, когда они опущены в исходном коде. Объектная модель создает эти объекты для каждого документа, загруженного в окно или фрейм. Если ссылка document.all имеет наиболее общее применение, то свойство all существует для любого элемента-контейнера. Например, document .forms [0] .all предоставляет доступ ко всем элементам, определенным в первой форме документа. Доступ к любому элементу возможен благодаря указанию идентификатора, присвоенного его атрибуту id, в строковой форме (а также целочисленного индекса). Вместо использования малоэффективной функции eval () для преобразования строки в ссылку на объект достаточно просто указать имя элемента как индекс массива. var paragraph = document.all["myP"] Internet Explorer для индексов одного набора позволяет использовать и квадратные, и круглые скобки. Два следующих примера выполняются одинаково. var paragraph = document.all["myРи] var paragraph = document.all("myP") В тех редких случаях, когда несколько элементов набора all имеют одинаковый идентификатор, синтаксис, в котором представлен строковый индекс, отвечает набору идентично именованных элементов. Тем не менее, можно воспользоваться вторым аргументом (в круглых скобках) для указания целочисленного индекса в исходном наборе, соответствующем определенному элементу. var secondRadio = document.all("groupO",1) Более приемлемым вариантом для доступа к элементам набора является метод item() (о нем рассказано далее в этой главе). var secondRadio = document.all.item("groupO",1) Для извлечения из набора определенного поднабора элементов, названия дескрипторов которых соответствуют заданному критерию, используется метод tags () (подробнее о нем рассказано далее в этой главе). Свойство all браузера IE эмулируется в некоторых других типах браузеров. Фрагмент кода, необходимый для этого, приведен в главе 18 (используется метод document. getElementByld ()). Пример Используйте приложение Evaluator (глава 13) для изучения коллекции all. Введите в нижнее текстовое поле одно из следующих выражений. Для каждого из них внимательно изучите возвращаемый результат. document .all myTable.all myP.all Глава 15. Основные объекты HTML-элементов 241
Если вы встретите в коллекции нумерованный элемент, то сможете определить, какой дескриптор сопоставляется с этим элементом. Например, если для элемента document. all возвращен результат document .all. 8= [object], то введите в самое верхнее поле следующее выражение, document.al1[8].tagName См. также методы item (), tags (). attributes Значение: массив, содержащий атрибуты объекта Только для чтения Совместимость: WinIE5+, МасГЕ5+, NN6+, Mozl+, Safari* Свойство attributes представляет собой массив атрибутов, заданных для элемента. В браузере Ш5+ этот массив содержит каждое возможное свойство, определенное для элемента,— даже в том случае, когда атрибут не указан в дескрипторе HTML явно. Кроме того, любые атрибуты, заданные при выполнении сценария, например с помощью метода set At tribute О, не изменяют значений массива. Другими словами, в Ш5+ массив attributes зафиксирован таким образом, что все атрибуты, не указанные явно в дескрипторе HTML, принимают значения по умолчанию. Свойство attributes в браузерах Mozilla возвращает массив, называемый картой именованных узлов (в терминологии W3C DOM), а также объект со своими свойствами и методами, с помощью которых сохраняются и считываются значения атрибутов. Например, для доступа к индивидуальным объектам атрибутов в W3C DOM можно воспользоваться методами getNamedltem (имяАтрибута) и item (индекс). В IE5+ и Mozl+ реализованы различные представления о том, каким должен быть объект атрибута. В табл. 15.2 приведены свойства объекта атрибута, определенные в двух объектных моделях. Больший набор свойств в Mozl+ указывает на зависимость объектной модели браузера от модели наследования узлов W3C DOM, которая была рассмотрена в предыдущей главе. Свойство attributes childNodes firstChild lastChild localName name nameSpaceURI nextSibling nodeName nodeType nodeValue ownerDocument ownerElement parentNode IES+ Нет Нет Нет Нет Нет Нет Нет Нет Да Нет Да Нет Нет Нет Moz1+ "1а Да Да Да Да Да Да Да Да Да Да Да Да Да Описание Массив вложенных объектов атрибутов (null) Массив дочерних узлов Первый дочерний узел Последний дочерний узел Имя в текущей области определения Имя атрибута URI пространства имен XML Следующий узел-всестраи Имя атрибута Тип узла (2) Значение, присвоенное атрибуту Ссылка на объект document Ссылка на узел элемента Ссылка на родительский узел 242 Часть III. Объекты документа
Окончание табл. 15.2 Свойство IE5+ Moz1+ Описание prefix Нет Да Префикс пространства имен XML previoussibiing Нет Да Предыдущий узел-асестраи specified Да Да Указывает, был ли атрибут задан в дескрипторе явно (значение логического типа) value Нет Да Значение, присвоенное атрибуту Наиболее полезным является свойство specified, имеющее логический тип. В ТЕ оно позволяет узнать, указан ли атрибут в дескрипторе явно. Поскольку в Mozl браузер возвращает только атрибуты, заданные явно, это значение всегда истинно. Пример Используйте приложение Evaluator (глава 13) при изучении массива attributes для отдельных элементов документа. Введите каждое из приведенных ниже выражений в нижнее поле; возвращаемый массив значений вы увидите в поле Results. document.body.attributes document .getElementByldC'myP") .attributes document. getElementByld ("myTable") . attributes В Ш5+ и W3C DOM-совместимых браузерах сравните возвращаемые в каждом случае результаты. Для ознакомления со свойствами отдельного атрибута в Winffi5+ в нижнем поле введите следующее выражение. document.getElementByld ("myP") .attributes ["class"] В браузерах Macffi5 и W3C DOM используется следующий синтаксис. document.getElementByld("myP").attributes.getNamedltem("class") См. также методы getAttribute (), mergeAttributes (), removeAttribute (), setAttribute (). behaviorUrns Значение: массив URN-строк поведения Только для чтения Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Свойство behaviorUrns предназначено для того, чтобы содержать список адресов в форме URN (Uniform Resource Names — унифицированных имен объектов) всех типов поведения, назначенных текущему объекту. При отсутствии поведений длина массива равна нулю. Однако на практике Ш5+ всегда возвращает массив пустых строк. Возможно, потенциальным влиянием сценария на список URN является риск потери конфиденциальности. Следующая функция используется в более сложных HTML-поведениях, поддерживаемых в WinlE (см. листинг 15.19). Она возвращает длину массива behaviorUrns, а также отображает URL-адрес присоединенного поведения (в случае возвращения значения). function showBehaviors () { var num = document.getElementByldC'myP").behaviorUrns.length; var msg = "The myP element has " + num + " behavior(s). "; if (num > 0) { msg += "Name(s): \r\n"; for (var i = 0; i < num; i++) { msg += document.getElementByldC'myP").behaviorUrns[i] + "\r\n"; Глава 75. Основные объекты HTML-элементов 243
alert(msg); } См. также метод urns (). canHaveChildren Значение: булевого типа Только для чтения Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Полезное в некоторых ситуациях при обработке динамического содержимого свойство canHaveChildren показывает, может ли определенный элемент содержать дочерние элементы (вложенные элементы). Большинство элементов, содержащих открывающий и закрывающий дескрипторы (в частности, основные элементы, о которых рассказано в этой главе), могут содержать вложенные элементы. В современных объектных моделях вложенный элемент называется дочерним элементом своего родительского контейнера. Пример В листинге 15.2 приведен пример использования свойства canHaveChildren для визуального распознавания элементов документа, которые имеют вложенные элементы. В данном случае различие между объектами, имеющими вложенные элементы, и объектами, не имеющими таковых, задается специальным цветом. Первая кнопка на странице позволяет окрасить каждый отображаемый на экране объект документа красным цветом (изменяется свойство color). Таким образом, все элементы документа (даже не имеющие дочерних элементов, на: пример, hr и input) приобретают указанный цвет. Если же щелкнуть на большей кнопке, та цвет изменит только те объекты, которые имеют вложенные элементы. <html> <head> <title>canHaveChildren Property</title> «script type="text/javascript"> function colorAHO { var elems = document. get Element sByTagName (■•*■») ; for (var i = 0; i < elems.length; i++) { elems[i].style.color = "red"; function colorChildBearingO { var elems = document.getElementsByTagName("*"); for (var i = 0; i < elems.length; i++) { if (elems[i].canHaveChildren) { elems[i].style.color = "red"; </script> </head> <body> <hl>canHaveChildren Property Lab</hl> <hr /> 244 Часть ///. Объекты документ
<form name="input"> <input type="button" value="Color All Elements" onclick= "colorAll () " /xbr /> <input type="button" value="Reset" onclick="history.go(0)" /> <br /> <input type="button" value="Color Only Elements That Can Have Children" onclick="colorChildBearing()" /> </form> <br /> <hr /> <form name="output"> <input type="checkbox" checked="checked" />Basic checkbox *<input type="text" name="access2" value="Some text." /> </form> <table id="myTable" cellpadding="10" border="2"> <tr> <th>Quantity</th> <th>Description</th> <th>Price</th> </tr> <tbody> <tr> <td width="100">4</td> <td>Primary Widget</td> <td>$14.96</td> </tr> <tr> <td>10</td> <td>Secondary Widget</td> <td>$114.96</td> </tr> </tbody> </table> </body> </html> См. также: свойства childNodes, firstChild, lastChj.ld, parentElement, parent Node; методы appendChild (), has ChildNodes (), removeChild (). canHaveHTML Значение: булевого типа Только для чтения Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- He все (хотя многие) элементы HTML являются контейнерами HTML-кода. Свойство canHaveHTML позволяет сценарию проверить, может ли определенный объект включать HTML-код, например при вставке или замене методами объекта. Для элемента р, например, данное свойство имеет значение true, а для элемента br — false. Пример Используйте приложение Eyaluator (глава 13) для изучения свойства canHaveHTML. Введите каждое из приведенных ниже выражений в нижнее поле; возвращаемый массив значе- ний вы увидите в поле Results. document.getElementByld("input").canHaveHTML document.getElementByld("myP").canHaveHTML Глава 15. Основные объекты HTML-элементов 245
Первое выражение возвращает значение false, поскольку элемент input (в данном случае верхнее текстовое поле) не имеет вложенных HTML-элементов. Наряду с этим элемент туР принимает HTML-содержимое. См. также методы appendChild (), insertAdj acentHTML (), insertBef ore (). childNodes Значение: массив объектов узлов Только для чтения Совместимость: WinIE5+, MacIE5+, NN6+, Mozl+, Safaril+ Свойство childNodes представляет собой массив объектов узлов, содержащихся в текущем объекте. Обратите внимание, что дочерние узлы состоят из объектов элементов и текстовых узлов. В зависимости от содержимого текущего объекта, количество элементов в childNodes и число наборов дочерних узлов могут отличаться. Если массив childNodes просматривается в цикле for с целью обработки последовательности элементов HTML (или XML), помните, что браузер может воспринимать пробелы в исходном коде (пустые строки или простые символы разрыва строки между элементами) как текстовые узлы. Эта потенциальная проблема присутствует в Mac IE5 и Moz1 (возможно, она будет исправлена в последующих версиях). Лишние текстовые узлы, если они присутствуют в документе, как правило, окружают блоковые элементы. Большая часть циклов, просматривающих массив childNodes, предназначена для проверки, подсчета или изменения узлов элементов внутри набора. Если таковой является задача и вашего сценария, то до выполнения обработки проверьте каждый узел из массива childNodes и убедитесь, что свойство nodeType имеет значение 1 (элемент). В ином случае такой узел необходимо пропустить. Примерная структура цикла выглядит следующим образом. for (var i = 0; i < myElem.childNodes.length; i++) { if (myElem.childNodes[i].nodeType == 1) { операторы обработки i-го узла } ) Присутствие "скрытых" текстовых узлов влияет также и на свойства f irstchild и lastchild, описанные далее в этой главе. Пример В листинге 15.3 содержится пример функции просмотра дочерних узлов заданного родительского узла. Функция walkChildrenNodes О, представленная в листинге, собирает сведения и возвращает иерархическую структуру дочерних узлов для HTML-элемента документа (по умолчанию) или любого другого элемента, идентификатор которого подставлен в качестве аргумента. Эта функция встроена в приложение The Evaluator, поэтому структура дочерних узлов указывается именно для этой страницы. Введите в верхнем поле приложеюц The Evaluator следующие выражения. walkChildNodesO walkChildNodes(getElementByld("myP")) Результат, возвращаемый функцией, представляет взаимоотношения между дочерними узлами заданного элемента. Функция просматривает вложенные элементы до самого нижнего уровня (пока все они не будут каталогизированы). Узлы подписываются соответствующим образом, чтобы их можно было легко идентифицировать и сравнить с элементами исходного HTML-кода. 246 Часть III. Объекты документ»
function walkChildNodes (objRef, n) { var obj; if (objRef) { if (typeof objRef == "string") { obj = document.getElementById(objRef); .} else { obj = objRef; } else { obj = (document.body.parentElement) ? document.body.parentE1ement : document.body.parentNode; } var output = "" ; var indent = ""; var i, group, txt; if (n) { for (i = 0; i < n; i++) { indent += "+ "; } else { n = 0; output += "Child Nodes of <" + obj.tagName; output += ">\n=====================\n"; group = obj.childNodes; л for (i - 0; i < group.length; i++) { output += indent; switch (group[i].nodeType) { case 1: output += "<" + group[i].tagName; output += (group[i].id) ? " ID=" + group[i].id : ""; output += (group[i].name) ? ■■ NAME=" + group [i] .name : ""; output += ">\n"; break; case 3 : txt = group[i].nodeValue.substr(0,15); output += "[Text:\,,M + txt.replace(/[\r\n] /g, "<cr>") ; if (group[i].nodeValue.length > 15) { output += "..."; } output += "\"]\n"; break; case 8: output += " [!COMMENT I]\n"; break; default: output += "[Node Type = " + group[i].nodeType + "]\n"; if (group[i].childNodes.length > 0) { output += walkChildNodes(group[i], n+1); »' return output; См. также: свойства nodeName, nodeType, nodeValue, parentNode; методы cloneNode (), hasChildNodes (), removeNode (), replaceNode (), swapNode (). Тлааа 15. Основные объекты HTML-элементов 247
children Значение: массив объектов элементов Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство children представляет собой массив объектов элементов, содержащихся в текущем объекте. В отличие от свойства childNodes, свойство children не учитывает текстовые узлы, а следует иерархии элементов HTML (и XML) с точки зрения текущего объекта. Текущий объект "видит** только прямые дочерние элементы. Если необходимо обратиться ко всем объектам элементов, вложенным внутрь данного объекта (независимо от уровня их вложенности), следует воспользоваться набором all. Пример В листинге 15.4 продемонстрировано, как с помощью свойства children можно просмотреть все дочерние узлы заданного элемента. Эта функция собирает сведения и возвращает иерархическую структуру дочерних узлов для HTML-элемента документа (по умолчанию) или любого другого элемента, чей идентификатор которого подставлен в качестве аргумента. Эта функция встроена в приложение The Evaluator, поэтому структура дочерних узлов указывается именно для этой страницы. Введите в верхнем поле приложения The Evaluator, запущенного в Ш5+, следующие выражения. walkChildrenO walkChildren("myP") Результат, возвращаемый функцией, представляет взаимоотношения между дочерними узлами заданного элемента. Функция просматривает вложенные элементы до самого нижнего уровня» пока все они не будут каталогизированы. Узлы подписываются соответствующим образом, чтобы их можно было легко идентифицировать и сравнить с элементами исходного HTML-кода. function walkChildren(objRef, n) { var obj; if (objRef) { if (typeof objRef == "string") { obj = document.getElementById(objRef); } else { obj ss objRef; } } else { obj = document.body.parentElement; } var output = ""; var indent = ""; var i, group; if (n) { for (i = 0; i < n; i++) { indent += "+ "; } } else { n = 0; output += "Children of <" + obj.tagName; output += »>\n=====================\n"; } group = obj.children; 248 Часть III. Объекты документ
} for (i = 0; i < group.length; i++) { output '+= indent + "<" + group[i].tagName; output += (group[i].id) ? " ID=" + group[i].id : и"; output += (group[i].name) ? " NAME=" + group[i].name output += ">\n"; if (group[i].children.length > 0) { output += walkChildren(group[i], n+1); } } return output; См. также: свойства canHaveChildren, f irstChild, lastChild, parentElement; методы appendChild (), removeChild (), replaceChild (). className Значение: строка Чтение/Запись . Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari* Имя класса— это идентификатор, присвоенный атрибуту class элемента. Чтобы навязать правило CSS нескольким элементам документа, следует присвоить один и тот же идентификатор атрибуту class этих элементов и использовать его (с точкой в начале) при выборе правила CSS. Свойство className позволяет применять различные правила CSS при управлении из сценария. Пример Стиль элемента имеет два состояния: "подключен" и "отключен". В листинге 15.5 свойству className назначается либо пустая строка, либо имя класса CSS-стиля. Если это свойство приравнивается пустой строке, то элемент hi форматируется соответственно правилам по умолчанию. Когда же вы щелкаете на кнопке, форматирование задается CSS-стилем, а не стандартными правилами. <html> <head> <title>className Property</title> <style type="text/ess"> .special {font-size:16pt; color:red} </style> <script type="text/javascript"> function toggleSpecialStyle(elemID) { var elem = (document.all) ? document.all(elemID) document.getElementByld(elemID); if (elem.className == "") { elem.className = "special"; } else { elem.className = ""; } } </script> </head> <body> Глава 15. Основные объекты HTML-элементов 249
<hl>className Property Lab</hl> <hr /> <form name="input"> <input type="button" value="Toggle Class Name" onclick="toggleSpecialStyle('headl')" /> </form> <br /> <hl id="headl">ARTICLE I</hl> <p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.</p> <hl>ARTICLE II</hl> <p>A well regulated militia, being necessary to the security of a free state, the right of the people to keep and bear arms, shall not be infringed.</p> </body> </html> Вы можете создать несколько вариантов правила стиля с различными идентификаторами выбора класса. См. также: объекты rule, stylesheet (глава 26); свойство id. clientHeight clientWidth Значения: целочисленное Только для чтения Совместимость: WinIE4+, МасГ£4+, NN7, Mozl+, Safari+ Два этих свойства содержат высоту и ширину содержимого элемента в пикселях. Их стали позволяют задавать параметры высоты и ширины. Теоретически эти величины не учитывают отступы, границы или поля, определяемые в таблицах стилей. Однако на практике ра> личные комбинации границ, отступов и полей влияют на эти значения самым неожиданньш образом. Один из наиболее надежных способов применения свойства clientHeight позволяет, например, определить, где заканчивается текст переполненного элемента. Для объекта document.body свойства clientHeight и clientWidth возвращают внутреннюю высоту и ширину окна или фрейма (плюс-минус несколько пикселей). Данные свойства замещают собой необходимые, но не существующие в Ш, свойства окна. В браузере Internet Explorer 5+ почти все объекты, представляющие элементы HTML, со* держат эти свойства. В ТЕЛ эти свойства применимы только к следующим объектам: body» button, caption, div, embed, f ieldset, legend, marquee, table, td, textarea, thn tr. Пример В листинге 15.6 для IE содержится пример динамического изменения содержимого страницы. В данном примере используются свойства clientHeight и clientWidth элемент* div, который представляет на странице текст абзаца. В таблице стилей задается только и» рина элемента div, поэтому текст абзаца вводится в документе в виде столбца. Свойстц clientHeght определяет высоту этого столбца. С его помощью на странице определяете! место отображения логотипа, который обычно располагается сразу же под объектом div, № зависимо от количества введенного в абзац текста. 250 Часть III. Объекты докумет
<html> <head> <title>clientHeight and clientwidth Properties</title> <script type="text/javascript"> function showLogoO { var paragraphW = document.getElementById("myDIV"). clientwidth; var paragraphH = document.getElementById("myDIV"). clientHeight; // устранение различия платформ Windows/Mac var paragraphTop = (document.getElementByld("myDIV"). clientTop) ? document.getElementByld("myDIV").clientTop : document.getElementByld("myDIV").offsetTop; var logoW = document.getElementByld("logo").style.pixelWidth; // горизонтальное центрирование логотипа в абзаце document.getElementByld("logo").style.pixelLeft = (ParagraphW-logoW) / 2; // Расположение изображения в конце абзаца document.getElementById("logo").style.pixelTop = paragraphTop + paragraphic- document .getElementByld ("logo") .style.visibility = "visible"; } </script> </head> <body> <button onclick^"showLogoO">Position and Show Logo Art</button> <div id="logo" style="position:absolute; width:12Opx; visibility:hidden"> <img alt="image" src="logo.gif" /> </div> <div id="myDIVM style="width:200px"> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,</p> </div> </body> </html> Чтобы правильно рассчитать расположение логотипа, примите во внимание, что свойство of f setTop задает расположение элемента div относительно его контейнера (объекта body). Пользователи Mac IE для этих целей применяют также свойство clientTop. В таком случае расположение логотипа рассчитывается следующим образом: к значению of f setTop прибавляется значение clientTop для элемента div (заносится в переменную paragraphTop). См. также свойства of f setHeight, of f setwidth. clientLeft clientTop Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Гяава 15. Основные объекты HTML-элементов 251
Назначение и имена свойств clientLeft и clientTop не совпадают. В отличие от clientHeight и clientWidth, которые соответствуют размеру содержимого элемента, свойства clientLeft и clientTop возвращают информацию о ширине границы элемента — при условии, что элемент позиционируемый. Если граница не задана или же элемент не позиционирован, эти значения равны нулю (хотя объект document. body может определить толщину в несколько пикселей в каждом из случаев). Если вам требуется вычислить левую верхнюю координату элемента, более подходящими в Winffi являются свойства of f set Left и of f set Top; однако, как показано в листинге 15.6, свойство clientTop возвращает вполне пригодное для использования в МасШ значение. В сущности, в ГЕ5+ все элементы имеют свойства clientLeft и clientTop; в ВЕ4 такие свойства присущи только объектам body, button, caption, embed, f ieldset, legend, marquee и textarea. См. также свойства of f setLef t, of f setTop. contentEditable Значение: булевоготипа Чтение/Запись Совместимость: WinIE5.5+, МасШ-, NN-, Moz-, Safari- B Ш5.5 представлена концепция редактируемого HTML-содержимого страницы. Дескрипторы элементов могут включать атрибут contenteditable, значение которого содержится в свойстве элемента contentEditable. По умолчанию значение этого свойства равно inherit; таким образом, свойство наследует установки контейнеров иерархической структуры HTML за пределами тела элемента. Если свойство contentEditable имеет значение true, то элемент и все вложенные в него элементы наследуют это значение, делая содержимое редактируемым; и наоборот, значение false отключает возможность изменения содержимого. Пример В листинге 15.7 продемонстрировано использование свойства contentEditable, которое позволяет редактировать текст Web-страницы. При щелчке на кнопке загруженной страницы выполняется функция toggle Ed it (), которая изменяет состояние "редактируемое™" текста на противоположное. Переключение состояния выполняется с помощью свойства contentEditable элемента div. Для большего эффекта текст абзаца приобретает красный цвет — таким образом сразу становиться ясно, какой элемент страницы подвергается изменению. <html> <head> <style type="text/css"> .normal {color: black} .editing {color: red} </style> <script type="text/javascript"> function toggleEditO { var newState = 'editableText.isContentEditable; editableText.contentEditable = newState; editableText.className = (newState) ? "editing" : "normal"; editBtn.innerText = (newState) ? "Disable Editing" : "Enable Editing"; } </script> <title> </title> 252 Часть III. Объекты документ
h, . </head> ;, <body> <hl>Editing Contents</hi> <hr /> <p>Turn on editing to modify the following text:</p> <div id="editableText"> Edit this text on the fly.... </div> <pxbutton id="editBtn" onclick="toggleEdit () " onfocus="this.blur() ">Enable Editing</buttonx/p> </body> </html> См. также свойство isContentEditable. currentStyle Значение: объект style Только для чтения Совместимость: Winffi5+t Macffi5+, NN-, Moz-, Safari- Каждый элемент имеет атрибуты стилей, даже если ими являются настройки браузера по умолчанию. Так как объект style элемента отражает только те свойства, которые были явно установлены операторами определения CSS-стилей, свойством style объекта element нельзя воспользоваться для чтения настроек стилей, примененных к элементу. Именно здесь и оказывается полезным свойство currentStyle. Это свойство возвращает предназначенный только для чтения объект style, содержащий значения всех свойств style, применимых к элементу. Если свойство style установлено оператором CSS явно или командами сценария, считывание свойства приводит к получению пра- ввльного значения. Таким образом, сценарий может запросить каждое свойство для проверки необходимости внесения изменений. Например, если текст находится внутри дескриптора <ет>, браузер по умолчанию использует для шрифта курсивное начертание. Это свойство никак ;не отражается в объекте style элемента (свойство f ontStyle), поскольку курсив не был установлен средствами CSS; с другой стороны, свойство currentStyle. f ontStyle объекта ^element содержит реальное свойство f ontStyle, соответствующее курсивному шрифту. Пример Для изменения свойства style вам необходимо обратиться к объекту style. Используйте приложение The Evaluator (глава 13) для сравнения этого свойства в объектах currentStyle и style. Например, неизмененная копия приложения содержит элемент em, который имеет идентификатор myEm. Введите в нижнее поле выражение document. get - ElementByldC'myEm") . style и нажмите <Enter>. Обратите внимание, что для большинства свойств значения не заданы. Теперь введите в нижнее поле выражение document .getElementByld ("myEm") . currentStyle. Теперь в результате у каждого свойства будет определенное значение. См. также объекты runtimeStyle, style (глава26); window.getComputedStyle () в W3C DOM-совместимых браузерах (глава 16). dataFld dataFormatAs dataSrc Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ5, NN-, Moz-, Safari- Г/шва 75. Основные объекты HTML-элементов 253
Свойства dataFld, dataFormatAs и dataSrc (вместе с такими специфическими для элемента свойствами, как dataPageSize и recordNumber) являются частью средств Internet Explorer внедрения данных с помощью элементов управления ActiveX. Internet Explorer версии 4 и выше для Win32 имеет несколько объектов ActiveX, которые встроены в браузер и используются для прямой передачи данных между Web-страницей и их источником. К источникам данных относят текстовые файлы, файлы XML, HTML и внешние базы данных. Внедрение данных является довольно серьезной темой, включающей обсуждение DSO (Microsoft Data Source Objects — объекты источников данных Microsoft), ODBC и JDBG Внедрение данных является мощным средством и используется не только администраторами баз данных. Поэтому обсуждение трех основных свойств— dataFld, dataFormatAs и dataSrc — затрагивает тему внедрения данных. С помощью средств внедрения данных любая страница способна получить доступ, сортировать, отображать и фильтровать (но не обновлять) данные, загруженные на страницу из внешнего текстового файла (обычно символом-разделителем данных является запятая или символ табуляции). Загрузить данные из внешнего текстового файла в документ позволяет средство TDC (Tabular Data Control — управление табличными данными). Ссылка на данные задается с помощью объекта TDC внутри дескриптора <object>H дополнительных параметров (например, URL текстового файла и символа-разделителя). Элемент ob j ect может находиться в любом месте документа внутри дескрипторов body. (Обычно их размещают в нижней части кода, чтобы отображение страницы происходило перед загрузкой элемента управления.) Ссылка на данные просто указывает их расположение браузеру, но сам по себе код страницы не отображает данные на странице. Тем, кому не приходилось работать со встроенными объектами в Ш, значение атрибута classid может показаться несколько странным. Некоторых пугает вид используемого для идентификации данных значения GUID (Globally Unique Identifier — глобальный уникальный идентификатор) объекта. Это значение необходимо указывать точно так, как показано в следующем примере, чтобы элемент ActiveX мог запуститься. Объект имеет в HTML следующий синтаксис. <object ID="objName" CLASSID="clsid:333C7BC4-460F-llD0-BC04 -0080С7055А83И> <param name="DataURL" value="url"> [необязательные дополнительные параметры] </object> В табл. 15.3 перечислены параметры, доступные для использования в объекте TDC. Обязательным является только параметр DataURL; остальные (например FieldDelim, UseHeader, RowDelim и EscapeChar) используются в зависимости от природы источника данных. Параметр Описание charSet Кодовая страница исходного файла с данными. Значение по умолчанию latini DataURL URL исходного файла с данными (относительный или абсолютный) EscapeChar Символы перехода, которые являются также разделителями данных. По умолчанию значение не установлено. Обычно указывают символ "V. FieldDelim Символ-разделитель полей в записи. По умолчанию запятая (,).&#09 ,- Language Код языка ISO исходных данных. По умолчанию en-us. TextQualif ier Дополнительный символ, окружающий поля данных. По умолчанию значение не установлено 254 Часть III. Объекты документе
Окончание табл. 15.3 Параметр Описание RowDelim Символ-разделитель записей. По умолчанию символ новой строки (nl) useHeader Имеет значение true, если первая строка данных в файле содержит имена полей. Значение по умолчанию false Значение, присвоенное атрибуту id элемента object, является идентификатором, с помощью которого сценарии взаимодействуют с данными после того, как и страница, и данные уже полностью загружены. Поэтому на странице могут загружаться только объекты TDC с уникальными именами, определяющими количество исходных файлов данных, которые требуется открыть одновременно. Исходное внедрение данных в элементы HTML обычно происходит при присвоении значений атрибутам элементов datasrc и dataf Id. Атрибут datasrc указывает на идентификатор DSO (совпадающий с атрибутом id элемента ob j ect с символом "решетки" впереди), а атрибут dataf Id— на имя поля, из которого следует извлечь данные. Когда внедрение данных выполняется для такого интерактивного элемента, как таблица, записи отображаются как последовательные строки таблицы (подробнее об этом см. далее). Если необходимо, чтобы элемент HTML (отличный от таблицы), который отображает данные, мог изменить их, следует указать значения свойств dataSrc и dataFld. Эти свойства применимы к поднабору элементов HTML, которым можно поставить в соответствие внешние данные: объекты a, applet, body, button, div, frame, iframe, img, input (большинство типов), label, marquee, object, param, select, span и textarea. В некоторых случаях источники данных могут содержать блоки форматированного HTML-текста, который необходимо отображать внутри элемента. Если не указано обратное, браузер отображает поля исходных данных как обычный текст — даже если в нем содержатся дескрипторы HTML-форматирования. Для того чтобы при отображении учитывался и код HTML, свойство dataFormatAs (или, скорее, атрибут дескриптора dataf ormatas) необходимо установить в значение html. По умолчанию оно имеет значение text. Пример Листинг 15.8 представляет простой документ, с которым связано два объекта TDC. Внешние файлы представлены документом U.S Bill of Rights, сохраненным в разных форматах. Первый файл будет представлен в традиционном текстовом формате с данными, разделенными символами табуляции — он содержит всего две записи. В первой записи приведены имена полей — "Article 1", "Article 2" и т.д. (которые разделены символами табуляции). Вторая запись содержит разделенные символами табуляции значения полей (они представлены в формате HTML). <hl>ARTICLE I</hlxp>Congress shall make...</p> Второй файл включает полный текст закона Bill of Rights в простом формате, не содержащем дескрипторы HTML. При загрузке кода из листинга 15.8 первая статья закона Bill of Rights отображается на странице в синей рамке. Кнопки на странице позволяют переходить от одной статьи к другой. Поскольку данные внешних файлов представлены в стандартных форматах, функции nextFieldO и prevField () легко определяют имя следующего поля и назначают соответствующее значение свойству dataField. В процессе открытия страницы в браузер загружаются все необходимые данные, поэтому операции перехода по статьям выполняются практически незамедлительно. Глава 15. Основные объекты HTML-элементов 255
<html> <head> <title>Data Binding</title> <style type="text/css"> #display {width:50Opx; border:1Opx ridge blue; padding:2Opx} .hiddenControl {display:none} </style> <script type="text/javascript"> function nextFieldO { var elem = document.getElementByld("display"); var fieldName = elem.dataFld; var currFieldNum = parselnt(fieldName.substring(7, fieldName.length),10); currFieldNum = (currFieldNum == 10) ? 1 : ++currFieldNum; elem.dataFld = "Article" + currFieldNum; } function prevFieldO { var elem = document.getElementByld("display"); var fieldName = elem.dataFld; var currFieldNum = parselnt(fieldName.substring(7, fieldName.length),10); currFieldNum = (currFieldNum ==1) ? 10 : --currFieldNum; elem.dataFld = "Article" + currFieldNum; } function toggleComplete() { if (document.getElementByldC'buttonWrapper").className == "") { document.getElementByld("display").dataSrc = "#rights_raw"; document.getElementByld("display").dataFld = "columnl"; document.getElementByld("display").dataFormatAs = "text"; document.getElementByldC'buttonWrapper").className = "hiddenControl"; } else { document. getElementByld ("display") .dataSrc = "#rights_html"; document. getElementByld ("display") .dataFld = "Articlel"; document.getElementByld("display") .dataFormatAs = "HTML" ; document.getElementByldC'buttonWrapper").className = ""; </script> </head> <body> <hl>U.S. Bill of Rights</hl> <form> <input type="button" value="Toggle Complete/Individual" onclick="toggleComplete()" /> <span id="buttonWrapper" class=""> <input type="button" value="Prev" onclick="prevField()" /> <input type="button" value="Next" onclick="nextField()" /> </span> </form> 256 Часть III. Объекты доммета
L, <div id="display" datasrc="#rightsjitml" datafld="Articlel" £' dataformatas="HTML"> :; </div> <object id="rights_html" classid="clsid:333C7BC4-460F-HD0-BC04-0080C7055A83"> <param name="DataURL" value="Bill of Rights.txt" /> <param name="UseHeader" value="True" /> <param name="FieldDelim" value="&#09;" /> </object> <object id="rights_raw" classid="clsid:333C7BC4-460F-HD0-BC04-0080C7055A83"> <param name="DataURL" value="Bill of Rights (no format).txt" /> <param name="FieldDelim" value="\" /> <param name="RowDelim" value="\" /> </object> </body> </html> Еще одна кнопке на странице позволяет переключаться между исходной урезанной версией документа и его полным вариантом. Для загрузки всего документа в виде единой записи параметрам FieldDelim и RowDelim второго элемента object вместо значений по умолчанию назначаются символы, которые никогда не встречаются в документе. Поскольку внешний файл в тексте не содержит имени поля, то в качестве значения по умолчанию принимается единственное поле с данными (columnl для единственного столбца в документе). В функции toggleComplete свойство dataSrc изменяет свое значение на идентификатор требуемого элемента object. Свойство dataField принимает значение используемого источника данных, а свойство dataFormatAs определяет тип исходных данных в выбранном источнике данных. При отображении на странице всего исходного документа можно скрыть два переключателя, назначив элементу span, содержащему эти переключатели, значение className. Как несложно догадаться, значение SpanName является идентификатором класса для таблицы стилей документа. Как только функция toggleComplete () приравняет свойство className к пустой строке, в силу вступают стандартные правила стилей. Следующий пример демонстрирует эффективность применения в сценариях объектов TDC. Листинг 15.9 позволяет отобразить на странице таблицу данных, созданную на основе текстового файла, в котором значения разделены символами табуляции. Файл данных состоит из восьми столбцов, заголовок каждого столбца рассматривается как имя поля: Year, Best Picture, Best Director, Best Director Film, Best Actress, Best Actress Film, Best Actor и Best Actor Film. На конечной странице отображаются данные только для пяти полей: Year, Film, Director, Actress и Actor. Обратите внимание, как в представленном листинге в таблицу вставляются данные из исходной таблицы источника. "Динамическая" часть кода этого примера определяет способы сортировки и фильтрации данных, загруженных в браузер, не требуя при этом повторного обращения к исходному файлу данных. Свойства Sort и Filter объекта TDC позволяют оперировать данными, уже загруженными в браузер. В самом простом случае сортировка выполняется по отдельному полю (или полям, согласно списку, в котором имена полей разделены точками с запятыми). Поставив перед именем поля знак "плюс" или "минус", вы сможете соответственно задать сортировку в возрастающем или ниспадающем порядке. После установки свойства Sort объекта data вызывается метод Reset (), который потребует применить новое свойство. Данные в таблице сразу будут обновлены в соответствии с проведенными изменениями. Подобным образом вы можете отображать в таблице только те данные, которые удовлетворяют определенным условиям. В листинге 15.9 интерфейсом для задания свойства Filter служит два раскрывающихся списка и два переключателя. Например, вы можете указать Глава 15. Основные объекты HTML-элементов 257
отобразить на странице записи только для премии Best Picture, завоеванной тем же фильмом, за игру в котором была получена премия Best Actress. Выражения фильтрации данных с использованием полей выглядит намного проще, чем словесная формулировка задачи. dataObj.Filter = "Best Picture" = "Best Actress Film"; <html> • <head> <title>Data Binding - Sorting</title> <script type="text/javascript"> function sortByYear(type) { oscars.Sort = (type == "normal") ? "-Year" : "+Year"; oscars.Reset(); } function filterlnCommon(form) { var filterExprl = form.filterl.options[form.filterl.selectedlndex].value; var filterExpr2 = form.filter2.options[form.filter2.selectedlndex].value; var operator = (form.operator[0].checked) ? " = " : "<>"; var filterExpr = filterExprl + operator + filterExpr2; oscars.Filter = filterExpr; oscars.Reset(); } </script> </head> <body> <hl>Academy Awards 1978-1997</hl> <form> <p>Sort list by year <a href="javascript: sortByYear('normal')">from newest to oldest</a> or <a href="javascript:sortByYear('reverse')">from oldest to newest</a>.</p> <p>Filter listings for records whose <select name="filterl" onchange="filterInCommon(this.form)"> <option value="Best Picture">Best Picture</option> <option value="Best Director Film">Best Director's Film</option> <option value="Best Actress Film">Best Actress' Film</option> <option value="Best Actor Film">Best Actor's Film</option> </select> <input type="radio" name="operator" checked="checked" onclick="filterInCommon(this.form)" /> is <input type="radio" name="operator" onclick= "filterInCommon(this.form)" />is not <select name="filter2" onchange="filterInCommon(this.form)"> <option value="Best Picture">Best Picture</option> <option value="Best Director Film">Best Director's Film</option> <option value="Best Actress Film">Best Actress' Film</option> <option value="Best Actor Film">Best Actor's Film</option> </selectx/p> 258 Часть III. Объекты документ
!\; ; </form> ',... <table datasrc="#oscars" border="l" align="center"> f, <thead style= "background- color .-yellow; text-align: center" > I <tr> "f' <td>Year</td> % <td>Film</td> r <td>Director</td> Yv <td>Actress</td> <td>Actor</td> </tr> </thead> <tr> <tdxdiv id="coll" datafld="Year"x/divx/td> <tdxdiv id="col2" datafld="Best Picture"></divx/td> <tdxdiv id="col3" datafld="Best Director"></divx/td> <tdxdiv id="col4" datafld="Best Actress"></divx/td> <tdxdiv id="col5" datafld="Best Actor"></divx/td> </tr> i, ' </table> <object id="oscars" cla8Sid="clsid:333C7BC4-460F-HD0-BC04- 0080C7055A83"> <param name="DataURL" value="Academy Awards.txt" /> <param name="UseHeader" value="True" /> <param name="FieldDelim" value="&#09;" /> </object> </body> </html > См. также свойства recordNumber, table.dataPageSize. dir S Значение: "ltr" | "rtl" Чтение/Запись Совместимость: WinIE5+, МасШ5+, NN6+, Mozl+, Safaril+ *■;.. Свойство dir (основанное на атрибуте DIR практически всех текстовых элементов HTML) управляет тем, как отображается текст элемента: слева направо (по умолчанию) или справа налево. Как правило, это свойство (и атрибут HTML) используется для переопределения направления вывода текста в кодировке, определенной стандартом Unicode. Пример Изменение этого свойства в стандартной американской версии браузера приводит к изменению начальной точки каждой строки с левого края страницы на ее правый край (при этом порядок письма слева направо соблюдается). Вы можете смело экспериментировать в приложении The Evaluator с этим свойством, введя в нижнем поле следующее выражение. document.getElementById("myP").dir = "rtl" См. также свойство lang. disabled Значение: булевого типа Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Напомним, что лишь некоторые элементы в IE4 и Ш5 имеют свойство disabled, однако в Ш5.5+ это свойство присуще всем элементам HTML. Отключение элемента HTML (например Глава 15. Основные объекты HTML-элементов 259
элемента формы) обычно делает его "недоступным", указывая на то, что данный элемент не является активным. Отключенный элемент не получает никаких событий. Кроме того, его нельзя использовать ни вручную, ни средствами сценария (хотя отключенные текстовые поля в МасШ4 по ошибке иногда активизируются). Тем не менее, пользователь имеет возможность выделить и скопировать содержимое отключенного текстового элемента. /Если элемент формы отключен, то его данные не отправляются на сервер вме- ЬшмйНг сте с данными остальных элементов. Если необходимо, чтобы Элемент формы был ^** "блокирован", но при этом его данные отправлялись на сервер, следует воспользоваться обработчиком события onsubmit элемента form. В нем нужно "разблокировать" элемент управления формы непосредственно перед отправкой данных Пример Используйте приложение Тле Evaluator (глава 13) для изучения свойства disabled как у элементов W3C DOM (IE4+), так и обычных HTML-элементов (Ш5.5+). В первом случае поемов рите, что произойдет, если отключить текстовую область с помощью следующего выражения. document.forms[0].output.disabled = true Текстовая область недоступна только для ввода данных, но вы все еще можете в сценарии задать свойство value поля. В Ш5.5+ элемент туР отключается с помощью следующего выражения в верхнем поле, document.getElementById("myP").disabled = true Пример текста абзаца при этом окрашивается в серый цвет. См. также свойство isDisabled. document Значение: объект document Только для чтешВ Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- В контексте объектов элементов HTML в Ш4+ свойство document является ссылкой и документ, содержащий данный объект. Хотя вам вряд ли понадобится это свойство, оно мо- жет оказаться полезным в сложных сценариях или библиотеках, обрабатывающих объекте универсальным образом и поэтому не имеющих сведений об указывающем на документ зад менте, в котором содержится определенный объект. Кроме того, ссылка на документ можея понадобиться для поиска в нем родственных объектов. Версия этого свойства в варианп W3C (реализованная в МасГ£5, но не в Winffi5.5) имеет имя ownerDocument. Пример Следующая упрощенная функция принимает параметр, представляющий любой объят в иерархической структуре документа. Функция возвращает ссылку на документ, содержащЯГ объект, с помощью которой можно обратиться к другим объектам страницы. function getCompanionFormCount(obj) { var ownerDoc = obj.document; return ownerDoc.forms.length; } Поскольку переменная ownerDoc содержит корректную ссылку на объект document оператор return использует эту ссылку для возвращения одного их свойств объекта. См. также свойство ownerDocument. 260 Часть III. Объекты доктеША
filters!] <ф ... г Значение: массив Только для чтения Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Фильтры — это специфические для IE дополнения к таблицам стилей, отвечающие за эффектное представление текста (они, например, добавляют к символам тень) и анимационные эффекты перехода от скрытых к отображаемым элементам. Каждая спецификация фильтра являются объектом filter. Свойство filters содержит массив объектов filter, определенных для текущего элемента. Фильтры можно применять для следующих элементов: body, button, img, input, li, marquee, ol, table, td, text area, th, ul, а также позиционируемых элементов div и span. Подробно о фильтрах таблиц стилей речь пойдет в главе 26. См. также объект filter. firstChild lastChild Значение: ссылка на объект узла Только для чтения Совместимость: Winffi5+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Объектные модели документов, основанные на W3C DOM, построены в соответствии с иерархической структурой — схемой узлов. Каждый объект, определенный в HTML, является узлом на этой схеме. Каждый из них взаимосвязан с другими узлами. Взаимоотношения описываются такими терминами: родительские (parents), "братские" (siblings) и дочерние (children). Дочерний узел — это элемент, содержащийся в другом элементе. Контейнер является родительским по отношению к такому элементу. Так же, как элемент HTML может содержать любое количество дочерних элементов, родительский объект может содержать несколько или ни одного дочернего элемента. Список таких дочерних объектов (возвращаемый как массив) вы получите, если используете свойство childNodes. var nodeArray = document.getElementByldCelementID").childNodes Как отмечалось, данный массив (и его свойство length) применяется для получения ука- " мтелей на первый и последний дочерние узлы, свойства firstChild и lastChild являются альтернативными способами представления подобных объектов. Они особенно полезны в случае, когда необходимо вставить новый дочерний элемент впереди или за уже существующими дочерними элементами. Для добавления элементов к списку узлов документа применяется (в ГЕ) метод insert Adjacent Element () или любой другой метод, указывающий на конкретный объект. Обратитесь к описанию свойства childNodes ранее в этой главе, где рассказано о "скрытых" узлах, присутствующих в некоторых версиях браузеров. Они могут влиять на использование свойств firstChild и lastChild. Пример В листинге 15.10 содержится пример использования свойств firstChild и lastChild для получения доступа к дочерним узлам. Это весьма поучительный пример, в котором в существующий элемент ol добавляются и удаляются элементы li. Таким образом, вы можете ввести любой текст в начало или в конец списка. Воспользовавшись свойствами f irstChildn lastChild, вы упростите себе задачу перемещения в конец списка. В качестве функции, заменяющей дочерний узел, в данном случае используется метод replaceChild (). Глаёа 15. Основные объекты HTML-элементов 261
Наряду с этим в Ш4+ вы можете изменить свойство innerText объектов, возвращаемых свойствами first Chi Id и last Chi Id. Этот пример весьма показательный при добавлении элементов в список — браузер автоматически перенумерует элементы, чтобы сохранить общий порядок следования элементов. <html> <head> <title>firstChild and lastChild Properties</title> <script type="text/javascript"> function makeNewLI(txt) { var newltem = document.createElement("LI"); newltem.innerHTML = txt; return newltem; } function prepend(form) { var newltem = makeNewLI(form.input.value); var firstLI = document.getElementByld("myList").firstChild; document.getElementByld("myList").insertBefore(newltem, firstLI); } function append(form) { var newltem = makeNewLI(form.input.value); var lastLI = document.getElementByld("myList").lastChild; document.getElementByldC'myList").appendChiId(newltem); } function replaceFirst(form) { var newltem = makeNewLI(form.input.value); var firstLI = document.getElementByldC'myList").firstChild; document.getElementByld("myList").replaceChild(newltem, firstLI); } function replaceLast(form) { var newltem = makeNewLI(form.input.value); var lastLI = document.getElementByld("myList").lastChild; document.getElementByld("myList").replaceChild(newltem, lastLI); } </script> </head> <body> <hl>firstChild and lastChild Property Lab</hl> <hr /> <form> <label>Enter some text to add to or replace in the OL element:</labelxbr /> <input type="text" name="input" size="50" /xbr /> <input type="button" value="Insert at Top" onclick="prepend(this.form)" /> <input type="button" value="Append to Bottom" onclick="append(this.form)" /><br /> <input type="button" value="Replace First Item" onclick="replaceFirst(this.form)" /> <input type="button" value="Replace Last Item" onclick="replaceLast(this.form)" /> </form> 262 Часть III. Объекты локшеиж
I y> <ol id="myList"> 'i <li>Initial Item l</li> i ' <li>Initial Item 2</li> ;=; <li>Initial Item 3</li> \- <li>Initial Item 4</li> \: </ol> г </body> ; </html> См. также: свойства nextSibling, parent Element, parentNode, previousSibling; ■ методы appendChild (), hasChildNodes (), removeChild (), removeNode (), replace- ' ChildO, replaceNode (). height width Значение: целочисленное или строковое (процентное) Чтение/Запись и Только для чтения Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Свойства height и width, описываемые в данном случае, не следует пугать со свойствами, описываемыми в стиле элемента (они имеют идентичные имена). Данные свойства, скорее, от- ' ражают значения, обычно присвоенные атрибутам height и width таких элементов, как img, , applet, table и т.д. Поэтому доступ к ним осуществляется непосредственно из объекта (например document. getElementByld ("myTable") . width в Ш4+), а не с помощью объ- . em style (например document. getElementByld ("myDIV") . style. width). Только те элементы, для которых стандарт HTML 4.x предусматривает наличие атрибутов height (и width, имеют соответствующие свойства. Эти свойства могут принимать целочисленные значения в пикселях (числа или строки) шш процентах (только строки). Прежде чем задать процентное значение, его необходимо преобразовать в числовое с помощью функции parselntO. Если атрибуты элемента height и width установлены в процентах, в ГЕ4+ с помощью свойств clientHeight „fclientwidth можно получить примерные размеры в пикселях. В большинстве современных браузеров свойства объекта image предназначены и для чтения, и для записи, так как размер объекта image в Ш4+ и Mozl+ можно изменить после загрузки страницы. То же самое справедливо и для некоторых других объектов (например table), но не обязательно для всех тех, которые поддерживают эти свойства. В большинстве случаев невозможно установить значения этих свойств меньшими, чем это требуется для представления элемента. Особенно это справедливо для таблиц. Если попытаться установить свойство height в значение, меньшее количества пикселей, требуемого для отображения таблицы (именно так это определено в ее настройках стилей), изменения не будут проведены (хотя свойство и будет содержать искусственно меньшее значение). Однако для других объектов (например изображений) их размер можно установить любым, и браузер проведет необходимое масштабирование. Если же требуется отобразить только часть элемента (другими словами, обрезать), для указания отображаемой области следует воспользоваться таблицами стилей. Пример Следующий пример демонстрирует возможности свойства width по увеличению ширины таблицы на 10%. var tableW = parselnt(document.getElementByld("myTable").width); document.getElementByld("myTable").width = (tableW * 1.1) + "%"; Глава f5. Основные объекты HTML-элементов 263
Поскольку исходно атрибут width для элемента table задан в виде процентного значения, то в сценарии изменение данного свойства также определяется в процентах. См. также свойства clientHeight, clientwidth или style. height, style. width. hideFocus Значение: булевого типа Чтение/Запись Совместимость: Winffi5.5+, MacIE-, NN-, Moz-, Safari- B браузере IE для Windows кнопки и другие элементы формы при активизации обозначаются пунктирным прямоугольником. Если в Ш5+ установить атрибут tabindex или свойство tab Index любого элемента, он также будет выделен пунктирной линией при активизации. Существует возможность активизировать элемент, но не отображать для него пунктирную границу. Для этого необходимо определить свойство hideFocus объекта элемента со значением true (по умолчанию оно имеет значение false). Отключение пунктирной линии не отменяет активизацию самого элемента. Если активный элемент находится за пределами видимой области, страница прокручивается до этого элемента. Элементы управления форм, воспринимающие введение данных с клавиатуры (например нажатие клавиши символа пробела для выставления или снятия флажка), продолжают выполняться так же, как обычно. В некоторых случаях пунктирный прямоугольник, указывающий на активизацию элемента, нарушает дизайн страницы. Свойство hideFocue позволяет управлять отображением элементов и поддерживать их совместимость с другим» страницами. В дескрипторе HTML нет соответствующего атрибута, поэтому для установит свойства hideFocus необходимых элементов после загрузки страницы следует воспользоваться обработчиком события onload. Пример Используйте приложение The Evaluator (глава 13) для изучения свойства hideFocus в IE5i. Введите следующее выражение в верхнее текстовое поле для задания свойству tabindex эдеме* та myP значения, при котором последний активизируется и обрамляется пунктирной линией. document.getElementByld("myP").tabindex = 1 Нажмите несколько раз клавишу <ТаЬ> — абзац должен быть выделен пунктирной рамкой. Далее отключите пунктирную рамку для выделенного абзаца. document.getElementByld("myP").hideFocus - true В дальнейшем, сколько бы раз вы ни нажимали <ТаЬ>, пунктирная линия вокруг абзац так и не появится, хотя сам элемент абзаца активизируется. Чтобы убедиться в том, что объев все-таки активизируется, прокрутите страницу вниз и так, чтобы абзац скрылся из виду (можете просто изменить размер окна). Щелкните на одном из визуально активизируемых элемешш страницы и медленно несколько раз нажмите клавишу <ТаЬ> — в строке адреса должен п<ь виться курсор. Нажмите <ТаЬ> еще раз. Страница автоматически будет прокручена к тексту абзаца, хотя пунктирная рамка вокруг него отображаться не будет. См. также: свойство tabindex; метод srcollIntoView (). id Значение: строка (См. в текста Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство id возвращает идентификатор, присвоенный атрибуту ID элемента в код HTML. Сценарий не может ни изменить идентификатор существующего элемента, ни присвоить его элементу без идентификатора. Но если в сценарии создается новый элемент, свей ство id позволяет присвоить ему идентификатор. 264 Часть III. Объекты документ
Пример При написании сценариев вам редко придется прибегать к услугам этого свойства. Исключением являются Web-страницы, в которых необходимо просмотреть все имена элементов, заданные разработчиком. После этого можно смело ссылаться на объекты документа по их идентификаторам (с помощью метода document .get Element By Id (идентификаторЭлемента)). Если по определенным причинам в сценарии не известен идентификатор элемента, например, второго абзаца документа, то его можно получить с помощью следующего выражения. ' var elemID = document .getElementsByTagName ("p") [1] .id; См. также свойство className. innerHTML innerText Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Один из способов доступа к содержимому элемента в браузере Internet Explorer заключается в использовании свойств innerHTML и innerText. (Браузеры Mozl+/NN6+ позволяют применять только свойство innerHTML.) Все содержимое, определенное этими "мугренними" свойствами, состоит из данных, заключенных между открывающими и закрывающими дескрипторами элемента, исключая последние (см. также свойства outerText HOuterHTML). Задав эти внутренние свойства, вы всегда сможете изменить определенную часть страницы после ее загрузки. Свойство innerHTML задает не только текстовое содержимое элемента, отображаемое на странице, но также все дескрипторы HTML в нем. (Если в содержимом нет дескрипторов, то текст будет представлен в таком виде, в каком есть.) Например, рассмотрим следующий исходный HTML-код. <р id="paragraphl">"How <em>are</em> you?" he asked.</p> В этом случае значение свойства innerHTML объекта абзаца (document .get Element- •3yld ("paragraphl") . innerHTML) будет таким. "How <em>are</em> you?" he asked. Браузер интерпретирует все дескрипторы HTML, включенные в строку innerHTML, как элементы HTML. Это значит, что в результате присвоения свойству innerHTML строки с HTML-содержимым на страницу можно будет добавить новые вложенные элементы (или, в современной терминологии, дочерние узлы). При вставке нового содержимого объектная модель документа корректируется автоматически. В отличие от описанного вами, свойство innerText включает только текстовое содер- ,жимое. В примере, приведенном ранее, значение свойства innerText (document .get- ElementByld ("paragraphl") . innerText) будет таким. "How are you?" he asked. Важно учесть следующее: когда свойству innerText присваивается строка, содержащая дескрипторы HTML, последние вместе с угловыми скобками выводятся на страницу и не интерпретируются как элементы HTML. Для корректировки HTML-кода таких элементов, как FRAMESET, HTML, HEAD, TITLE и связанных с таблицей объектов, не следует пользоваться свойством innerHTML. Структура таблицы будет изменена специальными методами, которые создают или форматируют строки, столбцы и ячейки (глава 37). Однако ничто не мешает изменить содержимое ячейки с помощью свойства innerHTML или innerText. Глава 15. Основные объекты HTML-элементов 265
Если вставляемый код HTML содержит элемент <script >, то в открывающем дескрипторе необходимо задать атрибут defer. Это справедливо и для сценариев, содержащих определения функций. Пример Листинг 15.11 содержит пример использования свойств innerHTML и innerText для динамического изменения содержимого страницы. Данная страница содержит элемент hi и элемент абзаца. Суть примера заключается в демонстрации разницы в обоих свойствах. Два текстовых поля содержат одинаковые комбинации текста и HTML-дескрипторов, с помощью которых изменится содержимое элементов. Если вы примените значение в первом текстовом поле к свойству innerHTML объекта label 1, то первое слово надписи будет отображена курсивом. Кроме того, текст в скобках отображается меньшим шрифтом (благодаря его включению в элемент span и применению специальной таблицы стилей). Если вы назначите содержимое поля свойству innerText объекта label 1, то он весь будет отображен в тексте абзаца. Вы можете ввести в текстовые поля этого документа другие выражения. Узнайте, что произойдет, если в тексте обоих полей используется дескриптор <br>. <html> <head> <title>innerHTML and innerText Properties</title> <style type="text/ess"> hi {font-size:18pt; font-weight:bold; font-family:"Comic Sans MS", Arial, sans-serif} .small {font-size:12pt; font-weight:400; color:gray} </style> <script type="text/javascript"> function setGroupLabelAsText(form) { var content = form.textInput.value; if (content) { document.getElementByld("label1").innerText = content; function setGroupLabelAsHTML(form) { var content = form.HTMLInput.value; if (content) { document.getElementByld("labell").innerHTML = content; </script> </head> <body> <form> <p><input type="text" name="HTMLInput" value="&lt;I&gt;First&lt;/I&gt; Article &lt;span class='small'&gt;(of ten)&lt;/span&gt;"size="50" /> <input type="button" value="Change Heading HTML" onclick="setGroupLabelAsHTML(this.form)" /></p> <p><input type="text" name="textInput" value="&lt;I&gt;First&lt;/I&gt; Article &lt;span class*'small'&gt;(of ten)&lt;/span&gt;" size="50" /> <input type="button" value="Change Heading Text" 266 Часть III. Объекты документ
onclick="setGroupLabelAsText(this.form)" /></p> </form> <hl id="labell"> ARTICLE I </hl> <p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.</p> </body> </html> См. также: свойства outerHTML, outerText; метод replaceNode (). isContentEdi table Значение: булевого типа Только для чтения Совместимость: Winffi5.5+, MacIE-, NN-, Moz-, Safari- Свойство isContentEditable возвращает значение булевого типа, указывающее, является ли объект элемента редактируемым (см. выше описание свойства contentEditable). Если свойство contentEditable родительского элемента имеет значение true, то свойство contentEditable вложенного элемента, скорее всего, имеет значение по умолчанию inherit. Но так как родительский элемент является редактируемым, то свойство isContentEditable дочернего элемента возвращает значение true. Пример Используйте приложение The Evaluator (глава 13) для экспериментов с обоими свойствами isContentEditable и contentEditable элемента туР и вложенных элементов туЕМ. Проверьте текущее значение свойств для элемента туЕМ, введя в верхнее поле следующее выражение. туЕМ.isContentEditable Исходное значение свойства равно false, поскольку ни один из элементов высшего уровня в иерархической структуре не разрешено редактировать. Далее мы сделаем редактируемым родительский элемент туР. туР.contentEditable = true Теперь редактированию подлежит весь элемент туР, поскольку дочерний объект по умолчанию наследует свойства родительского. Для проверки этого утверждения введите в верхнем поле следующее выражение. myEM.isContentEditable Несмотря на то, что элемент туЕМ подлежит редактированию, свойство contentEditable при этом не изменяется. myEM.contentEditable Это свойство по-прежнему содержит значение по умолчанию inherit. Дополнительные примеры использования этих свойств приведены в листинге 15.7. См. также свойство contentEditable. isDisabled Значение: булевого типа Только для чтения Совместимость: Winffi5.5+, MacIE-, NN-, Moz-, Safari- Глава 15. Основные объекты HTML-элементов 267
Свойство isDisabled возвращает значение булевого типа, указывающее, является ли определенный объект элемента отключенным (см. предыдущее обсуждение свойства disabled). Это свойство является чрезвычайно полезным по следующей причине: если свойство disabled родительского элемента имеет значение true, то свойство disabled вложенного элемента, скорее всего, будет иметь значение по умолчанию false. Но поскольку родительский элемент является отключенным, то свойство isDisabled дочернего элемента возвращает значение true. Другими словами, свойство isDisabled возвращает реальный статус элемента, независимо от установок его свойства disabled. Пример Используйте приложение The Evaluator (глава 13) для экспериментов с обоими свойствами disable и isDisabled элемента туР и вложенных элементов ту ЕМ. Проверьте текущее значение свойств для элемента туЕМ, введя в верхнее поле следующее выражение. туЕМ.isDisabled Исходное значение свойства равно false, поскольку ни один из элементов высшего уровня в иерархической структуре не отключен. Далее мы отключим родительский элемент туР. туР.disabled = true Теперь элемент туР (включая все его дочерние объекты) отключен. Для проверки этого утверждения введите в верхнем поле следующее выражение. myEM.isDisabled Несмотря на то, что элемент туЕМ отключен, его свойство disabled при этом не изменяется. myEM.disabled Это свойство по-прежнему содержит значение по умолчанию false. См. также свойство disabled. isMultiLine Значение: булевого типа Только для чтения Совместимость: Winffi5.5+, МасШ-, NN-, Moz-, Safari- Свойство isMultiLine возвращает значение булевого типа, указывающее на то, может ли элемент занимать или содержать более одной текстовой строки. Важно следующее: это значение не указывает, занимает ли элемент несколько строк; скорее, данное свойство демонстрирует возможность или невозможность этого. Например, текстовый элемент input не может занимать несколько строк, поэтому свойство isMultiLine для него содержит значение false. Элемент BUTTON может в нескольких строках содержать свою текстовую подпись, поэтому это его свойство имеет значение true. Пример Приложение The Evaluator (глава 13) позволяет считывать значение свойства isMultiline элементов страницы. Введите в верхнее поле следующие выражения. document.body.isMultiLine document.forms[0].input.isMultiLine myp.isMultiLine myEM.isMultiLine Все элементы, за исключением текстовых полей, поддерживают ввод данных в несколько строк. 268 Часть ///. Объекты документа
isTextEdit ■ ■ ■, Значение: булевого типа Только для чтения Совместимость: WinBE4+, MacIE4+, NN-, Moz-, Safari- Свойство isTextEdit указывает, можно ли на основе его содержимого создать объект Winffi TextRange. (См. объект TextRange в главе 35.) Объекты TextRange в Ш4+ для Windows можно создать на основе ограниченного набора объектов: body, button, некоторых элементов форм (text/ password, hidden, button, reset и submit) и объекта text area. В МасШ5 это свойство всегда возвращает значение false. Пример Рекомендуется всегда проверять это свойство перед выполнением метода createText- Range () текущего объекта. Ниже приведет стандартный код этой операции. if (document.getElementByld ("myObject").isTextEdit) { var myRange = document.getElementByld("myObj ect").createTextRange(); [дополнительные операторы управления диапазоном myRange] } См. также: метод createRange (); объект TextRange (глава 35). lang Значение: кодовая страница языка ISO Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство lang управляет набором символов, используемым для отображения текстового содержимого элемента, когда настройки браузера по умолчанию не применяются. По умолчанию это свойство содержит пустую строку, если только атрибуту lang в дескрипторе элемента не присвоено значение. Изменение этого свойства средствами сценария пока никак не проявляется в современных версиях браузеров. Пример В качестве значений свойства lang указывают текстовые строки, содержащие корректные коды ISO языков. В данном коде обязательно указывается идентификатор языка ("f r" для французского языка), а также необязательный суффикс региона, в котором используется данных язык (например, "fr-ch" для швейцарского французского). Код задания швейцарского немецкого языка ввода выглядит следующим образом. document.getElementByld("specialSpan").lang = "de-ch"; language Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Архитектура браузеров Ш4+ позволяет использовать несколько механизмов добавления сценариев. В базовой версии браузера для Windows содержится два варианта сценариев: JScript (совместимый с JavaScript) и Visual Basic Scripting Edition (VBScript). По умолчанию задается значение JScript. Если же в операторах, включенных в обработчики событий атрибутов дескриптора, требуется использовать VBScript или какой-либо другой язык сценариев, браузеру можно указать, какой именно язык сценариев следует применять для обработки операторов, установив атрибут LANGUAGE дескриптора. Свойство language обеспечивает сценарию доступ к этому атрибуту. Если только вы не собираетесь изменять обработчик событий HTML-кода Глава 15. Основные объекты HTML-элементов 269
и заменять его оператором VBScript (или любого другого языка, несовместимого с JScript и установленного в браузере), вам не потребуется изменять (или читать) это свойство. К допустимым значениям относят JScript, javascript, vbscript и vb's. Браузеры других производителей имеют собственные идентификаторы для использования в этом свойстве. Так как атрибут language задается также в дескрипторе <script >, Internet Explorer 5 воспринимает и оператор languages "xml ■■. См. также объект элемента script. lastChild (см. f irstchild) length Значение: целочисленное Только для чтения и Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Свойство length возвращает количество элементов в массиве или наборе объектов. Чаще всего это свойство используют в условии цикла for. Если в массивах и наборах индексация производится с нуля, значение length представляет собой реальное количество элементов в группе. Поэтому для просмотра всех элементов условное выражение должно включать знак "меньше" (<), а не "меньше или равно" (<=), как показано в следующем примере. for (var i = 0; i < someArray.length; i++) {...} Для просмотра массива в обратном порядке (т.е. начиная с последнего элемента и заканчивая первым) исходное выражение должно инициализировать счетчик цикла следующим образом. for (var i = someArray.length — 1; i >= 0; i--) {...} В большинстве массивов и наборов свойство length предназначено только для чтения и зависит только от количества элементов в группе. Однако в современных версиях браузеров в массивах элементов (areas, options и объекту select) можно создать заполнители для последующего размещения в них данных. Подробно эта возможность описана в разделах, посвященных объектам элементов area, select и option. В обычном массиве JavaScript значение length можно изменять, либо удаляя элементы в конце, либо резервируя место для дополнительных элементов. Подробнее об объекте Array речь пойдет в главе 30. Пример Введите в верхнем поле приложения the Evaluator следующие выражения, чтобы ознакомиться со значениями свойства length для различных объектов. Обратите внимание на то, что отдельные выражения поддерживаются далеко не всеми браузерами. (А11 browsers) document.forms.length (All browsers) document.forms[0].elements.length (NN3+, IE4+) document.images.length (NN4+) document.layers.length (IE4+) document.all.length (IE5+, W3C) document.getElementById("myTable").childNodes.length См. также объекты area, select, option и array. localName namespaceURI prefix Значение: строка Только для чтения Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safari 1+ 270 Часть III. Объекты документ*
Три свойства localName, namespaceURI и prefix применимы к любому узлу в XML- документе, в котором в дескрипторе XML задается пространство имен URI. Несмотря на то, что в NN6 все три свойства имеют все объекты элементов (и узлов), они не возвращают требуемых значений. Ситуация исправлена в Mozilla-совместимых браузерах. Именно в этом описании рассказано, какие значения будут содержать данные свойства. Рассмотрим следующий XML-код. <х xmlns:bk='http://bigbooks.org/schema'> <bk:title>To Kill a Mockingbird</bk:title> </x> Элементу дескриптора <bk: title > задается пространство имен URI, определенное для блока кода, поэтому свойство namespaceURI элемента возвратит строку http: //bigbooks. org/ schema. Имя дескриптора состоит из префикса (до двоеточия) и локального имени (после двоеточия). В приведенном выше примере свойством prefix элемента, определенного дескриптором <bk:title>, является bk, а свойством localName— title. Свойство localName любого узла возвращает то же значение, что и свойство nodeName, например #text для текстового узла Более подробная информация о пространстве имен XML приведена по адресу http: //www.w3.org/TR/REC-xml-names. См. также свойства scopeName, tagUrn. nextSibling previousSibling Значение: ссылка на объект Только для чтения Совместимость: Winffi5+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Элементы-"братья" — это элементы, находящиеся на одном уровне вложенности. Например, элемент р имеет два дочерних узла (em и span). Два дочерних узла являются элемента- ми-"братьями" по отношению друг к другу. <p>MegaCorp is <em>the</em> source of the <span class="hot">hottest</span> gizmos.</p> Порядок следования элементов-"братьев" полностью определяется их порядком задания в исходном коде. Поэтому в предыдущем примере элемент em не имеет свойства previous- Sibling. Точно так же элемент span не имеет свойства nextSibling. Данные свойства обеспечивают еще один способ просмотра элементов, находящихся на одном уровне. Пример Следующая функция назначает одно и то же имя класса всем дочерним узлам элемента. function setAHChildClasses (parentElem, className) { var childElem = parentElem.firstChild; while (childElem.nextSibling) { childElem.className = className; childElem = childElem.nextSibling; Этот код представляет не единственный способ выполнения текущей задачи. С помощью цикла for вы также можете просмотреть коллекцию childNodes родительского элемента. См. также: свойства firstChild, lastChild, childNodes; методы |iasChildNodes (), insertAdjacentElement (). Глава 15. Основные объекты HTML-элементов 271
nodeName Значение: строка Только для чтения Совместимость: WinIE5+, MacIE5+, NN6+, Mozl+, Safari 1+ Для элементов HTML и XML имя узла совпадает с именем дескриптора. Свойство nodeName включено для совместимости с архитектурой узлов, формально описанной стандартом W3C DOM. Значением свойства, как и для tagName, является строка с именем дескриптора, где все символы принадлежат верхнему регистру (даже если в исходном HTML-коде дескрипторы введены символами нижнего регистра). Некоторые узлы (например, текстовое содержимое элемента) не имеют соответствующих дескрипторов. Свойство nodeName для таких узлов имеет специальное значение: #text. Другим типом узла является атрибут элемента. Для атрибута свойство nodeName возвращает имя атрибута. Более подробно свойства объекта Node описаны в главе 14. Пример Следующая функция демонстрирует один из способов (далеко не самый эффективный) назначения имени класса каждому элементу р в документе Ш5+. function setAUPClasses (className) { for (var i = 0; i < document.all.length; i++) { if (document.all[i].nodeName == "P") { document.all[i].className = className; } } } Более эффективный способ предполагает использование метода getElementByldf) для получения коллекции элементов р и последовательного их изменения. См. также свойство tagName. nodeType Значение: целочисленное Только для чтения Совместимость: Winffi5+, МасГ£5+, NN6+, Mozl+, Safaril+ Спецификация W3C DOM определяет набор констант, которые указывают тип узла. Не все эти значения реализованы в браузерах, совместимых с W3C DOM, хотя NN6 включает на две константы больше, чем Ш5. В табл. 15.4 перечислены значения nodeType, поддерживаемые текущими версиями браузеров. Значение Описание WlnlE' MaclE NN/Moz Safari i Узел элемента 5 5 NN6 1 2 Узел атрибута 6 5 NN6 1 3 Текстовый узел (#text) 5 5 NN6 1 4 Узел раздела CDATA - v - 5 Узел ссылки на сущность - 6 Узел сущности ... 7 Узел обработки инструкций - 272 Часть III. Объекты документа
Окончание табл. 15.4 Значение 8 9 10 11 12 Описание Узел комментария Узел документа Узел типа документа Узел фрагмента документа Узел примечания WinlE 6 5 - 6 - MaclE 5 5 - 5 - NN/Moz NN6 NN6 NN6 NN6 - Safari Значение nodeType автоматически присваивается элементу независимо от того, существует он в исходном HTML-коде документа или создается сценарием на лету. Например, если новый элемент создается одним из способов, задаваемых сценарием (например, присвоение строки с дескрипторами HTML-свойству innerHTML или явный вызов метода document. createElement ()), то его свойство nodeType содержит значение 1. Mozilla-совместимые браузеры превосходят остальные в том, что касается определения набора значений nodeType для констант свойства Node в спецификации W3C DOM. В табл. 15.5 приведен полный перечень значений, определяемый спецификацией DOM 2 (в NN6 поддерживаются не все свойства). Замена целочисленных значений этими константами улучшает читаемость сценария. Например, гораздо проще понять сценарий, если вместо if (myElem.nodeType ==1) {...} используется if (myElem.nodeType == Node.ELEMENT_NODE) {...} Константа Node. ELEMENT_NODE Node. ATTRIBUTE_NODE Node.TEXT_NODE Node. CDATA_SECTION_NODE Node. ENTITY_REFERENCE_NODE Node.ENTITYJTODE Node. PROCESSING_INSTRUCTION_NODE Node. COMMENT_NODE Node. DOCUMENT__NODE Node. DOCUMENTJTYPE_NODE Node. DOCUMENT_FRAGMENT_NODE Node.NOTATION NODE Значение no l 2 3 4 5 6 7 8 9 10 11 12 Пример Вы можете изучить свойство nodeType в приложении The Evaluator. Начните с анализа элемента р, имеющего идентификатор ту Р. Сам элемент р имеет свойство nodeType, равное 1. document .getElementByld ("myP") .nodeType Шва 15. Основные объекты HTML-элементов 273
Этот элемент включает три дочерних узла: текстовая строка (nodeName #text), элемент em (nodeName em) и остальной текст элемента (nodeName #text). Если запросить свойство nodeType для одной из текстовых составляющих, то будет возвращено значение 3. document.getElementById("myP").childNodes[0].nodeType См. также свойство nodeName. nodeValue Значение: число, строка или mil 1 Чтение/Запись Совместимость: WinIE5+, МасШ5+, NN6+, Mozl+, Safaril+ Для текстового узла свойство nodeValue сохраняет реальный текст, содержащийся в нем. Такой узел не может содержать вложенных элементов, поэтому свойство nodeValue представляет собой еще один способ чтения и изменения того, что реализовано в браузере Internet Explorer как свойство innerText. Из всех типов узлов, которые поддерживаются браузерами, совместимыми с W3C DOM, только текстовые узлы и узлы атрибутов имеют доступные для считывания значения. Значение, узла элемента всегда null. Для узла атрибута свойство nodeValue содержит значение, присвоенное атрибуту. Согласно стандарту W3C DOM, значения атрибутов должны быть строковыми. Однако браузер WinT£5 возвращает значение числового типа, если оно включает только символы цифр. Даже если свойству nodeValue присвоить строковое значение, оно будет преобразовано в тип Number. NN6 и МасШ5 во всех случаях возвращают значения nodeValue как строки (и преобразуют числовые значения в строковые при присвоении этому свойству). Пример С помощью свойства nodeValue выполняется целый ряд практических задач. Далее используем это свойство для увеличения ширины объекта textarea на 10%. Значение свойства nodeValue перед подстановкой в математические выражения необходимо преобразовать в целое число. function widenCols(textareaElem) { var colWidth = parselnt(textareaElem.attributes["cols"].nodeValue, 10); textareaElem.attributes["cols"].nodeValue = (colWidth * 1.1); } В еще одном примере мы заменим текст элемента, предположив, что последний не имеет вложенных элементов. function replaceText(elem, newText) { if (elem.childNodes.length == 1 && elem.firstChiId.nodeType == 3) { elem.firstChild.nodeValue = newText; Создавая функцию, мы предполагали, что элемент содержит всего один дочерний узел текстового типа. Во втором примере в качестве альтернативы также можно использовать следующее выражение, в котором используется свойство innerText. elem.innerText = newText; См. также свойства attributes, innerText, nodeType. offsetHeight offsetWidth Значение: целочисленное Только для чтенш Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ 274 Часть III. Объекты документ*
Эти свойства, которые обычно связываются с высотой и шириной элементов, настолько противоречивы, что часто вводят в заблуждение даже самых опытных разработчиков. Причина состоит в конфликте объекгных моделей Internet Explorer и W3C ЕЮМ. Оба свойства впервые появились в ЕЕ4. Хотя они и не включены в стандарт W3C, многие браузеры (в том числе Mozilla и Safari) поддерживают их, поскольку разработчикам сценариев весьма сложно от них отказаться. При переводе Ш6 в режим совместимости (см. главу 14) значения этих свойств определяют реальную высоту и ширину содержимого элемента, независимо от настроек полей, границ и выравнивания текста. Но свойство of f setWidth всегда содержит полную ширину (включает границы, поля и отступы) содержимого элемента. Это же поведение наблюдается в модели W3C, которое поддерживается всеми W3C ЕЮМ-совместимыми браузерами. Наряду с этим в IE6 и старых версиях WinlE при расчете указанных свойств учитываются ширина границ и отступы. Помните, что для обычного элемента, высота и ширина которого не указаны, свойство off set Height определяется реальной высотой содержимого элемента после обтекания и выравнивания текста. Но свойство of f setWidth всегда содержит полную ширину (включает границы, поля и отступы) содержимого элемента. Поэтому свойство of f setWidth не позволяет определить реальную ширину текстового содержимого, которая меньше, чем полная ширина родительского элемента. Чтобы найти реальную ширину текста внутри элемента, его необходимо заключить внутрь элемента (например span), после этого проверьте свойство of f setWidth последнего. Пример В WinIE4+ свойствами of f setHeight и of f setWidth иногда можно успешно заменить свойства clientHeight и clientWidth, как показано в листинге 15.6. Одно из достоинств свойств of f setHeight и of f setWidth (no сравнению с clientHeight и clientWidth) состоит в том, что первые имеют заданные значения даже в том случае, когда они не указаны явно в атрибутах дескриптора HTML. Так происходит по той причине, что эти значения устанавливаются автоматически при ссылке на родительский элемент — чаще всего body. В IE5+ и W3C DOM-совместимых браузерах вы можете использовать приложение The Evaluator для знакомства со свойствами of f setHeight и of f setWidth самых разных элементов страницы. Введите в верхнее поле следующие выражения. document.getElementByld("myP").offsetWidth document.getElementByld("myEM").offsetWidth document.getElementByld("myP").offsetHeight document.getElementByld("myTable").offsetWidth См. также свойства clientHeight, clientWidth. offsetLeft offsetTop Значение: целочисленное Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойства offsetLeft и offsetTop имеют те же недостатки, что и offsetHeight HoffsetWidth, когда к элементу добавляются границы, поля и отступы. Однако свойства offsetLeft и offsetTop являются полезными при получении координат элемента, позиционированного внутри родительского элемента (даже если элементы не позиционируются явно). £ ^ Свойства offsetLeft и offsetTop для позиционированных элементов в брау- ШтлЩ зере Mac IE возвращают значения, отличающиеся от style, left и style, top " >**** для одного и того же элемента. В качестве примера обратитесь к листингу 39.17, где показано, как устранить эти расхождения без введения точных корректирующих значений в исходный код. Глава 15. Основные объекты HTML-элементов 275
Элемент, используемый в качестве "точки отсчета" для этих свойств, — это узел, возвращаемый свойством of f setParent. Чтобы определить точную позицию конкретного элемента, необходимо добавить код, последовательно просматривающий структуру of f setParent до тех пор, пока свойство не возвратит значение null. Свойства of f setLef t и of f setTop не являются частью спецификаций W3C DOM, однако их реализовали во многих браузерах, поскольку они удобны для выполнения ряда задач, решаемых посредством сценариев динамического HTML. Используя эти два свойства в сценарии можно получить координаты в пикселях любого блокового или внутритекстового элемента. Измерения отсчитываются от элемента body, однако в будущем это, скорее всего, будет изменено (см. описание свойства of f setParent далее в этой главе). Пример Следующий сценарий для IE содержит выражения, в которых все четыре offset- свойства, задающие размеры, используются для позиционирования элемента div. Этот элемент должен полностью покрывать элемент span, расположенный в элементе р. Указанный прием часто используется при подготовке опросов, в которых от ответа респондента зависит расположение текстового кадра. При получении ответа, верхний элемент div скрывается, чтобы показать корректный результат. document.all.blocker.style.pixelLeft = document.all.span2.offsetLeft document.all.blocker.style.pixelTop = document.all.span2.offsetTop document.all.blocklmg.height = document.all.span2.offsetHeight document.all.blocklmg.width = document.all.span2.offsetWidth Поскольку свойство of f setParent для элемента span представляет элемент body, то располагаемый поверх элемент div должен позиционироваться в таком же контексте. Что и отражается в значениях свойств pixelLef t и pixelTop (обратите внимание, что указанные свойства задаются для объекта style элемента). С помощью свойств of fsetHeight и of fsetWidth определяется расположение в документе элемента span (в рассматриваемом примере не используются поля, границы и отступы). Полученные значения применяются при позиционировании на странице элемента div. В отдельных ситуациях приведенный выше код содержит потенциальные ошибки. Бели текст элемента span2 переносится на новую строку, то новое значение of fsetHeight вполне корректно определяет высоту элемента, необходимую для "закрытия" обоих строк. Тем не менее, элемент blocklmg отображается на странице в виде прямоугольника. Другими словами, этот элемент не преобразуется в две отдельные полосы, необходимые для скрытия двух текстовых строк. См. также свойства clientLef t, clientTop, of f setParent. offsetParent Значение: ссылка на объект Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство of fsetParent возвращает ссылку на объект, действующий как "точка отсчета" позиционирования текущего элемента. Значения свойств of f setLef t и of f setTop измеряются относительного левого верхнего угла объекта of fsetParent. Возвращаемый объект — это, как правило (но не всегда), расположенный на уровень выше блоковый контейнер. Для большинства элементов документа объектом of fsetParent является document. body (за исключением некоторых элементов в определенных браузерах). Ячейки таблицы, например, имеют различные элементы of fsetParent в различных браузерах. 276 Часть ///. Объекты документа
Браузер Свойство offsetParent элемента TD WnlE4 tr WmlE5+/NN7+/Moz1 + table MadE table NN6 body Это свойство для позиционируемых элементов также возвращает различные результаты в разных браузерах. В ГЕ значением свойства offsetParent позиционируемого элемента первого уровня является body; значением вложенного позиционируемого элемента (например, одного абсолютным образом позиционированного элемента div внутри другого) будет внешний контейнер (другими словами, узел позиционируемого внутреннего элемента). Пример Вы можете использовать свойство offsetParent для определения расположения на странице вложенного элемента. В листинге 15.12 показан сценарий, просматривающий иерархическую структуру объектов offsetParent в Winffi, с помощью которых определяется расположение на странице вложенных элементов. Цель кода, приведенного в этом листинге, — расположить изображение в левом верхнем углу второй ячейки таблицы. Сама таблица находится по центру страницы. Обработчик событий onload вызывает функцию setlmageposition (). Эта функция сначала назначает булев флаг, который определяет тип используемых свойств: client или offset. Браузеры WinIE4 и МасШ5 используют свойства client, a Winffi5+— свойства offset. В цикле while просматриваются свойства offsetParent для всех объектов, начиная с уровня ячейки. При этом из просмотра исключается объект document. body, в котором собственно и задается расположение изображения. В Ш5 цикл выполняется всего раз, поскольку элемент table располагается в иерархической структуре между элементами body и cell. В Г£4 цикл вьшолняется дважды: для элементов table и tг. Наконец, полученные суммарные значения применяются к свойствам позиционирования стиля объекта div, а само изображение отображается на экране. <html> <head> <title>offsetParent Property</title> <script type="text/javascript"> function setlmagePositionO { var x = 0; var у = 0; var offsetPointer = document.getElementByldp'myCell"); while (offsetPointer) { x += offsetPointer.offsetLeft; у += offsetPointer.offsetTpp; offsetPointer = offsetPointer.offsetParent; } if (navigator.userAgent.indexOf("Mac") != -1 && typeof document.body.leftMargin != "undefined") { x += document.body.leftMargin; у += document.body.topMargin; }. Глава 15. Основные объекты HTML-элементов 277
document.getElementByld("myDIV").style.left = x + "px"; document.getElementByld("myDIV").style.top = у + "px"; document.getElementByld("myDIV").style.visibility = "visible"; } </script> </head> <body onload="setImagePosition()"> <hl>The offsetParent Property</hl> <hr /> <p>After the document loads, the script positions a small image in the upper left corner of the second table cell.</p> <table border="l" align=" center'»> <tr> <td>This is the first cell</td> <td id="myCell">This is the second cell.</td> </tr> </table> <img id="myDIV" alt="image" src="end.gif' height="12" width="12" style="position:absolute; visibility:hidden; height:12px; width:12px" /> </body> </html> См. также свойства of f setLef t, of f setTop, offsetHeight, of f setWidth. outerHTML outerText Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Один из способов, которым Internet Explorer представляет элемент для использования в сценариях, является задание свойств outerHTML и outerText. Основное отличие между этими двумя свойствами состоит в том, что outerHTML включает открывающий и закрывающий дескрипторы, a outerText — только текст, включенный в элемент (в том числе и текст всех вложенных элементов). Свойство outerHTML содержит не только текст, отображаемый на странице, но и все дескрипторы HTML, находящиеся внутри элемента. В качестве примера рассмотрим следующий блок HTML-кода. <р id= "paragraphia "How <em>are</em> you?" he asked.</p> Значение свойства outerHTML объекта Р (document. all .paragraphl. outerHTML) в точности совпадает с исходным кодом. Браузер интерпретирует все дескрипторы HTML, содержащиеся в строке, как присвоенные свойству outerHTML. Таким образом, это свойство позволяет удалить (значение свойства— пустая строка) или заменить весь дескриптор. При внесении каких-либо изменений в HTML таким способом объектная модель документа корректируется автоматически. В отличие от описанного выше, свойство outerText содержит лишь информацию о тексте внутри элемента. Значение свойства outerText (document.a 11.paragraphl. innerText) из предыдущего примера выглядит как абзац текста. "How are you?" he asked. Ничего необычного, поскольку в большинстве случаев свойства innerText и outerText возвращают идентичные строки. 278 Часть ///. Объекты документ!
Пример В листинге 15.13 продемонстрирован пример использования в Ш свойств outerText и outerHTML для получения доступа к Web-странице и ее динамического изменения. Страница, сгенерированная с помощью кода в листинге 15.13 (только в Ш4+), содержит лишь заголовок hi и абзац с текстом. Цель данного примера — продемонстрировать разницу в этих двух свойствах. Два текстовых поля приложения содержат одинаковый текст и HTML- дескрипторы, с помощью которых заменяется текст заголовка над абзацем. Если вы назначите свойству outerHTML содержимое первого текстового поля, то элемент hi будет заменен на элемент span, атрибуту class которого назначена другая таблица стилей, определенная ранее в документе. Обратите внимание, что идентификатор этого элемента span подобен идентификатору исходного элемента hi. Это позволяет сценарию второй кнопки обращаться к объекту. Однако второй сценарий заменяет текст элемента hi исходным кодом в текстовом поле. Используйте представленную на экране страницу для ввода других значений в текстовые поля. <html> <head> <title>outerHTML and outerText Properties</title> <style type="text/ess"> hi {font-size:18pt; font-weight:bold; font-family:"Comic Sans MS", Arial, sans-serif} .heading {font-size:2Opt; font-weight:bold; font- family:"Arial Black", Arial, sans-serif} </style> <script type="text/javascript"> function setGroupLabelAsText(form) { var content = form.textInput.value; if (content) { document.getElementById("labell").outerText = content; function setGroupLabelAsHTML(form) { var content = form.HTMLInput.value; if (content) { document.getElementByldC'labell").outerHTML = content; </script> t </head> <body> <form> <p><input type="text" name="HTMLInput" value="&lt;SPAN ID='labell' CLASS='heading'&gt;Article the First&lt;/SPAN&gt;"size="55" /> <input type="button" value="Change Heading HTML" onclick="setGroupLabelAsHTML(this.form)" /></p> <p><input type="text" name="textInput" value="&lt;SPAN ID='labell' CLASS='heading'&gt;Article the First&lt;/SPAN&gt;" size="55" /> <input type="button" value="Change Heading Text" onclick="setGroupLabelAsText (this. form),f /></p> </form> Глава 15. Основные объекты HTML-элементов 279
<hl id="label1">ARTICLE I</hl> <p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press,- or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.</p> </body> </html> См, также: свойства innerHTML, innerText; метод replaceNode (). ownerDocument Значение: ссылка на объект document Только для чтения Совместимость: Winffi6+, МасШ5+, NN6+, Mozl+, Safari 1+ Свойство ownerDocument имеют все элементы в объектных моделях документа W3C DOM. Значением свойства является узел документа, содержащего данный элемент или узел. Если в сценарии используется ссылка на элемент или узел (например» если он передан функции как параметр), свойство ownerDocument объекта обеспечивает возможность создания ссылок на другие объекты в этом же документе или получения доступа к свойствам и методам объектов документа. Версия Ш этого свойства называется просто document. Пример Используйте приложение The Evaluator (глава 13) для изучения свойства ownerDocument. Введите в верхнее текстовое поле следующее выражение, document.body.childNodes[5].ownerDocument Возвращаемый результат представляет ссылку на объект document. Вы можете использовать его для изучения свойств документа, как показано в следующем выражении, которое также следует ввести в верхнее поле. document.body.childNodes[5].ownerDocument.URL Этот оператор возвращает свойство document. URL для документа, содержащего дочерний узел. См, также объект document. parentElement Значение: ссылка на объект элемента или nul 1 Только для чтения Совместимость: WinIE4+, Macffi4+, NN-, Moz-, Safari- Свойство parentElement возвращает ссылку на элемент, внешний по отношению к данному. Такое взаимоотношение родительских и дочерних узлов между элементами часто (но не всегда) совпадает со взаимоотношением между узлами (см. описание свойства parentNode далее в этой главе). Различие состоит в том, что свойство parentElement возвращает элементы HTML, в тр время как узел не обязательно является таковым (например, узлом может быть атрибут дескриптора или заключенный в него блок текста). Кроме того, между свойствами parentElement и of f set Parent существует различие. Последнее возвращает элемент, который находится на определенном расстоянии от данного элемента в иерархии, но является родителем относительно "точки отсчета" при позиционировании. Например, свойство parentElement элемента td в большинстве случаев содержит ссылку на внешний элемент TR, однако свойство of f set Parent для этого же элемента равно элементу table. 280 Часть III. Объекты документа
С помощью свойства parentElement сценарий может "пройти" по иерархии элементов. Вершиной цепочки родительских элементов является элемент HTML. Его свойство parentElement возвращает значение null. Пример Вы можете экспериментировать со свойством parentElement в приложении The Evaluator. Его документ содержит элементы р и туР. Введите следующие выражения из левого столбца в верхнее текстовое поле приложения и нажмите <Enter>. Выражение Результат document .getElementByldC'myP") .tagName p document.getElementById("myP") .parentElement [object] document .getElementByldC'myP").parentElement.tagName body document.getElementByld("myP").parentElement.parentElement [object] document.getElementByld("myP").parentElement.parentElement. html tagName document.getElementByldC'myP") .parentElement. null parentElement .parentElement См. также свойства of f setParent, parentNode. parentNode Значение: ссылка на объект элемента или nul 1 Только для чтения Совместимость: WinIE5+, МасШ5+, NN6+, Mozl+, Safaril+ Свойство parentNode возвращает ссылку на узел, внешний по отношению к данному и отображаемый как объект, принадлежащий документу. Для стандартного объекта элемента свойство parentNode совпадает со свойством parentElement в Ш, так как оба объекта имеют взаимоотношения родительских и дочерних узлов во всех элементах. Однако узлами могут быть представлены и другие типы данных. Последние включают фрагменты текста внутри элемента. Свойство parentNode фрагмента текста представляет собой внешний узел или элемент, включающий в себя этот фрагмент. Объект текстового узла в Ш не имеет свойства parentElement. Пример Используйте приложение The Evaluator для изучения свойства parentNode для узлов разных типов. Начните с ввода в верхнем поле следующих выражений. document.getElementByld("myP").parentNode.tagName document.getElementByldC'myP").parentElement.tagName (только в IE) Теперь изучите свойства с точки зрения узла первого текстового фрагмента элемента ту Р. document.getElementByldC'myP").childNodes[0].nodeValue document.getElementByld("myP").childNodes[0].parentNode.tagName document. getElementByld ( "myP") . childNodes [0] . parentElement (только в IE) Обратите внимание, что в Г£ текстовый узел не имеет свойства parentElement. См. также свойства childNodes, nodeName, nodeType, nodeValue, parentElement. Глава 15. Основные объекты HTML-элементов 281
parentTextEdit Значение: ссылка на объект элемента или mil 1 Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Только немногие объекты в модели Г£ могут создать блок текста (см. объект TextRange в главе 35). Для нахождения ближайшего к объекту внешнего контейнера, способного генерировать текстовый блок, используется свойство parentTextEdit. Если элемент содержится в иерархии, то возвращается ссылка на его объект. В ином случае (например document. body. parentTextEdit) свойство принимает значение null. Пример В листинге 15.14 приведен пример, в котором продемонстрировано использование свойства parentTextEdit для создания текстового диапазона. Страница, представляемая кодом из листинга 15.14, содержит абзац латинского текста, три переключателя, с помощью которых указывается размер выделяемого текстового фрагмента. При щелчке в тексте абзаца обработчик событий onclick вызывает функцию selectChunkO. Эта функция сначала проверяет, какой из переключателей выставлен, а затем определяет выделяемый текстовый фрагмент (относительно места щелчка пользователем). В данном сценарии свойство parentTextEdit используется для проверки того, можно ли использовать элемент, на котором щелкнул пользователь, для создания выделяемого текстового фрагмента. С помощью методов объекта TextRange текстовый фрагмент сначала сжимается в одну точку, далее он перемещается в точку щелчка и расширяется до указанного фрагмента. Обратите особое внимание на необычное поведение метода expand () объекта TextRange. При указании выделить все предложение Ш автоматически не рассматривает начало элемента р как начало предложения. Началом в данном случае является точка (которой заканчивается предыдущее предложение). Поэтому в конец предыдущего элемента добавляется еще одна «рытая (окрашенная в белый цвет) точка. Таким образом удается исключить из выделения "истинную" точку предыдущего элемента р. <html> <head> <title>parentTextEdit Property</title> <style type="text/css"> p {cursor:hand} </style> <script type="text/javascript"> function selectChunkO { var chunk, range; for (var i * 0; i < document.forms[0].chunk.length; i++) { if (document.forms[0].chunk[i].checked) { chunk = document.forms[0].chunk[i].value; break; var x = window.event.clientX; var у = window.event.clientY; if (window.event.srcElement.parentTextEdit) { range = window.event.srcElement.parentTextEdit. createTextRange(); range.collapse(); 282 Часть III. Объекты документа I
} } range.moveToPoint (x, y); range.expand(chunk); range.select(); </script> </head> <body bgco1or="white"> <form> <p>Choose how much of the paragraph is to be selected when you click anywhere in it:<br /> <input type="radio" name="chunk" value="character" checked="checked" />Character <input type="radio" name="chunk" value="word" />Word <input type="radio" name="chunk" value="sentence" />Sentence <font color= "white">.</fontx/p> } </form> <p onclick="selectChunk()">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in eprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </body> </html> j См. также: свойство isTextEdit; объект Text Range (глава 35). previousSibling (Cm. nextSibling) readyState Значение: строка (целочисленное для объекта obj ect) Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- До начала обработки объекта или его данных, в сценарии можно проверить загруженность объектом всех вспомогательных данных (например внешние файлы изображений или аудись/видеоклипы). Свойство readyState отображает состояние загрузки элемента. ' Возможные значения и их описание приведены в табл. 15.6. ^^^^й^ШйШшшЯ Значение HTML Значение OBJECT complete interactive loaded loading uninitialized Элемент и данные полностью загружены Данные загружены или не загружены полностью, однако пользователь может взаимодействовать с элементом Данные загружены, объект может начинать использоваться Данные загружаются Объект еще не начал загрузку данных Глава 15. Основные объекты HTML-элементов 283
Для большинства элементов HTML это свойство имеет значение complete. Большинство других состояний применяется с такими элементами, как img, embed и object, которые загружают внешние данные и даже запускают другие процессы (например элементы управления ActiveX). Предупреждение: не стоит думать, что свойство readyState позволяет определить, существует ли объект в документе (например, по значению uninitialized). Если такого объекта нет, то он не может иметь свойства readyState — это приводит к ошибке в сценарии: объект не определен. Если сценарий необходимо запустить лишь после того, как загружены все элементы и их данные, следует использовать обработчик события onload для элемента body или обработчик события onreadystatechange для текущего объекта (проверив, что свойство readyState имеет значение complete). Пример Чтобы удостовериться в том, что свойство readyState отличается от complete, изучите и выполните код, вводимый в дескрипторе <img> (см. ниже). <img id="myImgM src="someImage.gifи> <script type="text/javaScript"> alert(document.getElementByldC'mylmg").readyState); </script> Вставьте этот фрагмент кода в документ, загружаемый с помощью низкоскоростного сетевого соединения. Если изображение отсутствует в кэше браузера, то будет получен результат uninitialized или loading. Последнее означает, что объект img существует, но его данные еще не начали передаваться с сервера. При повторной перезагрузке страницы изображение загружается не из сервера, а из кэша браузера, поэтому свойство readyState принимает значение complete. См. также обработчик события onreadystatechange. recordNumber Значение: целочисленное или null Только для чтения Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Практически все объекты включают свойство recordNumber (оно применяется при внедрении объектов в Internet Explorer (для Windows) для представления повторяющихся данных). Например, при отображении 30 записей из внешнего источника в таблице элемент tr встречается в HTML-коде только один раз. Однако браузер повторяет строку таблицы (и ее компоненты-ячейки) для размещения всех 30 строк данных. Свойством recordNumber объекта tr можно воспользоваться для определения, например, на какой строке был проведен щелчок мышью. Распространенным применением этого свойства является внедрение данных, позволяющее обновлять записи. Например, можно создать сценарий, который при выборе нередактируемой строки отображает данные записи в отдельном редактируемом поле или в другом элементе страницы. Если объект не привязан к источнику данных (или он является неповторяющимся объектом), свойство recordNumber содержит значение null. Пример В листинге 15.15 показано, как можно использовать свойство recordNumber для перехода к определенной записи в последовательности данных. Источник данных представляет собой небольшой текстовый документ, в котором значения разделены символами табуляции. 284 Часть III. Объекты документ \
В нем содержится всего 20 записей. Отображаемая на странице таблица связана с этим источником данных. С ним также связаны три элемента span, которые представляют текстовый абзац в верхней части документа. Щелчок на данных строки в таблице документа приводит к соответствующему изменению текстовых данных в верхнем абзаце. Сценарий этой страницы занимает всего одну строку кода. При вызове обработчика события onclick для повторяемого объекта tr функция получает в качестве аргумента ссылку на этот объект tr. Копия данных из внешнего источника сохраняется в объекте recordset. Свойство AbsolutePosition объекта recordset указывает на номер выбранной записи (по умолчанию выбирают первую запись). В сценарии этому свойству назначается номер строки, на которой щелкнул пользователь. Поскольку все три элемента span обращаются к одному и тому же источнику данных, то их содержимое немедленно обновляется, чтобы соответствовать изменившемуся объекту recordset. Обратите внимание, что третий элемент span связан с полем источника данных, которое не представлено в таблице страницы. <html> <head> <title>Data Binding (recordNumber)</title> <style type="text/ess"> .filmTitle {font-style:italic} </style> <script type="text/javascript"> // установка указателя в записи, на которой выполнен щелчок function setRecNum(row) { document.oscars♦recordset.AbsolutePosition = row.recordNumber; } </script> </head> <body> <pxb>Academy Awards 1978-1997</b> (Click on a table row to extract data from one record.)</p> <p>The award for Best Actor of <span datasrc="#oscars" datafld=nYear"x/span> &nbsp;went to <span datasrc="#oscarsM datafld="Best Actor"></span> &nbsp;for his outstanding achievement in the film <span class="filmTitle" datasrc="#oscars" datafld="Best Actor Film"x/span>.</p> <table border="l" datasrc="#oscars" align="center"> <thead style="background-color:yellow; text-align:center"> <tr> <td>Year</td> <td>Film</td> <td>Director</td> <td>Actress</td> <td>Actor</td> </tr> </thead> <tr id="repeatableRow" onclick="setRecNum(this)"> <tdxdiv id="coll" dataf ld="Year"x/divx/td> <tdxdiv class="filmTitle" id="col2" datafld="Best Picture" ></divx/td> <tdxdiv id="col3" datafld="Best Director"x/divx/td> <tdxdiv id="col4" datafld="Best Actress"></divx/td> <tdxdiv id="col5" datafld="Best Actor"></divx/td> Глава 15. Основные объекты HTML-элементов 285
</tr> </table> <object id="oscars" classid="clsid:333C7BC4-460F-llDO-BC04- 0080C7055A83"> <param name="DataURL" value="Academy Awards.txt" /> <param name="UseHeader" value="True" /> <param name="FieldDelim" value="&#09;" /> </object> </body> </html> См. также: свойства dataFld, dataSrc; объекты table, tr (глава 37). runtimeStyle Значение: объект style Только для чтения Совместимость: Winffi5+, MacIE5+, NN-, Moz-, Safari- С помощью свойства runtimeStyle можно определить настройки стилей браузера по умолчанию. Объект style, который возвращает это свойство, принимает все атрибуты стилей и настройки по умолчанию во время загрузки страницы. Это свойство не отображает значений, присвоенных элементам стилевыми спецификациями в документе или в сценариях. Значения, возвращаемые этим свойством, отличаются от значений currentStyle. Последние включают данные о значениях, которые не присвоены в стилях явно, но подвержены влиянию браузера. Свойство runtimeStyle отображает неустановленные значения для стиля как пустые или нулевые. Пример Чтобы изменить свойство стиля, обратитесь к объекту style. Приложение The Evaluator (глава 13) позволяет сравнить свойства объектов runtimeStyle и style элемента. Например, неизмененная копия приложения The Evaluator содержит элемент em с идентификатором "туЕМ". Введите в верхнее поле приведенные далее выражения. document.getElementByld("myEM").style.color document.getElementByld("myEM").runtimeStyle.color Исходно оба свойства не имеют значений. Теперь назначьте цвет свойству style, воспользовавшись следующим выражением. document.getElementById("myEM").style.color = "red" Если после этого вы повторно введете два первых выражения, то увидите, что объект style изменился, а объект runtimeStyle — нет (по-прежнему не имеет значения). См. также: свойство currentStyle; объект style (глава 26). scopeName Значение: строка Только для чтения Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Свойство scopeName непосредственно связано с данными XML, включенными в доку-, мент. При подключении XML-кода указывается одно или несколько пространств имен XML, определяющих "владельца" определенного дескриптора. Это необходимо для предотвращения конфликтов, которые могут возникнуть в документе между одинаковыми именами дескрипторов из различных источников. (Подробно объекты XML рассмотрены в главе 41.) 286 Часть III. Объекты документ
Пространство имен XML определяется как атрибут дескриптора <html>, в который помещается документ. <html xmlns:fred='http://www.someURL.com'> После этого значение пространства имен включается во все дескрипторы документа. <fred:first_name id="fredfirstname"/> Чтобы найти "владельца" пространства имен элемента, необходимо получить его свойство scopeName. В предыдущем примере свойство scopeName имело значение Fred. Для обычных элементов HTML возвращаемое значение всегда равно html. Свойство scopeName доступно только в Ш5+ для Win32 и UNIX. Аналогичное сврйство в W3C DOM называется localName. Пример Если вы имеете в своем распоряжении тестовый документ, содержащий XML-код, то можете использовать методы document .write () или alert () для просмотра свойства scopeName. document. getElementByld ("идентификаторЭлемента") . scopeName См. также свойство tagUrn. scrollHeight scroll Width Значение: целочисленное Только для чтения Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safaril+ Свойства scrollHeight и scrollWidth содержат значения размера объекта, не зависящие от того, какая его часть видна на странице. Таким образом, если в окне браузера присутствует вертикальная полоса прокрутки и объект выходит за пределы видимой области окна, свойство scrollHeight учитывает полный размер (как если бы пользователь прокрутил страницу вниз для отображения всего элемента). Для большинства элементов, которые не имекгг своих полос прокрутки, свойства scrollHeight и scrollWidth обладают теми же значениями, что client Height и clientwidth. Пример Приложение The Evaluator (глава 13) предоставляет возможность детально изучить свойство text area. Чтобы получить список свойств объекта body, сначала введите в нижнее поле следующее выражение. document. body Далее введите в верхнее поле приведенное ниже выражение, чтобы получить свойство scrollHeight для объекта text area, который состоит из нескольких строк и имеет идентификатор output. document.getElementByld("output").scrollHeight В результате в области вывода будет отображено большое числовое значение (несколько сотен пикселей). Это означает, что вы можете прокрутить содержимое элемента output для отображения других частей элемента. Один раз щелкните на кнопке Evaluate. Предыдущий результат занимает по высоте всего одну строку, 13-ую или 14-ую, в зависимости от используемого шрифта, поэтому свойство scrollHeight объекта text area принимает именно это значение. Свойство scrollWidth этого объекта имеет фиксированное значение, определенное атрибутом cols элемента. См. также: свойства client Height, clientwidth; метод window, scroll (). Глава IS. Основные объекты HTML-элементов 287
scrollLeft scrollTop Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN7+, Mozl+, Safari 1+ Если элемент является прокручиваемым (другими словами, имеет собственные полосы прокрутки), с помощью свойств scrollLeft и scrollTop можно определить, насколько он прокручен в горизонтальном и вертикальном направлениях. Величины измеряются в пикселях. Для непрокручиваемых элементов эти свойства всегда равны нулю, даже если они содержатся внутри прокручиваемых элементов. Например, если прокрутить окно браузера (или фрейм) по вертикали, свойство scrollTop объекта body будет указывать расстояние между вершиной объекта (за пределами видимой области) и первой видимой строкой пикселей элемента. Тем не менее, свойство scrollTop таблицы внутри документа всегда равно нулю. В NN до версии 7 (Mozl) прокрутка элемента body выполняется с точки зрения окна. Если необходимо определить, насколько прокручена страница (в пикселях), воспользуйтесь свойствами window, scrolIX и window, scrollY. В сценариях, в которых отслеживаются события, связанные с мышью, в ГЕ нужно принимать в расчет свойства scrollLeft и scrollTop для компенсации прокрутки страницы (см. событие Event в главе 25). Пример Приложение The Evaluator (глава 13) позволяет исследовать эти два свойства для объекта текстовой области, в которой представлены результаты вычислений. Для начала введите в нижнее текстовое поле следующее выражение, позволяющее отобразить список свойств элемента body. document.body Используйте полосу прокрутки текстовой области для смещения в нижнюю часть списка. Далее введите следующее выражение в верхнее текстовое поле. document.getElementByld("output").scrollTop В качестве результата вы получите число, определяющее расстояние, на которое текстовая область была прокручена в вертикальном направлении. Щелкните на кнопке Evaluate еще раз. При этом будет возвращен результат 0. Это означает, что в текстовой области было недостаточно данных для выполнения прокрутки (в ней находилась всего одна текстовм строка с предыдущим результатом 0). Поскольку горизонтальная полоса прокрутки вообще не отображается, то и свойство scrollLeft тоже остается неизменным. См. также: свойства client Left, client Тор; метод window, scroll (). sourcelndex Значение: целочисленное Только для чтенщ Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Свойство sourcelndex возвращает числовой индекс (начиная с нуля) объекта в полном наборе элементов документа. Пример Операции с описываемым свойством весьма однозначны, этого не скажешь о наборе свойств объекта document .all. Вы можете использовать приложение The Evaluator для опро» деления того, корректно ли соотносятся индексы, возвращаемые свойствами sourcelndei и document. all (например, в Ш4+). 288 Часть III. Объекты документ
Для начала загрузите приложение The Evaluator и введите в верхнее поле следующее выражение. а = О При выполнении этого выражения в поле результатов должен появиться ноль. Далее введите в верхнее поле следующее выражение. document.all[a].tagName + " [" + а++ + "] " В этом выражении много знаком "плюс", поэтому отнеситесь к их вводу особенно внимательно. После выполнения этого выражения глобальная переменная а увеличит свое значение, позволив просматривать элементы в порядке их представления в коде. Значение свойства sourcelndex для каждого HTML-дескориптора приводится в квадратных скобках в поле Results. html [0] head [1] title [2] Продолжайте выполнять это выражение до тех пор, пока не достигнете конца кода и не получите сообщение об ошибке (пока не просмотрите все элементы массива document.all). Сравните полученные объекты с исходным HTML-кодом. См. также метод item (). style Значение: ссылка на объект style Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство style представляет собой "шлюз" к настройкам стилей элемента. Значением свойства является объект style, свойства которого позволяют получать и изменять установки стилей. Как правило, сценарии не управляют объектом style целиком, а используют его свойства для подключения эффектов анимации, отображения или скрытия элемента. Изменение свойств объекта style может повлиять на разметку страницы. Например, установка большего размера шрифта элемента приводит к переформатированию абзаца. Между свойствами объекта style в IE и NN существует немало различий. Более подробно об объекте style рассказано в главе 26. Пример Многие действия, выполняемые с помощью свойства style, требуют управления объектом style. Используйте приложение The Evaluator, и вы сможете ознакомиться со свойствами этого объекта в самых разных браузерах. Для начала введите следующее выражение в нижнее текстовое поле. document.body.style Теперь просмотрите свойства объекта style для элемента таблицы, которая включена в страницу приложения The Evaluator. Введите в нижнее поле такое выражение, document. getElementByld ("myTable") . style В обоих случаях значения свойств объекта style весьма ограничены. См. также: свойства currentStyle, runtimeStyle; объект style (глава 26). tablndex Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство tablndex управляет тем, в какой момент при последовательном нажатии клавиши <ТаЬ> текущий элемент активизируется. Очевидно, что это свойство имеют только те Глава 15. Основные объекты HTML-элементов 289
элементы, которые способны к активизации. В Ш5+ количество таких элементов больше, чем в других браузерах; тем не менее, почти во всех браузерах это свойство поддерживается большинством основных элементов (например элементы ввода данных форм), для которых оно может понадобиться. В большинстве случаев браузеры по умолчанию рассматривают элементы форм как активизируемые. Элементы, которые не добавляются на формы, не активизируются, если только их свойство tablndex (или атрибут дескриптора tabindex) не заданы специально. Если свойство tablndex определенного элемента формы равно 1, то он будет активизироваться первым. Остальные элементы при нажатии клавиши <ТаЬ> будут активизироваться в порядке задания в документе. Если два элемента имеют значение свойства, равное 1, то сначала выделяется тот из них, который расположен в документе первым, а затем все остальные элементы. В браузере Internet Explorer, если вы установите значение свойства tablndex равным -1, элемент можно будет полностью устранить из последовательности активизируемых объектов. Пользователи все равно смогут вносить изменения в содержимое такого элемента, однако при последовательном нажатии клавиши <ТаЬ> он выделяться не будет. Пример Листинг 15.16 содержит простой сценарий, демонстрирующий принципы управления порядком активизации элементов с помощью свойства tablndex. Например, из него вы узнаете не только о том, как изменить порядок активизации элементов форм, но и как обратиться к элементам формы, которые не включены в порядок активизации в IE. На указанной странице самая верхняя форма (именуемая lab) содержит четыре элемента. Сценарий запускается с помощью кнопок нижней формы. Обратите внимание, что свойство tablndex для всех трех кнопок нижней формы установлено в значение -1, поэтому эти кнопки не рассматриваются при формировании порядка активизации элементов в IE. При загрузке страницы порядок активизации элементов по умолчанию для формы lab изменяется. При нажатии клавиши <ТаЬ> получаемый результат будет полностью зависеть от используемого браузера. В ЕЕ сначала выделяется строка адреса, затем активизируется окно документа или кадр (в случае использования многокадрового документа). Только после этого активизируется форма и ее элементы. В NN6+ вы должны щелкнуть в любом месте формы, чтобы предоставить пользователю возможность активизировать элементы формы. Следующий простой сценарий инвертирует порядок активизации элементов. Для этого используется цикл for и две переменные. Таким образом, последнему элементу назначаете! самый меньший индекс tablndex. Функция skip2 () устанавливает свойство tablndex второго текстового поля равным -1. В результате последнее удаляется из порядка активизации элементов в ГЕ. Обратите внимание, что вы всегда можете щелкнуть в поле и ввести в нем необходимый текст. В NN6+ нельзя изменить это свойство так, чтобы исключить соответствующий элемент из списка активизации. <html> <head> <title>tablndex Property</title> <script type="text/javascriptM> function invert() { var form = document.lab; for (var 1=0, j = form.elements.length; i < form.elements.length; i++, j*-) { form.elements[i].tablndex = j; 290 Часть ///. Объекты документ
} function skip2() { if (navigator.userAgent.indexOf("MSIE") != -1) { document.lab.text2.tablndex = -1; } else { alert ("Not available.'») ; } } function resetTabO { var form = document.lab; for (var i = 0; i < form.elements.length; i++) { form.elements[i].tablndex = 0; } } </script> </head> <body> <hl>tablndex Property Lab</hl> <hr /> <form name="lab"> Text box no. 1: <input type="text" name="textl" /><br /> Text box no. 2: <input type="text" name ="text2" /xbr /> < input type =" but ton" value="A Button" /xbr /> <input type="checkbox" />And a checkbox </form> <hr /> <form name="control"> <input type="button" value="Invert Tabbing Order" tabindex="-l" onclick="invert () " /xbr /> <input type="button" value="Skip Text box no. 2 (IE Only)" tabindex=»'-l" onclick="skip2 () " /xbr /> <input type="button" value»"Reset to Normal Order" tabindex="-l" onclick="resetTab()" /> </form> </body> </html> Последняя функция resetTabO устанавливает свойство tablndex для формы lab равным нулю, что приводит к восстановлению исходного порядка активизации элементов. См. также методы blur (), focus (). tagName Значение: строка Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство tagName возвращает строку с именем дескриптора HTML или (в Ш5+ и NN6) XML объекта элемента. Все значения tagName содержат символы только верхнего регистра, даже если в исходном коде они указаны иначе. Такая согласованность облегчает сравнение строк. Например, при запуске определенных действий для некоторых (не для всех) элементов можно воспользоваться следующей функцией, содержащей оператор switch. function processObj(objRef) { switch (objRef.tagName) { Глава 15. Основные объекты HTML-элементов 291
case "TR": [операторы управления объектом строки] break; case »TD": [операторы управления объектом ячейки] break; case "COLGROUP": [операторы управления объектом группы столбцов] break; default: [операторы управления другими объектами] Пример Вы также можете использовать свойство tagName для программирования действий, подобных тем, которые представлены в предыдущем примере по управлению свойством sourcelndex. В предыдущем примере свойство tagName считывалось для объектов исходного порядка активизации. См. также: свойство nodeName; метод getElementsByTagName (). tagUrn См. свойство scopeName title Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safaril+ В стандарте W3C утверждается, что свойство title (и атрибут TITLE) необходимо использовать как "подсказку". Многие браузеры выводят текст (присвоенный свойству или» атрибуту) при наведении указателя мыши на элемент. Преимущество записи значений в это свойство заключается в возможности изменения текста подсказки элемента в ответ на взаимодействие с пользователем. Подсказка отображает информацию о назначении значков и ссылок на странице. Кроме того, она может содержать краткое резюме страницы, на которую указывает ссылка, что позволяет пользователю просмотреть информацию без перехода на другую страницу. В данном случае не рекомендуется использовать подсказки для отображения важных сведений. Не все пользователи достаточно терпеливы, чтобы навести указатель мыши и дождаться, когда появится подсказка. С другой стороны, пользователь скорее заметит появление подсказки, чем сообщение в строке состояния (хотя последнее и появляется мгновенно). Пример В листинге 15.17 показано, как можно использовать свойство title для создания всплывающих подсказок. Простой элемент абзаца в представленной странице имеет всплывающую подсказку "First Time!". Эта подсказка будет отображена на экране, если вы наведете указатель мыши на текст абзаца и задержите его там на несколько секунд. Кроме того, с помощью обработчика событий mouseover и переменной counter ведется учет количества наведений пользователем указателя мыши на абзац. В каждой следующей подсказке вы получите сведения о количестве выполненных операций. 292 Часть III. Объекты документа
<html> <head> <title>title Property</title> <script type="text/javascript"> var count = 0; function setToolTip(elem) { elem.title = "You have previously rolled atop this paragraph " + count + " time(s)."; } function incrementCount(elem) { count++; setToolTip(elem); } . </script> </head> <body> <hl>title Property Lab</hl> <hr /> <p id="myP" title="First Time!" onmouseover= "incrementCount(this)">Roll the mouse over this paragraph a few times.<br /> Then pause atop it to view the tooltip.</p> </body> </html> См. также свойство window. status. uniquelD Значение: строка Только для чтения Совместимость: Winffi5+, MacJE5-, NN-, Moz-, Safari- C помощью свойства unique ID браузер WinIE5+ позволяет генерировать идентификатор (свойство id) элемента, создаваемого на странице динамически. Это свойство следует использовать с осторожностью, так как идентификатор, созданный в определенный момент времени, может отличаться от идентификатора, генерируемого при последующем создании элемента на странице. Поэтому к свойству uniquelD обращаются тогда, когда в сценарии неизвестный элемент должен иметь свойство id, но сами алгоритмы не могут зависеть от конкретного идентификатора. Чтобы элемент получил только один идентификатор (пока объект существует в памяти), присвойте значение свойства uniquelD одного и того же объекта. Получение свойства uniquelD не влияет на его значение. Таким образом, значение свойства uniquelD присваивается свойству id объекта для выполнения других видов обработки. (Например, метод getElementByld () требует, чтобы свойству id объекта было присвоено значение.) Пример Листинг 15.18 демонстрирует синтаксис получения сгенерированного браузером идентификатора объекта. После ввода определенного текста в поле щелкните на кнопке — функция addRowO вставит в таблицу новую строку. В левом столбце приведен идентификатор, Глава 15. Основные объекты HTML-элементов 293
сгенерированный с помощью свойства uniquelD. В Ш5+ идентификаторы создаются в формате "ms_ictolf, где п представляет собой целое число текущего сеанса работы в браузере. Поскольку функция addRow () назначает идентификатор строке и ячейкам каждой строки, то целое число для каждой строки на три больше, чем для предыдущей. Нет никакой гарантии, что будущие версии браузеров наследуют этот формат и последовательность именования объектов. <html> <head> <title>Inserting an WinIE5+ Table Row</title> <script type="text/javascript"> function addRow(iteml) { if (iteml) { // сохранение длинной ссылки в переменной var theTable = document.getElementById("myTable"); // добавление новой строки в конец таблицы var newRow = theTable.insertRow(theTable.rows.length); // назначение строке идентификатора newRow.id = newRow.uniqueID; // объявление переменной строки var newCell;' // вставленная строка изначально не имеет ячеек newCell = newRow.insertCell(0); // назначение идентификатора ячейке newCell.id = newCell.uniquelD; // отображение идентификатора ячейки в качестве текста newCell.irinerText = newRow.id; newCell.bgColor = "yellow" // повторное использование переменной newCell = newRow.insertCell(1); .id = newCell.uniquelD; } } newCell. newCell.innerText = iteml; </script> </head> <body> <table id="myTable" border="l' <tr> <th>Row ID</th> <th>Data</th> </tr> <tr id="firstDataRow"> <td>firstDataRow</td> <td>Fred</td> </tr> <tr id="secondDataRow"> <td>secondDataRow</td> <td>Jane</td> </tr> </table> <hr /> <form> 294 Часть III. Объекты документ
Enter text to be added to the table:<br /> <input type="text" name="input" size="25" /xbr /> <input type='button' value='Insert Row' onclick='addRow(this.form.input.value)' /> </form> </body> </html> См. также: свойство id; метод getElementByld (). Методы addBehavior (» URLn) Возвращаемое значение: целочисленный идентификатор Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Метод addBehavior () импортирует внешнее поведение Internet Explorer и присоединяет его к текущему объекту, расширяя, таким образом, его свойства и/или методы. Подробно о поведениях Ш (новое свойство ЕЕ5 для Windows) рассказывается в главе 48. Единственным параметром метода addBehavior () является ссылка URL на код компоненты поведения. Эта компонента может располагаться во внешнем файле (с расширением . htc). В этом случае URL является либо абсолютным, либо относительным. Ш включает библиотеку встроенных (по умолчанию) поведений, URL которых имеют следующий формат. #defaul ^имяПоведения В данном случае имяПоведения представляет одно из поведений по умолчанию (глава 48). Если поведение импортируется в документ с помощью дескриптора ob j ect, то параметром метода addBehavior () является идентификатор элемента в следующем формате. #идентификаторОбъекта При добавлении поведения загрузка внешнего кода происходит асинхронно. Несмотря на то, что метод быстро возвращает значение, поведение не всегда готово к работе. Только после полной загрузки поведение может отзываться на события и предоставлять доступ к своим свойствами и методам. К поведениям, загружаемым из внешних файлов, применяются правила безопасности доменов. Пример В листинге 15.19а показано, как выглядит файл поведения. Данное поведение предназначено для демонстрации возможностей метода addBehavior (). Поведение и HTML-страница, с которой оно загружается, должны располагаться на одном сервере и в одном домене (также они должны загружать по одному протоколу). <PUBLIC:ATTACH EVENT="onmousedown" ONEVENT="makeHot()." /> <PUBLIC:ATTACH EVENT=»onmouseup" ONEVENT="makeNormal()" /> <PUBLIC:PROPERTY NAME="hotColor" /> <PUBLIC:METHOD NAME="setHotColor" /> <SCRIPT LANGUAGE="JScript"> var oldColor var hotColor = "red" Глава 15. Основные объекты HTML-элементов 295
function setHotColor(color) { hotColor = color } function makeHot() { if (event.srcElement == element) { oldColor = style.color runtimeStyle.color = hotColor function makeNormalO { if (event.srcElement runtimeStyle.color } } </SCRIPT> Поведение присоединено в объекту текстового абзаца, который приведен в листинге 15.196. При загрузке страницы поведение к объекту автоматически не присоединяется, поэтому щелчок на тексте абзаца ни к чему не приводит. При включении поведения с помощью функции turnOn () метод addBehavior () присоединяет код makeHot. ht с к объекту ту Р. Начиная с этого момента, объект туР располагает дополнительными свойством, методом и двумя обработчиками событий. Если необходимо присоединить данное поведение к другим абзацам документа, то потребуется выполнить метод addBehavior () по отношению к им всем. После распоряжения о загрузке файлу поведения в сценарии вызывается функция setlnitialColorО, с помощью которой новый цвет (выбранный в списке) назначается абзацу. Но это происходит только после полной загрузки поведения. Именно поэтому функция проверят значение свойства readyState объекта туР. Если IE все еще загружает поведение, то функция будет запущена повторно через 500 миллисекунд В процессе загрузки поведения вы можете изменить цвет выделения абзаца. Функция сначала проверяет, загружено ли поведение полностью, анализируя для этого свойство цвета для объекта. Если цвет новый, то вызывается метод добавления поведения. Вы также можете просто установить значение свойства. <html> <head> <title>addBehavior() and removeBehavior() Methods</title> <script type="text/javascript,,> var myPBehaviorlD; function turnOnO { myPBehaviorlD =' document.getElementById("myP"). addBehavior("makeHot.htc"); setlnitialColor(); } function setlnitialColor() { if (document.getElementByldC'myP").readyState == "complete") { element) { oldColor 296 Часть III. Объекты докутнп.
var select = document.forms[0].colorChoice; var color « select.options[select.selectedlndex].value; document.getElementByld("myP").setHotColor(color); } else { setTimeout ("setlnitialColor () ■', 500) ; function turnOff() { document.getElementByld("myP").removeBehavior(myPBehaviorlD); } function setColor(select, color) { if (document.getElementByld("myP").hotColor) { document.getElementByld("myP").setHotColor(color); } else { alert("This feature is not available. Turn on the Behavior first."); select.selectedlndex = 0; function showBehaviorCount() { var num = document.getElementByld("myP").behaviorUrns.length; var msg = "The myP element has " + num + " behavior(s). "; if (num > 0) { msg += "Name(s): \r\n"; for (var i = 0; i < num; i++) { msg += document.getElementByld("myP").behaviorUrns[i] + "\r\n"; alert(msg); } </script> </head> <body> <hl>addBehavior() and removeBehavior() Method Lab</hl> <hr /> <p id="myP">This is a sample paragraph. After turning on the behavior, it will turn your selected color when you mouse down anywhere in this paragraph.</p> <form> <input type="button" value="Switch On Behavior" onclick="turnOn()" /> Choose a 'hot' color: <select name="colorChoice" onchange="setColor(this, this.value)"> <option value="red">red</option> <option value="blue">blue</option> <option value="cyan">cyan</option> </select> <br /> <input type="button" value="Switch Off Behavior" onclick="turnOff()" /> <p><input type="button" value="Count the URNs" onclick="showBehaviorCount()" /></p> </form> </body> </html> Глава 15. Основные объекты HTML-элементов 297
Для отключения поведения выполняется метод reraoveBehavior (). Обратите внимание, что он связан с объектом туР и в качестве аргумента принимает идентификатор загруженного ранее поведения. Если с объектом связно несколько поведений, то вы можете удалить каждый из них отдельно от остальных (поскольку все они имеют разные идентификаторы). См. также: свойство readyState; метод removeBehavior (); поведения (глава 48). addEventListener("типСобытия", функцияПолучателяСобытия, захват) removeEventLis tener (" типСобытия11, функцияПолучателяСобытия, захват) Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Механизм событий W3C DOM включает в себя способы возникновения и перемещения событий (главу 25). Хотя новый метод обеспечивает привязку события к элементу с помощью атрибутов HTML (например, всем известный обработчик события onclick), все же рекомендуется определять события с помощью приемника события для элемента. (В браузерах, поддерживающих модель событий W3C, происходит внутреннее преобразование методов привязывания событий — например, обработчиков событий в атрибутах — в приемники событий.) Чтобы сообщить объектной модели документа, что элемент должен принимать определенный тип события, необходимо воспользоваться методом addEventListener(). Он имеет три параметра. Первый является строкой с типом события, который должен приниматься элементом. Строки с типами событий не включают префикс on, который имеют обработчики событий. Имена состоят только из названий событий, как правило, включающих только символы нижнего регистра (за исключением специальных системных событий, имена которых начинаются с префикса DOM). Все события, заданные спецификацией W3C DOM (хотя не все они поддерживаются NN6), приведены в табл. 15.7. abort blur change click DOMActivate DOMAttrModified DOMCharacterDataModified DOMFocusIn DOMFocusOut DOMNodeInserted DOMNodelnsertedlntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified error focus load mousedown mousemove mouseout mouseover mouseup reset resize scroll select submit unload 298 Часть III. Объекты документ*
Обратите внимание, что количество событий, определяемых DOM 2, является более ограниченным по сравнению с числом событий в IE4+. Кроме того, консорциум W3C временно приостановил решение вопроса о событиях клавиатуры до выхода DOM 3. К счастью, такие события поддерживаются в NN в той же форме, в которой они, вероятно, будут реализованы в W3C DOM. Вторым параметром метода addEventListener О является ссылка на функцию JavaScript. Структурно это напоминает ситуацию присвоения функции свойству объекта '(например obj Reference, onclick = Функция). Кроме того, имя функции не должно помещаться в кавычки. Такой подход означает, что в вызове функции нельзя указать параметры. Поэтому функции, которым необходим доступ к формам или их элементам управления, должны использовать собственные ссылки (в результате чтения свойства объекта события, определяющего, какой объект является целью). По умолчанию модель событий W3C DOM заставляет события всплывать вверх по иерархии элементов-контейнеров, начиная с объекта, являющегося целью события (например по щелчку на кнопке). Однако если третий параметр метода addEventListener О имеет значение true, то захват определенного типа события разрешен всякий раз, когда текущий объект является целевым. Это значит, что событие любого другого типа, целью которого является текущий объект, переместится по иерархии (если только событие также не имеет приемника события, связанного с объектом, третий параметр метода которого установлен в значение true). Использование метода addEventListener () требует, прежде всего, наличия объекта, к которому присоединен метод. Поэтому данный метод лучше вызывать внутри функции инициализации, запускаемой обработчиком события onload для всей страницы. (Объект document может вызвать метод addEventListener О сразу, поскольку этот объект существует с самого начала процесса загрузки.) Сценарий обладает возможностью удалить приемник события, который ранее был добавлен сценарием. Метод removeEventListener () имеет те же параметры, что и addEventListener (), а это значит, что отключение одного приемника не влияет на остальные. Исходя из того, что для одного события можно назначить два приемника (один — предназначенный, а второй — не предназначенный для захвата, хотя это очень редкая ситуация), три параметра метода removeEventListener () позволяют точно указать, какой приемник события из объекта следует удалить. В отличие от метода захвата в NN4, модель событий W3C DOM не имеет "глобального" механизма захвата событий независимо от цели. Метод addEventListener () очень близок по функциональности к методу attachEvent () в Ш5. Кроме того, захват событий в Ш5 можно разрешить с помощью метода set Capture (). Обе модели событий W3C и Ш5 используют свои типы синтаксиса для привязки объектов к функциям-обработчикам, поэтому реальные функции могут служить обеим моделям, а различие в версии браузера проявляется только при привязке событий. В главе 25 вопрос обработки событий в этих двух моделях освещен более подробно. Пример В листинге 15.20 приведен простой пример управления базовой моделью событий W3C DOM. При загрузке страницы приемником событий выступает браузер (за исключением кнопок). Но вы всегда можете указать приемник для события click объекта body или объекта р, который окружает элемент span (содержащий текст), причем сделать это можно двумя способами: всплывания и захвата. После добавления приемника события щелкните в тексте — в результате вы увидите процесс обработки события и узнаете о том, каким из двух методов передается событие. Обратите внимание на последовательность обработки событий. Удалите передатчики событий по одному, при этом следите за реакций браузера. Глава 15. Основные объекты HTML-элементов 299
<html> <head> <title>W3C Event Model Lab</title> <style type="text/ess"> td {text-align:center} </style> <script type="text/javascript"> // добавление приемников событий function addBubbleListener(elemlD) { document.getElementByld(elemlD).addEventListener("click", reportEvent, false); } function addCaptureListener(elemlD) { document.getElementByld(elemlD).addEventListener("click", reportEvent, true); } // удаление приемников событий function removeBubbleListener(elemlD) { document.getElementByld(elemlD).removeEventListener("click", reportEvent, false); } function removeCaptureListener(elemlD) { document.getElementByld(elemlD).removeEventListener("click", reportEvent, true); } // отображение сведений о событии function reportEvent(evt) { var elem = (evt.target.nodeType ==3) ? evt.target.parentNode : evt.target; if (elem.id mm "mySPAN") { var msg = "Event processed at " + evt.currentTarget.tagName + " element (event phase = " + evt.eventPhase + ").\n";_ document.controls.output.value += msg; // очистка сведений о событиях function clearTextAreaO { document.controls.output.value = ""; } </script> </head> <body id="myBODY"> <hl>W3C Event Model Lab</hl> <hr /> <p id="myP"xspan id="mySPAN">This paragraph (a SPAN element nested inside a P element) can be set to listen for "click" events. </spanx/p> <hr /> <form name="controls" id="controls"> <p>Examine click event characteristics:&nbsp;<input type="button" value="Clear" onclick="clearTextArea()" /> <br /> <textarea name="output" cols="80" rows="6" wrap="virtual"> </textareax/p> 300 Часть III. Объекты документ
«ctable cellpadding=H5" border="l"> <caption style="font-weight:bold">Control Panel</caption> <tr style="background-color:#ffff99"> <td rowspan="2">"Bubble"-type click listener:</td> <tdxinput type= "button" value="Add to BODY" onclick= "addBubbleListener('myBODY')" /></td> <tdxinput type= "button" value="Remove from BODY" onclick="removeBubbleListener('myBODY')" /></td> </tr> <tr style="background-color:#ffff99"> <td><input type="button" value="Add to P" onclick= "addBubbleListener(»myP')" /></td> <td><input type="button" value="Remove from P" onclick= "removeBubbleListener('myP')" /></td> </tr> <tr style="background-color:#ff9999"> <td rowspan="2">"Capture"-type click listener:</td> <td><input type="button" value="Add to BODY" onclick= "addCaptureListener('myBODY')" /></td> ctdxinput type= "button" value= "Remove from BODY" onclick= "removeCapturefListener ('myBODY') " /></td> </tr> <tr style="background-color:#ff9999"> <td><input type="button" value="Add to P" onclick= "addCaptureListener('myP')" /></td> <tdxinput type= "button" value= "Remove from P" onclick="removeCaptureListener ('myP') " /x/td> </tr> </table> </form> </body> </html> См. также методы attachEvent (), de,tachEvent (), dispatchEvent (), f ireEvent (), removeEventListener (). appendChi Id (объектЭлемеита) Возвращаемое значение: ссылка на объект узла Совместимость: Winffi5+, MacEE5+, NN6+, Mozl+, Safari 1+ Метод appendChi Id () вставляет элемент или текстовый узел (определенный в предьщущем коде) в качестве нового, последнего дочернего объекта текущего элемента. Кроме очевидного применения (добавления нового дочернего элемента к последовательности дочерних узлов), метод appendChi Id () полезен при создании объектов, предназначенных для добавления, замены или вставки в существующий документ новых данных. Метод document. createElement (), параметром которого является имя дескриптора, возвращает ссылку на элемент. Метод appendChi Id () возвращает ссылку на добавленный объект узла. Эта ссылка отличается от объекта, переданного методу в качестве параметра, так как возвращаемое значение представляет объект как часть документа, а не отдельный объект, созданный в памяти. Пример В листинге 15.21 приведен пример использования метода appendChildO совместно с методами removeChild () и replaceChild () для изменения в документе дочерних элементов. Поскольку браузеры W3C DOM рассматривают символ возврата каретки в исходном Глава 15. Основные объекты HTML-элементов 301
коде как текстовый (дочерний) узел, в листинге 15.21 HTML-код не содержит символов возврата каретки между элементами. Функция append () создает новый элемент li, а затем использует метод appendChild () для присоединения текста, введенного в текстовое поле, в качестве отображаемого текста элемента. Вложенное выражение document. createTextNode (form, input .value) выполняется, чтобы ''узаконить" операцию создания узла, добавляемого к элементу li. Все описанные выше операции выполняются до добавления элемента Ив документ. В последнем операторе функции из элемента lu вызывается метод appendChildO, чтобы добавить элемент Ив элемент lu. При вызове метода replaceChild () в функции replace () во многом используется такой же код. Разница состоит в методе двух аргументов. Второй аргумент представляет ссылку на заменяемый дочерний элемент. В этом случае заменяется последний дочерний узел элемента lu. Чтобы получить ссылку на него в коде функции, используется свойство lastChild. Полученная ссылка подставляется в качестве второго элемента метода replaceChild (). <html> <head> <title>appendChild() , removeChildO , and replaceChild() Methods</title> <script type="text/javascript"> function append(form) { if (form.input.value) { var newltem = document.createElement("LI"); newltem.appendChild(document.createTextNode(form. input.value)); j document .getElementByldC'myUL").appendChild(newltem); } } function replace(form) { if (form.input.value) { var newltem = document.createElement("LI"); var lastChild = document.getElementByldC'myUL"). lastChild; newltem.appendChiId(document.createTextNode(form. input.value)); document.getElementByld("myUL").replaceChild(newltem, lastChild); } } function restore() { var oneChild; var mainObj = document.getElementByld("myUL"); while (mainObj.childNodes.length > 2) { oneChild = mainObj.lastChild; mainObj.removeChiId(oneChild); } } </script> </head> <body> <hl>Child Methods</hl> 302 Часть III. Объекты документа
<hr /> Here is a list of items: <ul id="myUL"xli>First Item</lixli>Second Item</lix/ul> <form> Enter some text to add/replace in the list: <input type="text" name="input" size="30" /><br /> <input type="button" value="Append to List" onclick="append(this.form)" /> <input type="button" value="Replace Final Item" onclick="replace(this.form)" /> <input type="button" value="Restore List" onclick="restore()" /> </form> </body> </html> В последних операторах сценария используется метод removeChild () для удаления всех дочерних элементов узла ul. Эта операция выполняется до тех пор, пока элемент ul содержит более двух исходных узлов. Для решения данной задачи используется свойство lastChild. См. также: методы removeChild(), replaceChild (); узлы и дочерние объекты (глава 14). applyElement (объехтЭлемента [, тип]) Возвращаемое значение: отсутствует Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Метод applyElement () (не реализованный в МасШ5) позволяет вставить новый элемент в качестве родительского или дочернего элемента текущего объекта. Важным свойством данного метода является то, что новый объект заключает в себя текущий (если новый элемент является родительским) или наоборот (если новый элемент является дочерним). Когда новый элемент становится дочерним, все предыдущие дочерние объекты становятся вложенными в него (смещаются на один уровень). Легко догадаться, как действие метода влияет на уровень текущего элемента, поэтому applyElement () следует применять с осторожностью. Один из параметров — ссылка на объект — является обязательным. Этот объект создается операторами типа document. createElement () или же одним из методов дочерних узлов, которые возвращают объект. Второй (дополнительный) параметр может принимать одно из следующих значений. Значение параметра Описание outside Новый элемент становится родительским для текущего inside Новый элемент становится первым дочерним узлом текущего Если параметр опущен, по умолчанию подразумевается значение outside. В листинге 15.22 показано, как используется метод applyElement () для решения практических задач. Пример Листинг 15.22 поможет вам детальнее изучить метод applyElement (). В коде этого листинга в элемент span абзаца вставляется новый, элемент em. В любой момент вы можете просмотреть HTML-код всего элемента р, чтобы проверить, вставлен ли в него элемент em, а также проверить влияние вставленного элемента на иерархическую структуру объектов документа. Глава 15. Основные объекты HTML-элементов 303
После загрузки страницы внимательно изучите HTML-код элемента абзаца. Только после этого можете приступать к выполнению следующих операций. Обратите внимание на элемент span и вложенный в него элемент font, которые содержат всего одно слово. Если вы вставите элемент em в элемент span (щелкните на средней кнопке), то элемент еш станет первым (единственным) дочерним элементом span. При этом элемент font станет дочерним у элемента em. <html> <head> <title>applyElement() Method</title> <script type="text/javascript"> function applyOutsideO { var newltem = document.createElement("EM"); newltem.id = newltem.uniqueID; document.getElementById("mySpan").applyElement(newltem); } function applylnside() { var newltem = document.createElement("EM"); newltem.id = newltem.uniquelD; document.getElementByld("mySpan").applyElement(newltem, "inside"); } function showHTMLO { alert(document.getElementByld("myP").outerHTML); } </script> </head> <body> <hl>applyElement() Method</hl> <hr /> <p id="myP">A simple paragraph with a <span id="mySpan"><font size=" + l">special</fontx/span> word in it.</p> <form> <input type="button" value="Apply &lt;EM&gt; Outside" onelick="applyOutside()" /> <input type="button" value="Apply &lt;EM&gt; Inside" onclick="applylnside()" /> <input type="button" value="Show &lt;P&gt; HTML..." onclick=" showHTMLO " /xbr /> <input type="button" value="Restore Paragraph" onclick="location.reload()" /> </form> </body> </html> Результаты вставки и удаления элемента em визуально проявляются в изменении начертания всего одного слова на странице. Тем не менее, в приведенном примере видно, насколько сильно влияние всего одного элемента на общую иерархическую структуру HTML-документа. См. также методы insertBef ore (), appendChild (), insertAdjacentElement (). 304 Часть III. Объекты документа
attachEvent (" имяСобытия", ссылкаНаФункцию) detachEvent("имяСобытия", ссылкаНаФункцию) Возвращаемое значение: булевого типа Совместимость: Winffi5+, МасШ-, NN-, Moz-, Safari- Метод attachEvent () используется в коде, который определяет поведения Ш (глава 48). Его можно также применить как еще один способ привязки обработчика событий к объекту. В следующем примере приведен типичный подход для назначения обработчика события. myObject.onmousedown = setHilite; С помощью метода attachEvent () эта операция выполняется следующим образом. myObject.attachEvent("onmousedown", setHilite); Оба параметра являются обязательными. Первый из них представляет собой строку с именем элемента (регистр учитывается). Второй — ссылку на функцию, запускаемую при возникновении события. Эта ссылка представляет собой идентификатор функции с учетом регистра без кавычек и скобок (а это значит, что при таком вызове функции ей нельзя передать параметры). Использование метода attachEvent О имеет небольшое преимущество по сравнению , с привязкой событий к атрибутам элемента. В первом случае метод возвращает значение true, если привязка события прошла успешно. Ш сообщает об ошибке, если функция указана неверно, поэтому при обработке ошибок не стоит полагаться на значение false. Кроме того, метод не дает подтверждения, что объект распознал имя события. Если для привязки обработчика к событию объекта использовался метод attachEvent (), то обратное действие можно произвести с помощью метода detachEvent (). Параметры последнего совпадают с параметрами метода attachEvent (). Метод detachEvent () не может отключить события, привязка которых была выполнена в атрибутах дескриптора или установкой свойств событий. ; В модель событий W3C DOM включены функции, подобные этим методам в IE: addEvent - Listener () и removeEventListener (). Пример Используйте приложение The Evaluator (глава 13) для создания функции, которая вызывается при возникновении события onmousedown для объекта первого абзаца страницы. Начните с назначения функции глобальной переменной а (уже инициализированной в The Evaluator) в верхнем поле. а = new Function ("alert ('Function created at " + (new DateO) + "')") Кавычки и скобки делают выражение весьма запутанным, поэтому будьте внимательны при его вводе. Если вы все ввели правильно, то в области результатов будет представлен текст функции. Теперь назначьте эту функцию в качестве обработчика события onmousedown элемента туР, введя в верхнем поле следующее выражение. document.getElementByld("туР").attachEvent("onmousedown", а) Если оно будет выполнено успешно, в области результатов выводится значение true. При наведении указателя мыши на первый абзац в окне сообщения будут указаны дата и время создания функции обработки события (выполняется выражение newData ()). Чтобы отменить связь между объектом и обработчиком событий, введите в верхнее поле «следующее выражение. document .getElementByld ("myP") . detachEvent ("onmousedown", a) См. также: методы addEventListener (), detachEvent (), dispatchEvent (), f ireEvent (), removeEventListener (); привязка событий (глава 14). Глава 15. Основные объекты HTML-элементов 305
blur () focus О Возвращаемое значение: отсутствует Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Метод blur () делает элемент неактивным, а метод focus — наоборот, активизирует элемент. Хотя методы blur () и focus () подцерживались уже самыми ранними версиями браузеров, не все объекты можно активизировать. Браузеры до ГЕ4 и NN6 имеют ограниченную поддержку этих методов в объекте window и элементах управления форм. Окна Метод blur () (NN3+, ГЕ4+) размещает указанное окно за всеми открытыми на экране окнами. Если открыты окна других программ (например почтовых клиентов или приложений загрузки новостей), окно, в котором выполнялся метод blur (), размещается позади других окон. В браузерах Mozilla метод window. blur (), не корректирует порядок расположения текущего окна в стеке (таким образом в этих браузерах кнопка Put Me in Back листинга 15.23 не работает). В сценарии можно воспользоваться следующим способом: с помощью метода focus () окажите воздействие на другое окно и переместите его на передний план (мы говорим о связи, возникающей при использовании свойства window. opener, которая должна существовать между двумя окнами). Открывая новое окно, уделите особое внимание его размещению на экране. При быстром отображении окна после щелчка мышью пользователь может скрыть меньшее окно за большим. Как правило, неопытные пользователи не обращают внимания на панель задач Windows или меню браузера (если оно есть), не проверяют, открыто ли еще меньшее окно, и, таким образом, не активизируют его. Если вспомогательное окно является важным, то в каждом окне следует разместить кнопку или другой элемент, позволяющий пользователю легко переходить от окна к окну. Метод window. focus () размещает текущее окно поверх всех остальных окон (т.е. в начале стека). Вы можете не размещать на странице кнопку, активизирующую скрытое окно,— постройте функции открытия окон так, чтобы открываемое окно автоматически выводилось на передний план (как показано в листинге 15.23). Это упрощает навигацию по Web-узлу. Чтобы достичь успеха, проверьте правильность всех ссылок на окна. Будьте внимательны при использовании свойства window. opener для обращения к главному окну в случае, когда вспомогательное окно его активизирует. Элементы форм Методы blur () и focus () применяются, прежде всего, к элементам управления форм: текстовым полям, элементам select и text are а. Подобно тому, как изображение с камеры становится нечетким при изменении фокуса, текстовый объект становится "нечетким", отдаленным при его деактивизации — когда кто-то активизирует другое поле. В сценарии метод blur () снимает выделение с поля и удаляет курсор введения текста. При этом курсор не переходит к следующему полю, как это происходит при нажатии клавиши <ТаЬ> вручную. Для текстового объекта активность обозначает наличие курсора, ожидающего введенвд текста в поле объекта. Активизация означает "открытие" поля для редактирования его значения пользователем. Активизация текстового поля или элемента textarea сама по себе не позволяет разместить курсор в определенной части поля. Курсор, как правило, появляется в начале текста. Дад подготовки поля к замене существующего текста необходимо последовательно воспользоваться 306 Часть III. Объекты документ*
методами focus () и select (). Помните, что метод focus () работает ненадежно в браузере NN3 для UNIX: хотя метод select () и позволяет выделить текст в поле, однако поле чаще всего не активизируется. Еще одна проблема в совместном применении методов focus () и select () для предварительного выделения содержимого поля заключается в следующем: многие версии Internet Explorer не позволяют получить желаемых результатов из-за внутренних проблем с синхронизацией. Эту проблему можно обойти (и обеспечить совместимость с NN), инициируя действия активизации и выделения с помощью метода setTimeout (). Соответствующий пример приведен в главе 43. Распространенным требованием к документу является размещение курсора в конце текстового поля или элемента textarea, чтобы пользователь мог добавить текст к уже существующему содержимому. В Ш4+ это достигается в результате применения объекта TextRange. Следующий сценарий перемещает текстовый курсор в конец элемента textarea, идентификатором которого является myTextarea. var range = document.all.myTextarea.createTextRange(); range. move (" text edit") ; range.select () ; При совместном использовании методов blur () или focus (), а также обработчиков событий onblur и onf ocus необходимо проявлять осторожность (особенно если обработчики выводят на экран окна с предупреждениями). Многие комбинации таких событий и методов могут создать бесконечный цикл, в результате чего закрыть диалоговое окно будет невозможно. С другой стороны, существует комбинация этих методов и обработчиков, полезная для старых версий браузеров, в которых текстовые поля не обладают свойством disabled. Следующий обработчик события для текстового поля предотвращает ввод информации в него. onfocus = "this.blur()"; Некоторые операционные системы и браузеры позволяют активизировать такие элементы, как кнопки (включая флажки и переключатели) и гиперссылки (включая элементы а и area). Когда такой элемент активизируется, вместо щелчка кнопкой мыши нажимается клавиша пробела на клавиатуре. Это свойство может быть полезным тем, кому трудно пользоваться мышью. Л Нежелательным сторонним эффектом в отдельных ОС является то, что признак активности элемента (пунктирный прямоугольник) остается вокруг кнопки и после щелчка на ней мышью (причем до тех пор, пока активным не станет другой элемент). Чтобы избежать этого, включите следующий обработчик события onmouseup в атрибутах кнопок. onmouseup = "this.blur()"; В Ш5.5 установка свойства hide Focus в значение true позволяет устранить эффект выделения пунктиром элемента при его активизации. Однако пользователь уже не сможет визуально определить, какой элемент на странице в данный момент активен. Другие элементы При управлении другими элементами методом focus () можно воспользоваться вместо метода scrollIntoViewO . Ссылки (а) и элементы area в версии IE для Windows после активизации будут окружены пунктирным прямоугольником. Если этот эффект нежелателен, следует применить тот же обработчик события onmouseup = "this.blur () " ; (или свойство hide Focus в Ш5.5+), о котором было рассказано в разделе "Элементы форм". Компания Microsoft в браузере Ш5 расширила количество объектов, поддерживающих методы blur () и focus (). Глава 15. Основные объекты HTML-элементов 307
Пример В листинге 15.23 приведен пример использования методов focus () и blur () для активизации окон браузера. В рассматриваемом примере рабочая среда состоит из двух окон. Из каждого из окон можно активизировать другое окно. Для создания ссылки на новое окно в главном окне используется метод window. open (). Во вложенном окне (его содержимое создается динамически с помощью JavaScript-кода) для доступа к исходному окну используется свойство self .opener. При этом к самому вложенному окну применяется метод self .blur (). Активизация одного окна и деактивизация другого приводит к тому же результату, что и отображение одного окна поверх другого на рабочем столе. <html> <head> <title>Window Focus О and Blur()</title> <script type="text/javascript"> // объявление глобальной переменной var newWindow = null; function makeNewWindow() { // проверка существования окна if (!newWindow || newWindow.closed) { // сохранение нового объекта окна в глобальной переменной newWindow = window.open С'","","width=250,height=250"); // небольшая пауза для завершения открытия окна в IE3 setTimeout("fillWindow()",100); } else { // окно существует, вывод его на передний план newWindow.focus(); // компоновка нового содержимого и вывод его в подокне function fillWindowO { var newContent = "<html><headxtitle>Another Sub Window <\/titlex\/head>" ; newContent += "<body bgColor='salmon1>"; newContent += "<hl>A Salmon-Colored Subwindow.<\/hl>"; newContent += "<form><input type='button1 value='Bring Main to Front" onclick='self.opener.focus()'>"; newContent += "<formxinput type='button' value=' Put Me in Back' onclick='self.blurO •>"; newContent += "<\/form><\/body><\/html>"; // написание HTML-кода в окно нового документа newWindow.document.write(newContent); newWindow.document.close(); } </script> </head> <body> <hl>Window focus() and blur() Methods</hl> <hr /> <form> <input type="button" name="newOne" value="Show New Window" onclick="makeNewWindow0» /> </form> </body> </html> 308 Часть III. Объекты документ
Ключевой оператор в функции makeNewWindow () в этом листинге — это первое условное выражение. Поскольку переменная newWind при загрузке страницы инициализируется значением null, то это же значение она принимает сначала и в функции. Но после отображения второго окна^ переменной newWind сохраняется объект этого (вложенного) окна; такое значение сохраняется в переменной даже после закрытия окна. Таким образом, переменная newWind не принимает значение null. Чтобы проверить закрыл ли пользователь вложенное окно, используется условное выражение в начале функции. В главе 25 речь пойдет о методе focus () для текстовых объектов. См. также методы window. open (), document. f ormObj ect. textObj ect. select (). clearAttributes () Возвращаемое значение: отсутствует Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Метод clearAttributes () удаляет все атрибуты элемента, за исключением name и id. Таким образом, удаляются параметры стилевого форматирования, обработчики событий, а также атрибуты, присвоенные в исходном HTML-коде или в сценарии. Помните, что метод clearAttributes () не изменяет длину набора атрибутов элемента, так как этот набор всегда содержит все возможные атрибуты элемента. (Вернитесь к свойству attributes, рассмотренному ранее в этой главе.) Этот метод удобен тогда, когда нужно создать абсолютно новый набор атрибутов элемента и начать отображение элемента "с чистого листа". Помните: если в сценарии атрибутам не присвоить новые значения, элемент будет отображаться в первичном состоянии до тех пор, пока новые значения не будут установлены. Это значит, что даже позиционируемые элементы окажутся в неупорядоченном состоянии (до тех пор, пока не будет задан новый стиль позиционирования). Если вам нужно лишь изменить значение одного или нескольких атрибутов, воспользуйтесь методом setAttribute () или определите соответствующее свойство. Чтобы получить тот же результат в NN6+/Mozl+, необходимо в цикле очистить значения всех атрибутов (методом removeAttribute ()), кроме id и name. Пример Используйте приложение The Evaluator (глава 13) для изучения атрибутов элемента до и после применения метода clearAttributes О . Для начала отобразите HTML-код для элемента'таблицы, введя в вверхнее текстовое поле следующее выражение. myTable.outerHTML Обратите внимание на атрибуты дескриптора <table>. Взгляните на отображенную в документе таблицу, чтобы оценить влияние на нее атрибутов border и width. Введите в верхнее поле приложения следующее выражение для удаления из элемента всех подлежащих этой операции атрибутов. myTable.clearAttributes() Еще раз взгляните на таблицу. Границы таблицы исчезли, а ее ширина определяется исключительно ее содержимым. Наконец, ознакомьтесь с HTML-кодом таблицы после удаления атрибутов, воспользовавшись свойством outerHTML. myTable.outerHTML Файл с исходным кодом не изменился, хотя объектная модель в памяти браузера все еще отражает выполненные над атрибутами операции. См. также свойство attributes; методы getAttribute (), setAttribute О , removeAt tribute (), me rgeAt tributes () и setAttributeNode (). Глава 15. Основные объекты HTML-элементов 309
clickO Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE4+, NN2+, Mozl+, Safari 1+ Метод click () позволяет сценарию произвести действие, равнозначное щелчку на элементе. Данный метод существовал с момента появления языка сценариев, однако он был доступен только для таких элементов input, как кнопки (командные кнопки, кнопки восстановления, отправления, переключатели и флажки). В ранних версиях браузеров операторы обработчиков событий необходимо было указывать напрямую. Кроме того, не на всех платформах кнопки реагируют в ответ на "щелчок" из сценария. Например, NN4 для Мае не изменяет состояния флажка из сценария. Если вам требуется, чтобы сценарий "щелкал" на кнопке, проще всего напрямую запустить обработчик события. Если элемент является переключателем или флажком, то его состояние придется изменять вручную (например установить свойство checked флажка), а не ждать, что это сделает браузер. Пример Используйте приложение The Evaluator для изучения метода click (). В нижней части страницы приложения содержится несколько разных типов элементов управления. Чтобы "щелкнуть", например, на флажке, выполните следующее выражение, введя его в верхнее поле. document.myForm2.myCheckbox.click() Если вы используете браузер одной из последних версий, то флажок изменит свое состояние с установленного на сброшенный при каждом следующем выполнении последнего выражения. См. также обработчик события onclick. cloneNode (булевоЗначение) Возвращаемое значение: ссылка на объект узла Совместимость: Winffi5+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Метод cloneNode () создает точную копию объекта узла. Эта копия не имеет родительского узла и не обладает другими типами взаимосвязей с остальными элементами (конечно же, исходный узел остается на своем месте). Копия не становится частью объектной модели документа, если только явно не вставить и не добавить узел где-либо на странице. Копия' включает все атрибуты исходного элемента, в том числе и атрибут ID. Так как значение, возвращаемое методом cloneNode (), является самым настоящим объектом Node, к нему можно применить любой из методов Node, хотя объект и не является частью документа J Значение логического типа, являющееся аргументом метода cloneNode () управляет] тем, что включает копия узла: все его дочерние узлы (true) или только сам узел (false)j Например, если создать только копию элемента абзаца, она будет содержать лишь элемент (т.е. пару дескрипторов и атрибуты открывающего дескриптора), исключая его содержимое.! Включение дочерних узлов делает все содержимое элемента частью копии. Этот параметр явл*| ется необязательным в Ш5 (имея по умолчанию значение false) и обязательным в W3C DOM.J Пример I Используйте приложение The Evaluator (глава 13) для клонирования, переименования и при-1 соединения элементов, управляемых в исходном коде приложения. Начните с дублировании элемента абзаца туР вместе с его содержимым. Введите в верхнее поле следующее выражение. 1 а = document.getElementByld("myP").cloneNode(true) Щ 310 Часть III. Объекты документ
Переменная а теперь содержит исходный узел, поэтому вы можете изменить ее атрибут id, введя следующее выражение. а. setAttribute ("id", "Dolly") Если вы хотите ознакомиться со свойствами клонированного узла, то введите в нижнее поле переменную а. Точный список свойств зависит от используемого браузера и его версии. В любом случае вы должны ознакомиться со свойством id, которое теперь имеет значение Dol ly. На последнем этапе присоедините новый переименованный узел в конец элемента body, введя в верхнее поле такое выражение. document.body.appendChi1d(а) Теперь вы можете прокрутить страницу вниз и увидеть добавленный в него абзац. Поскольку два узла имеют разные идентификаторы, то в сценарии не возникает путаницы с их управлением. См. также: объект Node (глава 14); методы appendChild(), removeChild(), removeNode (), replaceChild () и replaceNode (). componentFromPoint (x,y). Возвращаемое значение: строка Совместимость: WinIE5+, МасШ-, NN-, Moz-, Safari- Метод componentFromPoint () помогает решать некоторые задачи по управлению событиями. Его используют для "поиска" событий (другими словами, для определения того, где произошло событие: внутри или снаружи определенного элемента). Если элемент имеет полосы прокрутки, метод возвращает дополнительную информацию о событии, например, какую компоненту полосы прокрутки активизировал пользователь. Ключевым аспектом этого метода является то, что его применяют для элемента, используемого в качестве ссылки. Например, если нужно проверить, произошло ли событие mouseup для элемента с идентификатором myTable, метод запускается следующим образом. var result = document.all.myTable.componentFromPoint(event.clientX, event.clientY); " Параметрами метода являются координаты х и у. Они не поступают от события, но, как правило, привязывают метод к определенному событию. События мыши (кроме onclick) подходят лучше всего. Строка, возвращаемая методом, характеризует точку, в которой произошло событие. Если она находится внутри элемента, метод возвращает пустую строку. Если точка находится за пределами элемента, строка содержит значение "outside". Для полос прокрутки список возвращаемых значений несколько шире (как показано в табл. 15.8). Компания Microsoft определяет дополнительные значения, соответствующие изменению размеров элемента (это происходит в специальном режиме, называемом авторизованным режимом DHTML в Windows). Указанный режим требует наличия специального элемента ActiveX, который не рассматривается в этой книге. Такие значения также перечислены в табл. 15.8. Возвращаемая строка Компонента элемента в указанной точке scrollbarDown scrol IbarHThumb scrollbarLeft Кнопка прокрутки вниз Бегунок на горизонтальной полосе прокрутки Кнопка прокрутки влево Глава 15. Основные объекты HTML-элементов 311
Окончание табл. 15.S Возвращаемая строка Компонента элемента в указанной точке scrolIbarPageDown scrollbarPageLeft scrollbarPageRight scrolIbarPageUp scrollbarRight scrollbarUp scrolIbarVThumb handleBottom handleBottomLeft handleBottomRight handleLeft handleRight handleTop handleTopLeft handleTopRight Область постраничной прокрутки вниз Область постраничной прокрутки влево Область постраничной прокрутки вправо Область постраничной прокрутки вверх Кнопка прокрутки вправо Кнопка прокрутки вверх Бегунок на вертикальной полосе прокрутки Нижний элемент изменения размера Нижний левый элемент изменения размера Нижний правый элемент изменения размера Левый элемент изменения размера Правый элемент изменения размера Верхний элемент изменения размера Верхний левый элемент изменения размера Верхний правый элемент изменения размера Однако для большинства событий этот метод использовать не нужно. Свойство srcElement объекта события возвращает ссылку всегда, когда происходит событие. Пример Листинг 15.24 демонстрирует метод component FromPoint (), используемый для определения места возникновения события. Таким образом, метод связывается с объектом textarea, размер которого специально изменялся, чтобы на экране отобразились полосы прокрутки. После щелчка в произвольной области объекта textarea или другом месте документа в строке состояния не без помощи метода component FromPoint () отобразится информацм о месте возникновения события. В сценарии комбинация свойства event. srcElement и метода component FromPoint () используется для определения способа обработки событий. Свойство srcElement применяется как фильтр, определяющий будет ли отображаться в строке состояния информация о событиях. Обработчик события onmousedown элемента body выполняет все действия по управлению событиями. В Ш используется метод всплывания событий (на странице не отменяется не одно событие), поэтому все события mousedown достигают элемента body. Таким образом функция wherelnWorld () может определить, где произошло событие mousedown: в пр* делах текстовой области или в остальной части страницы. chtml> <head> <title>componentFromPoint() Method</title> <script type="t.ext/j avascript" > function wherelnWorld(elem) { var x = event.clientX; 312 Часть III. Объекты документ*
jj" ■" var у = event .clientY; l~" var component = document.getElementByldC'myTextarea"). I componentFromPoint(x,y); ^ if (window.event.srcElement == document. getElementByldC'myTextarea")) { [■■ if (component == "") { p status = "mouseDown event occurred inside the element"; } else { ; status = "mouseDown occurred on the element\'s " + component; Г } l } else { v status = "mouseDown occurred " + component + f " of the element"; ь } и </script> h ' </head> \\ <body onmousedown="whereInWorid () " > <hl>componentFromPoint() Method</hl> \ <hr /> <p>Tracking the mouseDown event relative to the textarea i object. View results in status bar.</p> *■" <form> v <textarea name="myTextarea" wrap="off" cols="12" rows="4"> \ This is Line 1 This is Line 2 r This is Line 3 ; This is Line 4 This is Line 5 \- This is Line 6 ■\ </textarea> y\ </form> fy </body> N/html> *к. См. также объект event. contains (ссылкаНаОбъектЭлемента) Возвращаемое значение: булевого типа Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Метод contains () сообщает, содержит ли текущий объект другой известный объект в иерархии контейнера HTML. Обратите внимание на то, что это не определение физически накладывающихся элементов, а анализ того, вложен ли один элемент в другой. Метод contains () просматривает всю иерархию текущего объекта в поисках вложенного объекта. По существу, метод contains () проверяет все элементы, входящие в массив all. ; Потому указанный метод можно использовать вместо цикла, с помощью которого обычно осуществляют поиск вложенного элемента. Параметром метода contains () является ссылка на объект. Если задается только строка— идентификатор объекта, то для поиска ссылки на вложенный элемент можно использовать метод document .all. item(). Если одним идентификатором обладает несколько объектов, то браузер выдаст ошибку сценария, так как ссылка на такие элементы является ссылкой на массив, а не на один объект. Шва 15. Основные объекты HTML-элементов 313
Элемент всегда содержит самого себя. Пример Используя приложение The Evaluator, определите, как метод contains () определяет наличие одного объекта в другом объекте. Для этого введите следующие выражения в верхнее поле страницы приложения. document.body.contains(document.all.myP) document.all.myP.contains(document.all.item("myEM")) document.all.myEM.contains(document.all.myEM) document.all.myEM.contains(document.all.myP) Экспериментируйте с другими комбинациями объектов документа. См. также методы item (), document. getElementByld (). detachEvent () См. attachEvent(). dispatchEvent(объехтСобытия) Возвращаемое значение: булевого типа Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Метод di spa tchE vent () позволяет сценарию эмулировать событие для любоге объекта, который его поддерживает. Это обобщенный метод модели событий W3C, который был частично реализован в более ранних версиях браузеров с помощью таких методов, как click() и focus(). Процесс генерирования одного из событий с помощью этого метода подобен созданию в сценарии нового узла и вставке в объектную модель документа. Однако для событий создаваемый объект является объектом Event, который генерируется методом document. createEvent (). Событие, генерируемое таким способом, является просто его экземпляром. Для задания параметров экземпляров события (например указания координат или кнопки мыши) необходимо использовать свойства объекта события. Запустите событие с помощью метода dispatchEventf) и передайте в него новосозданный объект Event как единственный параметр. Интерпретация значения булевого типа, которое возвращает dispatchEvent О, нети проста. Браузер отслеживает запущенное событие согласно типу установленного способа обработки событий (всплывание или захват). Если определенная функция приемника событий запускает метод preventDefault (), то метод dispatchEvent О возвращает false, указывая на то, что событие не вызывает естественного действия для объекта; иначе метод возвращает значение true. Обратите внимание, что возвращаемое значение ничего не сообщает о типе обработки события или о том, сколько функций-приемников события вызываете! при запуске события. Несмотря на то, что метод dispatchEvent О реализован в NN6, браузер не обеспечивает способ генерирования новых событий. Если попытаться перенаправить существующее событие другому объекту с помощью метода dispatchEvent () браузер сможет аварийно завершить работу. 314 Часть III. Объекты документа
Пример В листинге 15.25 показано, как в W3C DOM с помощью метода dispatchEvent () события генерируются программным образом. Обратите внимание на синтаксис функции doDispatch (), которая используется для создания и инициализации нового события, связанного с мышью в Mozilla-совместимых браузерах. Поведение этой страницы идентично поведению страницы листинга 15.26, в которой используется эквивалентная функция f ireEvent () (она поддерживается в IE5.5+). <html> <head> <titlex/title> <style type="text/ess"> #mySPAN {font-style:italic} </style> <script type="text/javascript"> // установка нескольких свойств объекта события function getEventProps(evt) { var msg = ""; var elem = evt.target; msg += "event.target.nodeName: " + elem.nodeName + "\n"; msg += "event.target.parentNode: " + elem.parentNode.id + "\n"; msg += "event button: " + evt.button; return msg; } // обработчик события onclick для объектов body, myP и mySPAN function bodyClick(evt) { var msg = "Click event processed in BODY\n\n"; msg += getEventProps(evt); alert(msg); checkCancelBubble(evt); function pClick(evt) { var msg = "Click event processed in P\n\n"; msg += getEventProps(evt); alert(msg); checkCancelBubble(evt); function spanClick(evt) { var msg = "Click event processed in SPAN\n\n"; msg += getEventProps(evt); alert(msg); checkCancelBubble(evt); } // отмена всплывания события при установке флажка function checkCancelBubble(evt) { if (document.controls.bubbleOn.checked) { evt.stopPropagation(); } } Главе 15. Основные объекты HTML-элементов 315
// назначение обработчиков события onclick для трех элементов function init() { document.body.onelick « bodyClick; document.getElementById("myP").onclick = pClick; document.getElementById("mySPAN").onclick = spanClick; } // вызов метода dispatchEvent (") для объекта с ID, // подставляемым в качестве параметра function doDispatch(objID, evt) { // создание пустого события мыши var newEvt = document.createEvent("MouseEvents"); // инициализация щелчка кнопкой с ID 3 newEvt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 3, null); // передача события элементы, подставленному как параметр document.getElementById(objID).dispatchEvent(newEvt); // запрет всплывания событий щелчков evt.stopPropagation(); } </script> </head> <body id=MmyBODY" onload="init0"> <hl>dispatchEvent() Method</hi> <hr /> <p id="myP">This is a paragraph <span id="mySPAN"> (with a nested SPAN)</span> that receives click events.</p> <hr /> <pxb>Control Panel</bx/p> <form name="controls"> <p><input type="checkbox" name="bubbleOn" onclick="event.stopPropagation()" />Cancel event bubbling.</p> <pxinput type="button" value="Fire Click Event on BODY" onclick="doDispatch('myBODY', event)" /></p> <pxinput type= "button" value="Fire Click Event on myP" onclick="doDispatch( 'myP' , event) " /x/p> <p><input type="button" value="Fire Click Event on mySPAN" onclick="doDispatch('mySPAN', event)" /></p> </form> </body> </html> См. также метод f ireEvent (). f ireEvent (" типСобытия11 [, ссылхаНаСобытие]) Возвращаемое значение: булевого типа Совместимость: WinIE5.5+, МасШ-, NN-, Moz-, Safari- Несмотря на то, что некоторые объекты имеют методы эмуляции физических событий (например методы click() и focus О), IE5.5 обобщает механизм, позволяя сценарин) направить любое подходящее событие любому объекту. Его переносчиком является метод fireEvent (). Один из требуемых параметров — тип события; он задается как строка. Типы событий в JE называются так же, как и свойства для обработчиков (например onclick, onmouseover и т.д.). 316 Часть III. Объекты ломтю
Второй дополнительный параметр представляет собой ссылку на существующий объект event. Этот объект может быть событием, вызываемым пользователем или системой {подразумевается, что метод f ireEvent О является функцией, запускаемой обработчиком -события). Существующее событие может быть также объектом, созданным методом document.createEventObject () в IE5.5. В любом случае существующий объект event указывается с целью задания свойств объекта event, создаваемого методом f ireEvent (). Тип события определяется первым параметром метода, но если необходимо установить другие свойства (например координаты указателя или код клавиши), они выбираются у существующего объекта. Ниже приведен пример кода, который создает новое событие mousedown, устанавливающее некоторые свойства, а затем запускающее событие для элемента на странице. var newEvent = document.createEventObject(); newEvent.clientX = 100; newEvent.сlientY = 30; newEvent.cancelBubble = false; newEvent.button = 1; document.all.myElement.fireEvent("onmousedown", newEvent); События, генерируемые методом f ireEvent О, совпадают с обычными объектами window.event в ГЕ и имеют несколько важных свойств объекта event, предварительную установку которых производит браузер. Важно, что свойство cancelBubble имеет значение false, a returnValue— значение true (как это происходит, когда событие генерируется пользователем или системой). Таким образом, если требуется предотвратить всплывание событий и/или действие исходного элемента события по умолчанию, то функции обработчиков событий должны устанавливать эти события объекта event так, как это обычно происходит в ГЕ. Метод f ireEvent () возвращает значение булевого типа, которое определяется свойством returnValue. Если свойство returnValue имеет значение false во время обработки события, метод f ireEvent () также возвращает значение false. При обычной обработке метод возвращает значение t rue. > Несмотря на то, что модель событий W3C DOM 2 включает метод dispatchEvent () для обработки событий, генерируемых в сценарии (и методы объекта Event для создания объектов событий), Microsoft не следует рекомендациям стандарта. В базовых операциях методы f ireEvent () и dispatchEvent () похожи, однако в серьезных приложениях между ними возникает существенная разница (например в том, как распространяются события, или как объект Event представлен в модели W3C). Пример Листинг 15.26 содержит код сценария, в котором события генерируются программным образом с помощью метода f ireEvent (). Три кнопки на представленной странице позволяют сгенерировать событие щелчка для каждого из трех элементов, которым назначены обработчики событий. Возникающие таким образом события искусственные, поскольку создаются с помощью метода createEventObject О. В демонстрационных целях свойство button этих событий устанавливается в значение 3. Обычно свойство с таким значением задается для объектов event, которые в конечном счете указывают на элемент. При включенном всплывании событий, те из них, которые сгенерированы методом f ireEvent (), подобны событию щелчка на реальных объектах. Таким образом, если отключить всплывание событий, то первый же обработчик событий предотвратит всплывание события, и дальнейшая обработка события будет прекращена. Учтите, что всплывание события отменяется в обработчиках событий, которые управляют событиями. Глава 15. Основные объекты HTML-элементов 317
<html> <head> <titlex/title> <style type="text/ess"> #mySPAN {font-style:italic} </style> ocript type="text/javascript"> // назначение свойств объекта события function getEventProps() { var msg = ""; var elem = event.srcElement; msg += "event.srcElement.tagName: " + elem.tagName + "\n"; msg += "event.srcElement.id: " + elem.id + "\n"; msg += "event button: " + event.button; return msg; } // обработчики события onClick для объектов body, myP и mySPAN function bodyClick() { var msg = "Click event processed in BODY\n\n"; msg += getEventProps0; alert(msg); checkCancelBubble(); } function pClickO { var msg = "Click event processed in P\n\n"; f msg += getEventProps(); alert(msg); checkCancelBubble(); } function spanClick() { var msg = "Click event processed in SPAN\n\n"; msg += getEventProps(); alert(msg); checkCancelBubble(); } // отмена всплывания события при установке флажка function checkCancelBubble() { event.cancelBubble = document.controls.bubbleOn.checked; } // назначение обработчиков onclick трем элементам function initO { document.body.onclick = bodyClick; document.getElementByldC'myP").onclick = pClick; document .getElementByldCmySPAN").onclick = spanClick; } // вызов метода fireEventO для объекта, // ID которого подставляется как параметр function doFire(objID) { var newEvt = document.createEventObject(); newEvt.button = 3; document.all(objID).fireEvent("onclick", newEvt); 318 Часть III. Объекты докутнш
// предотвращение всплывания события щелчка event.cancelBubble = true; } </script> </head> <body id="myBODY» onload="init0"> <hl>fireEvent() Method</hl> <hr /> <p id="myP">This is a paragraph <span id="mySPAN"> (with a nested SPAN)</span> that receives click events.</p> <hr /> <pxb>Control Panel</bx/p> <form name="controls"> <p><input type="checkbox" name="bubbleOn" onclick="event.cancelBubble=true" />Cancel event bubbling.</p> <pxinput type= "button" value="Fire Click Event on BODY" onclick="doFire('myBODY')" /></p> <pxinput type= "button" value="Fire Click Event on myP" onclick="doFire('myP')" /></p> <p><input type="button" value="Fire Click Event on mySPAN" onclick="doFire ( 'mySPAN') " /x/p> </form> </body> </html> См. также метод dispatchEvent (). focus () Cm. blur (). getAdj acentText ("позиция") ' Возвращаемое значение: строка Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Метод getAdj acentText () позволяет извлечь текстовые компоненты объекта элемента (другими словами, без какой-либо информации о дескрипторах HTML). Единственным его параметром является одна из четырех строковых (с учетом регистра) констант, указывающая откуда пЬ отношению к текущему объекту следует извлекать текст. Значения констант приведены ниже. Значение параметра Описание bef oreBegin Текст от открывающего дескриптора текущего элемента до дескриптора предыдущего элемента af terBegin Текст после открывающего дескриптора элемента до следующего дескриптора (им может быть закрывающий дескриптор данного элемента или открывающий дескриптор вложенного элемента) bef oreEnd Текст от закрывающего дескриптора текущего элемента до предыдущего дескриптора (им может быть? открывающий дескриптор данного элемента или закрывающий дескриптор вложенного элемента) af terEnd Текст от закрывающего дескриптора текущего элемента до дескриптора следующего элемента Шва 15. Основные объекты HTML-элементов 319
Если текущий объект не содержит вложенных элементов, метод с параметром af terBegin или bef oreEnd возвращает то же значение, что и свойство объекта innerText. Если текущий объект вложен непосредственно в другой элемент (например, элемент td внутри элемента tr), перед открывающим дескриптором элемента и после закрывающего дескриптора не будет текста, поэтому вызов метода с такими параметрами возвратит пустую строку. Строки, возвращаемые данным методом, эквивалентны значениям текстовых фрагментов узлов в W3C DOM, однако Ш5+ рассматривает эти блоки данных только как строковые значения, а не текстовые узлы. Не зависящие от браузера DOM-версии данного метода выглядят следующим образом. document.getElementByld("objName").previousSibling.nodeValue document.getElementById("objName").firstChiId.nodeValue document.getElementByld("obj Name").lastChild.nodeValue document.getElementByld("objName").nextSibling.nodeValue Пример Используйте приложение The Evaluator для изучения всех четырех констант, определяющих извлекаемый из элемента туР или туЕт текстовый фрагмент. Поочередно введите в верхнее текстовое поле каждое из следующих выражений. document.getElementByld("myP").getAdjacentText("beforeBegin") document.getElementByld("myP").getAdj acentText("afterBegin") document.getElementByld("myP").getAdj acentText("beforeEnd") document.getElementByld("myP").getAdjacentText("afterEnd") Первый и последний операторы возвращают пустую строку, поскольку элемент myP не окружен текстовыми данными. Константа afterBegin указывает возвратить текстовый фрагмент внутри элемента myP до элемента ту ЕМ (не включая его). Константа bef oreEnd указывает возвратить текстовый фрагмент, начинающийся с конца элемента туЕМ и заканчивающийся правой границей элемента myP. Теперь мы можем узнать, что же возвращается в случае применения элемента туЕМ. document.getElementByld("туЕМ").getAdj acentText("beforeBegin") document.getElementById("туЕМ").getAdjacentText("afterBegin^) document.getElementByld("myEM").getAdj acentText("beforeEnd") document.getElementByld("myEM").getAdj acentText("afterEnd") Поскольку данный элемент не имеет вложенных элементов, то второй и третий варианты возвращают одинаковые результаты. Они совпадают со значением свойства innerText элемента. См. также свойства childNodes, data, first Chi Id, lastChild, nextSibling, node Value и previousSibling. getAttribute ("имяАтрибута" [, ЧувствительностьКРегистру] ) Возвращаемое значение: см. текст Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Метод getAttribute () возвращает значение, присвоенное определенному атрибуту текущего объекта. Этим методом можно воспользоваться как альтернативным вариантом получения свойств объекта, особенно если в сценарии имя атрибута задано в строковом виде (вместо ссылки на объект или его свойства). Поэтому следующие операторы возвращают одинаковые значения. var mult = document.all.mySelect.multiple; var mult = document.all.mySelect.getAttribute("multiple"); 320 Часть III. Объекты дою/mm
%.: Тип значений, возвращаемых методом getAttribute (), является или строковым yimaoHM значения атрибутов, присвоенных как числовые значения без кавычек) или булевым Например, свойство multiple объекта элемента select). Стандарт W3C DOM 2 рекомендует использовать методы getAttribute О и setAttributeO для чтения и записи значений атрибутов объекта элемента вместо применения соответствующих свойств объекта. Использовать эти методы рекомендуется для элементов XML, однако стандарт DOM приводит к некоторому конфликту, определяя все свойства для объектов элементов HTML. Браузеры, конечно же, будут поддерживать доступ к атрибутам с помощью свойств и в будущем, поэтому вы вполне можете пользоваться разными методами доступа. Все браузеры, поддерживающие метод getAttribute (), требуют одного параметра — строки с именем атрибута. По умолчанию он не учитывает регистр. Обратите внимание, что ?П) может повлиять на специальные атрибуты, присвоенные элементам HTML или XML. При присвоении свойствам объекта имена атрибутов автоматически преобразуются к нижнему ре- ; лиггру. Поэтому необходимо избегать повторного использования имен атрибутов, даже если ?:* исходном коде они включают символы разного регистра. Ш позволяет использовать дополнительный параметр, при указании которого в первом аргу- ненте учитывается регистр. По умолчанию он имеет значение false, т.е. в первом параметре ре- гастр не учитывается. Значение true меняет ситуацию. Все это имеет значение лишь тогда, кого для добавления параметра к существующему объекту используется метод setAttribute () и версия Ш этого метода требует учета регистра. По умолчанию метод setAttribute () учитывает регистр в имени атрибута (см. также описание метода setAttribute () далее в этой главе, где рассказывается о влиянии setAttribute () на свойство attributes в IE). Пример Приложение The Evaluator (глава 13) может использоваться для изучения метода getAttri - bute() элементов страницы. В Ш4 применяется синтаксис формата document .all. Браузеры Ш5+ и W3C распознают метод ge t Element By Id () обращения к элементам. Чтобы возвратить значения атрибутов, введите в верхнее поле страницы следующие выражения. .ч D34 document. all .myTable .getAttribute ("width") document.all.myTable.getAttribute("border") IE5+/W3C document. getElementByld ( "myTable") . getAttribute ( "width" ) document.getElementByld("myTable").getAttribute("border") См. также: свойство attributes; методы document. createAttribute (), setAttribute (). getAt tributeNode (" имяАтрибута") Возвращаемое значение: атрибут объекта узла Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- B W3C DOM атрибут является объектом, наследующим все свойства объекта Node (главу 14). Как следует из его названия, объект атрибута представляет собой пару "имя-значение" для атрибута, заданного явно в дескрипторе элемента. Возможность обработки атрибутов как объектов узлов важнее в XML, чем в HTML, но в любом случае она важна для представления узлов атрибутов в контексте объектно-ориентированного взгляда на документы W3C DOM. Обратите внимание, что узлы атрибутов не рассматриваются как узлы в иерархии документа. Поэтому узел атрибута не является дочерним узлом элемента, в котором он определен. Глава 15. Основные объекты HTML-элементов 321
Такое поведение атрибутов учитывается при сравнении содержимого свойства attributes объекта в IE и W3C DOM. В Ш5+ свойство attributes возвращает массив всех атрибутов элемента (даже те, которые не включены в дескриптор явно). В модели W3C свойство attributes возвращает объект, (внутренне) называемый картой именованных узлов. Как и массив, карта именованных узлов имеет свойство length (предназначенное для просмотра карты в цикле), а также несколько методов, позволяющих вставлять, удалять, читать или записывать пары "имя-значение" в карту узлов. Объект атрибута выглядит сложным, в первую очередь, потому что он наследует все свойства объекта Node. В табл. 15.9 приведены свойства объекта атрибута. attributes childNodes firstChild lastChild name nextSibling npdeName nodeType nodeValue ownerDocument parentNode previousSibling specified value Все выше изложенное является объяснением метода getAttributeNode (), который во> вращает объект атрибута в W3C DOM. Его единственным параметром является строка с именем атрибута (без учета регистра). Для получения или установки значений атрибутов можно воспользоваться любым свойством из табл. 15.9. Конечно же, атрибуты HTML являются свойствами элементов HTML, поэтому иногда проще читать или устанавливать их напрямую. Пример В приложении The Evaluator предусмотрены все необходимые инструменты для изучени метода getAttributeNode () в NN6. Текстовая область вывода результатов имеет несколько атрибутов, подлежащих проверке. Поскольку метод возвращает объект, введите в нижнее поле следующие выражения, которые позволяют ознакомиться со свойствами объекта узла атрибута. document.getElementById("output").getAttributeNode("cols") document.getElementById("output").getAttributeNode("rows") document .getElementByldC output").getAttributeNode("wrap") document.getElementBy!d("output").getAttributeNode("style") 322 Часть III. Объекты документ
Все (кроме последнего) выражения выводят список свойств для каждого объекта узла атрибутов. Последнее выражение, тем не менее, ничего не возвращает, поскольку атрибут ; style в элементе не определен. См. также: свойство attributes; методы getAttribute (), removeAt tribute - Node (), setAttributeNode (). getAttributeNodeNS (" ШНпространстваИмен", шлокальноеИмя") Возвращаемое значение: атрибут объекта узла Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari 1+ .> Этот метод возвращает объект атрибута в W3C DOM. Первый параметр метода задает строку URI (Uniform Resource Identifier — универсальный идентификатор ресурса), которая совпадает с URI, назначенным в подписи документа. Второй параметр определяет локальную часть имени получаемого атрибута. См. также: свойства attributes, namespaceURI; методы getAttributeNode О, GetAttributeNodeNS (). getAttributeNS (■ иШпространстваИмен", 9локальноеИмя") Возвращаемое значение: см. описание Совместимость: WinlE-, МасШ-, NN6+, Mozl+, Safari 1+ Этот метод возвращает значение, назначенное определенному атрибуту текущего объекта, если этот атрибут определен в пространстве имен XML документа. Первый параметр метода представляет собой строку URI, которая совпадает с URI, назначенным в подписи пространства имен ранее в документе. Второй параметр определяет локальную часть имени атрибута, 'Значение которого возвращает метод. Возвращаемые значения имеют строковый (в том числе числовые значения, не заключаете в кавычки) или булев тип (например, свойство multiple объекта элемента select). См. также: свойства attributes, namespaceURI, localName; методы getAttribute (), getAttributeNodeNS (), setAttributeNodeNS (). getBoundingClientRect() Возвращаемое значение: объект TextRectangle Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- B Ш5+ каждому элементу, имеющему содержимое, поставлен в соответствие прямоугольник, который указывает, сколько места объект занимает на странице. Этот прямоугольник называется ограничивающим; в объектной модели Winffi5 он является объектом TextRectangle (даже если содержимым является изображение или объект другого типа). Он имеет четыре свойства (top, left, bottom и right)— координаты точек, определяющих прямоугольник. Метод getBoundingClientRect () возвращает объект TextRectangle, отвечающий текущему объекту. Доступ к координатам ограничивающего прямоугольника осуществляется следующим образом. var parTop = document.all.myP.getBoundingClientRect().top; Для элементов, состоящих из текста (например абзацев), размеры объектов TextRectangles отдельных строк текста влияют на размеры результирующего ограничивающего прямоугольника. Например, если абзац содержит две строки, и вторая строка достигает лишь половины ширины Шва 15. Основные объекты HTML-элементов 323
первой, то так же соотносятся и значения объектов TextRectangle этих строк. Ширина результирующего прямоугольника, очевидно, совпадает с шириной объекта TextRectangle большей (первой) строки. Таким образом, ширина ограничивающего прямоугольника равна ширине самой длинной строки, а высота — сумме высот всех объектов TextRectangle в абзаце. Метод getClientRects () позволяет получить построчный набор объектов TextRectangle элемента. Пример В листинге 15.27 приведен пример использования обоих методов: getBoundingClient- Rect () и getClientRects (). Он демонстрирует разницу в использовании этих методов в одном документе. В документе содержится набор элементов, сгруппированных в элементе span, который называется main. Группа состоит из двух абзацев и неупорядоченного списка. Элементы управления страницы позволяют расположить желтый прямоугольник под любым из указанных объектов группы для его выделения. При этом выделяющий прямоугольник может иметь ширину как выделяемого элемента, так и ширину элемента span, содержащего всю группу объектов. Код, выполняющий все необходимые операции, включен в функцию hi lite О , котора! управляет элементом select и флажком. В начале функции с помощью метода getClientRects О элемента main создается массив объектов TextRectangle для всех текстовых строк. Этот массив используется при определении координат углов выделяющего строку (заданную элементом select) желтого прямоугольника. Если пользователь указывает номер выделяемой строки в списке select (и если этот номер меньше общего количества объектов TextRectangle), функция вычисляет размер и расположение выделяющего желтого прямоугольника. При установке на странице единственного флажка левая и правая границы задаются с помощью метода getBoundingClientRectO, поскольку ширина прямоугольника будет равна ширине элемента span. В противном случа# границы задаются свойствами left и right указанного объекта TextRectangle в массиве clientRects. Далее в свойстве style объекта hi liter устанавливается расположение и размер пр* моугольника. Верхняя и нижняя границы зависит от выбранной строки, поэтому используют ся свойства top и bottom соответствующего элемента. Уже упомянутые ранее значена left и right приравниваются к свойствам pixelLeft и pixelRight объекта hiliteE Обратите внимание, что в свойствах top и left учитывается прокрутка страницы в окне браузера. Если уменьшить размер окна браузера, то размер строк и их количество будут меняться (текст перетекает, чтобы не "выходить" за пределы окна). Таким образом, изменяете! и общая нумерация строк. С помощью обработчика события onresize в функции hiliter (* всегда применяется текущий порядок нумерации строк, независимо от их количества. <html> <head> <title>getClientRects() and getBoundClientRectО Methods</title> <script type="text/javascript"> function hiliteO { var hTop, hLeft, hRight, hBottom, hWidth; var select = document.forms[0].choice; var n = parselnt(select.options[select.selectedlndex] .value) - 1; var clientRects = document.getElementByld("main"). 324 Часть III. Объекты локтям
getClientRects 0; var mainElem = document.getElementByld("main"); if (n >= 0 ScSt n < clientRects.length) { if (document.forms[0].fullWidth.checked) { hLeft = mainElem.getBoundingClientRect0 .left; hRight = mainElem.getBoundingClientRectО.right; } else { hLeft = clientRects[n].left; hRight = clientRects[n].right; } document.getElementByld("hiliter").style.pixelTop = clientRects[n].top + document.body.scrollTop; document.getElementByld("hiliter").style.pixelBottom = clientRects[n].bottom; document.getElementByld("hiliter").style.pixelLeft = hLeft + document.body.scrollLeft; document.getElementByld("hiliter").style.pixelWidth = hRight - hl^eft; document.getElementByld("hiliter").style.visibility = "visible"; } else if (n > 0) { alert("The content does not have that many lines."); document.getElementByld("hiliter").style.visibility = "hidden"; } } </script> </head> <body onresize="hilite()"> <hl>getClientRects() and getBoundClientRect() Methods</hl> <hr /> <form> Choose a line to highlight: <select name="choice" onchange= "hiliteO "> <option value="l">l</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <option value="ll">ll</option> <option value="12">12</option> <option value="13">13</option> <option value="14">14</option> <option value=*'15">15</option> </selectxbr /> <input name="fullWidth" type="checkbox" onclick="hilite()" /> Full Width (bounding rectangle) </form> <span id="main"> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco:</p> Г/та 15. Основные объекты HTML-элементов 325
<ul> <li>laboris</li> <li>nisi</li> <li>aliquip ex ea commodo</li> </ul> <p>Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseruntmollit anim id est laborum Et harumd und lookum like Greek to me, dereud facilis est er expedit distinct. </px/span> <div id="hiliter" style="position:absolute; background-color:yellow; z-index:-1; visibility:hidden"> </div> </body> </html> Поскольку свойство z-index стиля для элемента hi liter устанавливается в значение -1, то выделяющий элемент всегда располагается под текстом. Если пользователь выберет номер строки, больший количества строк в окне браузера, то элемент hi liter будет скрыт. См. также: метод getClientRects (); объект TextRectangle (глава 35). getClientRects() Возвращаемое значение: массив объектов TextRectangle Совместимость: WinEE5+, MacIE-, NN-, Moz-, Safari- Метод getClientRects () возвращает массив всех объектов TextRectangle, находящихся внутри текущего объекта в момент вызова метода. Каждый объект TextRectangle имеет свои собственные свойства top, left, bottom и right. Поэтому можно, например, в цикле просмотреть все значения массива и подсчитать ширину каждой строки в пикселях, Если необходимо найти суммарную высоту и/или ширину всего набора, используйте метод getBoundingClientRect(). Пример В листинге 15.27 продемонстрирована разница между методами getBoundingClientRect () и getClientRects(). См. также: метод getBoundingClientRect (); объект TextRectangle (глава 35). getElementsByTagName ("имяДескрилтора") Возвращаемое значение: массив объектов элементов Совместимость: Winffi5+, МасШ5+, NN6+, Mozl+, Safari 1+ Метод getElementsByTagName () возвращает массив всех элементов текущего объекта, дескрипторы которых соответствуют имени, указанному как единственный аргумент этого метода. Аргумент представляет собой строку без учета регистра. Группа элементов, возвращаемая как массив, включает лишь элементы, находящиеся в области определения текущего объекта. Поэтому, если в документе две таблицы и для одной из них выполняется метод getElementsByTagName ("td"), то список элементов ячеек таблицы будет содержать лишь те из них, которые относятся к текущему объекту. Сам текущий элемент в массив не включен. 326 Часть III. Объекты документ
Параметром метода getElementsByTagName () может служить символ " *". Результирующий массив элементов в этом случае совпадает с тем, что Ш4+ возвращает как набор .document, all. Пример Приложение The Evaluator (глава 13) позволяет детально изучить метод getElement - ByTagName (). Введите следующие выражения в верхнее текстовое поле и внимательно изучите полученные результаты. document .body .getElementsByTagName ("div") document.body.getElementsByTagName("div").length document.getElementByld("myTable").getElementsByTagName("td").length Поскольку метод get Element ByTagName () возвращает массив объектов, вы можете использовать возвращаемые значения в качестве корректной ссылки на элемент. document.getElementsByTagName("form")[0].getElementsByTagName ("input").length См. также: методы getElementByld (), getElementByTagNameNS () tags (). getElementsByTagNameNS (" итпространстваИмен", ущлохальноеИмяи) Возвращаемое значение: массив объектов элементов Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Этот метод возвращает массив элементов, который содержится в текущем объекте (в XML-документе), определенном параметрами. Первый параметр метода определяет строку URI (она совпадает с URI, назначенным подписи к документу). Второй параметр задает часть с локальным именем атрибута, значение которого определяется. Этот метод возвращает значения строкового (включая незаключенные в кавычки числовые данные) или булевого типа (например, свойство multiple объекта элемента select). См. также: свойства attributes, namespaceURI, localName; методы getElementByld (),getElementByTagName() tags(). getExpression (" имяАтрибута") Возвращаемое значение: строка Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Метод getExpression () возвращает текст выражения, присвоенного атрибуту элемента методом setExpression (). Возвращаемое значение является не значением выражения, а самим выражением. Если требуется найти значение выражения (предполагая, что все переменные находятся в области определения сценария), необходимо вызвать метод getExpression О внутри функции eval (). Эта операция преобразует строку в выражение JavaScript и возвратит его результат. Метод имеет один аргумент — строку с именем атрибута. Пример В листинге 15.32 приведен пример использования метода setExpressions (). В нем используются значения, возвращаемые методом get Express ions (). См. также: методы document. recalc (), removeExpression (), setExpression (). Глава 15. Основные объекты HTML-элементов 327
hasAttribute (" имяАтрибута") Возвращаемое значение: булевого типа Совместимость: WinlE-, МасГЕ-, NN6+, Mozl+, Safari 1+ Метод hasAttribute () возвращает значение true, если текущий объект имеет атрибут, имя которого совпадает с единственным параметром. В противном случае возвращается значение false. См. также: методы hasAttributeNS (), hasAttribute () hasAttributeNS (" иШпростралстваИмен", ■ локлльяоеИмя") Возвращаемое значение: булевого типа Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safari- Метод hasAttributeNS () возвращает значение true, если текущий объект имеет атрибут, определенный двумя параметрами. В противном случае возвращается значение false. Первый параметр метода определяет строку URI, которая совпадает с URI, назначенным тюдтаси к документу. Второй параметр задает часть с локальным именем атрибута, значение которого определяется. См. также: свойства attributes, namespaceURl, localName; методы hasAttribute О, hasAttributes(). hasAttributes() Возвращаемое значение: булевого типа Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Этот метод возвращает true, если текущий объект имеет атрибуты, полностью определенные в дескрипторе элемента. В противном случае метод возвращает значение false. См. также: методы hasAttributeNS (), hasAttribute (). hasChildNodes() Возвращаемое значение: булевого типа Совместимость: WinlE5+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Метод hasChildNodes () возвращает значение true, если текущий объект имеет вложенные узлы; в ином случае он возвращает значение false. Вложенный узел не всегда является тем же, что и дочерний элемент, поэтому следующие два выражения возвращают true лишь в том случае, когда текущий объект имеет, по крайней мере, один дочерний узел. document.getElementByldC'myObject") .hasChildNodes О document.getElementByld("myObject").childNodes.length > 0 Второе выражение не взаимозаменяемо со следующим оператором (в котором используй ется свойство children, поддерживаемое только в Ш). document.getElementByld("myObject").children.length > 0 Метод hasChildNodes (), как правило, используется в условных выражениях для проверки существования узла перед выполнением операций с ним. if (document.getElementByldC'myObject").hasChildNodesО { операторы, применяемые к узлу } 328 Часть III. Объекты документ
Пример Приложение The Evaluator позволяет детально изучить метод hasChildNodes (). Если :; вы введете в верхнее поле следующее выражение [;■ document.getElementByld ("myP") . hasChildNodes () to будет возвращено значение true. Чтобы определить количество дочерних узлов элемента, ^.достаточно узнать свойство length массива childNodes. document .getElementByld("myP") .childNodes. length Это выражение определяет количество узлов как сумму двух текстовых узлов и элемента em между ними. Проверим, имеет ли первый текстовый узел дочерние узлы. document .getElementByld ("myP").childNodes[0].hasChildNodes() Возвращается значение false, поскольку текстовый узел не имеет вложенных узлов. Теперь выполним то же с элементом em. '.. document .getElementByld ("myP") .childNodes [1] .hasChildNodes () Возвращаемый ответ— true, поскольку в этот элемент вложен текстовый узел. В завершение выполните еще одно выражение. document .getElementByld ("myP") . childNodes [1] . childNodes. length Вы получите результат 1. Непосредственно к элементу em можно также обратиться с помощью следующих ссылок. document.getElementByld("myEM").hasChildNodes() document.getElementByld("myEM").childNodes.length Если вы хотите ознакомиться со свойствами текстового фрагмента, расположенного внутри элемента em, то введите в нижнее поле следующее выражение. document.getElementByldC'myEM").childNodes[0] См. также: свойство childNodes; методы appendChild.(), removeChild (), 1 replaceChildO. insertAdjacentElement ("расположение", объектЭлемента) Возвращаемое значение: объект Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Метод insertAdjacentElement () (не поддерживаемый в Мас1Е5) вставляет объект элемента (полученный из различных источников) в определенном месте по отношению к текущему объекту. Оба аргумента являются обязательными. Первый должен быть одним из четырех возможных параметров (регистр не учитывается), приведенных в таблице. Положение Описание bef oreBegin Перед открывающим дескриптором текущего элемента а£terBegin После открывающего дескриптора перед любым вложенным содержимым bef oreEnd Перед закрывающим дескриптором после любого вложенного содержимого afterEnd После закрывающего дескриптора Положение рассматривается относительно текущего объекта. Тип текущего элемента (блоковый или внутритекстовый) во многом влияет на отображение на экране вставляемого Глава 15. Основные объекты HTML-элементов 329
элемента. Предположим, что создается элемент b (с использованием метода document. createElement ()), которому присваивается некоторый текст. С помощью метода insert- Ad jacent Element () элемент b вставляется перед элементом р. Так как элемент р является блоковым, аргумент bef oreBegin размещает элемент b перед открывающим дескриптором элемента р. Это значит, что полужирный текст появится в строке текста над элементом р, так как дескриптор <р> начинает новый блок, выравниваемый по левому краю (если в стилях не указано иначе). В результате HTML-код будет иметь такой вид. <Ь>Новый элемент . </Ьхр>Исходный элемент. </р> Чтобы сделать элемент b частью р и вставить его перед существующим содержимым, используйте параметр af terBegin. В результате вы получите следующий HTML-код. <р><Ь>Новый элемент.</Ь>Исходный элемент.</р> Результат использования параметра bef oreEnd будет таким <р>Исходный элемент. <Ь>Новый элемент . </Ьх/р> a af terEnd — следующим <р>Исходный элемент.</р><Ь>Новый элемент.</Ь> Вставляемый объект представлен ссылкой на объект элемента. Ее можно получить с помощью любого оператора, который возвращает ссылку на объект, или, скорее всего, в результате выполнения метода document. createElement (). Помните, что объект, созданный методом document. createElement (), изначально является пустым, а все атрибуты имекя значения по умолчанию. Более того, объект передается методу insert Ad jacent Element!) по ссылке, т.е. существует всего одна копия объекта. При попытке вставить объект в двух местах (двумя операторами) он будет просто перемещен с первой позиции во вторую. EcjS необходимо скопировать объект, ничего не изменяя в исходном положении, следует воспой- зоваться методом cloneNodeO, указав аргумент true (тем самым вы скопируете всю внутреннюю структуру узла). Пример Приложение The Evaluator поможет вам разобраться и с использованием метода insert- Adj acentElement (). Вы должны научиться вставлять новый элемент hi над элементом туР. От вас потребуется всего лишь ввести несколько операторов в верхнее текстовое поле. Начните с сохранения нового элемента в глобальной переменной а. а = document.createElement("hi") Далее введите в новый объект текст. a.innerText = "New Header" Вставьте этот элемент непосредственно перед объектом туР. туР.insertAdjacentElement("beforeBegin", a) Обратите внимание, что новому элементу не было назначено свойство id. Посколыу элемент вставлялся по ссылке, вы можете изменить его, воспользовавшись переменной &. и сохраненным в нем объектом. a.style.color = "red" Вставленный элемент становится частью иерархической структуры документа, поэтому к нему можно обратиться с помощью оператора myP .previousSibling. Родительским для нового вставленного объекта является элемент body. Вы можете изучить текущее состояние HTML-кода отображенной страницы, введя в верхнее поле следующее выражение. document.body.innerHTML 330 Часть III. Объекты докшюит
Если вы прокрутите страницу ниже первой формы, то сможете увидеть элемент hi, вставленный в документ с атрибутом style. См. также: методы document. createElement (), applyElement (). insertAd j acentHTML ("расположение", щтекстНТМЬ") insertAd j acentText ("расположение", " текст") Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Два этих метода вставляют код HTML или просто текст в текущий элемент. Они используются после, а не во время загрузки страницы (в последнем случае следует применить метод document. write ()). Первый параметр должен быть одним из четырех возможных аргументов (регистр не учитывается), приведенных в таблице. Положение Описание bef oreBegin Перед открывающим дескриптором текущего элемента af terBegin После открывающего дескриптора перед любым вложенным содержимым bef oreEnd Перед закрывающим дескриптором после любого вложенного содержимого I afterEnd После закрывающего дескриптора Приведенные параметры дают те же результаты, что и для метода insertAdjacent- Element (), о котором было рассказано выше. Применение метода insertAd j acentHTML () или insertAd j acentText () зависит от природы содержимого, а также от выполняемых браузером задач. Если элемент содержит дескрипторы HTML, которые должны интерпретироваться и отображаться браузером как часть исходного кода страницы, воспользуйтесь методом insertAd j acentHTML (). В этом случае все дескрипторы станут членами объектной модели документа. Если же требуется просто отобразить текст (включая и дескрипторы HTML в неинтерпретированном виде), используйте метод insertAd j acentText (). В результате обычного отображения дескрипторы, включенные в строку (она передается во втором аргументе), не интерпретируются. Все дескрипторы отображаются как обычные символы на странице. Такое различие напоминает разницу между свойствами innerHTML и innerText. Отличие метода insertAd j acentHTML () от insertAd jacentElement () связано с природой вставляемого содержимого. Первый позволяет вставить строку как HTML-код, последний требует создания объекта элемента. Оба метода работают в Ш4+ (включая версии для Мае), тогда как insertAdj acentElement () требует новой объектной модели IE5 и выше. Если HTML-код, передаваемый как второй параметр insertAdj acentHTML (), содержит дескрипторы <script>, необходимо установить атрибут defer в открывающем дескрипторе. Таким образом, запуск операторов сценария непосредственно после вставки в документ будет невозможен. Пример Приложение The Evaluator (глава 13) применяется для изучения этих двух методов. Чтобы на реальном примере ознакомиться с результатом выполнения этих методов, перед элементом туР вставим HTML-код. Глава 15. Основные объекты HTML-элементов 331
Вначале назначьте глобальной переменной а следующий HTML-код. а = "<b id='myB'>Important News!</b>" Поскольку этот HTML-код вводится в той же строке, что и код начала элемента туР, то в методе вставки используйте параметр af terBegin. myP.insertAdjacentHTML("afterBegin", а) Обратите внимание, что после восклицательного знака в HTML-коде пробел отсутствует. Чтобы доказать принадлежность вставленного HTML-элемента объектной модели документа, добавьте пробел после элемента b с идентификатором myB. myB.insertAdjacentText("afterEnd", " ") Каждый раз при выполнении этого выражения (повторного щелчка на кнопке Evaluate или нажатия <Enter>) на страницу добавляется новый пробел. Далее мы разберемся, что же происходит при вставке с помощью метода insert Ad j acent- Text () строки, содержащей HTML-код. Перезагрузите приложение The Evaluator и введите следующие два выражения в верхнее поле, выполнив их совместно. а = "<b id='myB'>Important Newsl</b>" myP.insertAdjacentText("afterBegin", a) Как видно, HTML-код не вставляется, хотя и отображается в виде простого текста. После выполнения последнего метода вы не найдете в документе элемента myB. См. также: свойства innerText, innerHTML, outerText, outerHTML; методы insertAdj acentElement (), replaceAdj acentText (). insertBefore{новийОбъектДочернегоУзла[, ссылкаНаДочернийУзел]) Возвращаемое значение: объект Node Совместимость: WinIE5+, Macffi5+, NN6+, Mozl+, Safari 1+ Метод insertBef ore () относится к синтаксису W3C DOM, используемому для вставке дочернего узла в существующий элемент. Ссылки на узлы в обоих аргументах должны бьпъ объектами Node (включая и генерируемые методом document. createElement ()). Поведение метода может показаться неочевидным. Если указать второй параметр (ссылку ш существующий дочерний узел текущего элемента), то новый дочерний узел будет вставлен п* ред существующим. Если опустить второй параметр (или указать null), новый дочерний узел будет вставлен как последний в текущем элементе — в этой ситуации данный метод совпадает по действию с методом appendChild (). Преимущества метода проявляются, очевидно, при указании второго аргумента — новый дочерний узел можно вставить в любом месте внутри элемента. Помните, что метод insertBef ore () выполняется с точки зрения родительского объекта. Internet Explorer содержит несколько дополнительных методов, например insertAdj acentElement (), в которых указывается дочерний элемент. Пример В листинге 15.28 продемонстрирована операция вставки дочерних элементов (li) в родительский элемент (ol) с помощью метода insertBef ore (). При этом элементы вставад- ются в разные части документа (в зависимости от значения второго параметра). В текстовое- поле указывается текст или HTML-код, добавляемый в документ. Если не указать в следующем списке расположение вставляемого элемента, то второй параметр метода примет значение null. В последнем случае элемент добавляется после остальных дочерних элементе!. В списке select указывается порядковый номер одного из дочерних элементов объекта ol. 332 Часть III. Объекты документа
<html > <head> <title>insertBefore() Method</title> <script type="text/javascript"> function dolnsert(form) { if (form.newText) { var newChild = document.createElement("LI"); newChild.innerHTML = form.newText.value; var choice = form.itemlndex.options[form. itemlndex.selectedlndex].value; var insertPoint = (isNaN(choice)) ? null : document.getElementByld("myUL"). childNodes[choice]; document.getElementByld("myUL").insertBefore(newChild, insertPoint); </script> ' </head> , <body> <hl>insertBefore() Method</hl> <hr /> <form onsubmit="return false"> <p>Enter text or HTML for a new list item: <input type="text" name="newText" size=n40" value="" /></p> <p>Before which existing item? <select name="itemlndex"> <option value="null">None specified</option> <option value="0">l</option> <option value="1">2</option> <option value="2">3</option> </selectx/p> <input type="button" value="Insert Item" onclick="dolnsert(this.form)" /> </form> <ol id="myUL"> <li>Originally the First Item</li> <li>Originally the Second Item</li> <li>Originally the Third Item</li> </ol> </body> </html> См. также: методы appendChild (), replace Chi Id (), remove Chi Id (), insert- Adjacent Element (). isSupported (" спецификация™, " версия") Возвращаемое значение: булевого типа Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Метод is Supported () определяет, поддерживается ли текущий узел в указанной спецификации и версии W3C DOM. Если нет, то возвращается значение false. Первый пара* метр принимает имена следующих модулей (имена чувствительны к регистру символов): Core, XML, HTML, Views, Stylesheets, CSS, CSS2, Events, UIEvents, MouseEvents, MutationEvents, HTMLEvents, Range, Traversal. Второй параметр задает версию модуля в строковом формате, например "2.0". Глава 15. Основные объекты HTML-элементов 333
Пример Приложение The Evaluator может использоваться для выполнения метода isSupported (). Если в вашем компьютере установлено несколько браузеров NN или Mozilla, то попробуйте выполнить в них (на странице приложения) следующие выражения (а также многие другие). document.body.isSupported("CSS", "2.0") document.body.isSupported("CSS2", "2.0") document.body.i sSupported("Traversal", "2.0") Если у вас установлен браузер Safari, то обязательно выполните эти же выражения и в нем, чтобы увидеть разницу в поддерживаемых технологиях. i tem(index | "индекс" [, подиндекс]) Возвращаемое значение: объект Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Метод item () работает с такими объектами, которые представляют собой наборы (массивы) других объектов. В контексте W3C DOM такие объекты называются списками именованных узлов (узлы и атрибуты) или HTML-наборами (HTML-массивами) (элементы формы). В W3C DOM метод item() определен с одним числовым параметром — индексом объекта в массиве. В NN6 этот метод реализован именно так. Если известен индекс элемента в массиве, то можно обратиться к массиву непосредственно с помощью JavaScript. Два следующих оператора указывают на один и тот же объект. document.getElementByld("myTable").childNodes.item(2) document. getElementByld ("myTable").childNodes[2] Возможности метода расширены строковым идентификатором объекта в наборе. (Однако для доступа к объектам attributes, rules и TextRectangle требуются все же целочисленные значения.) Кроме того, если в набор входит несколько объектов с одним идентификатором (их стоит использовать лишь в случае необходимости), второй числовой параметр позволит выбрать конкретный объект из группы (в подгруппе индекс начинается с нуля). Очевидно, что это неприменимо к таким наборам, как attributes и rules, поскольку им не присваивается идентификатор. Метод возвращает ссылку на объект, заданный аргументами метода. Пример Приложение The Evaluator (глава 13) используется также для анализа метода item(). Введите в верхнее текстовое поле следующие выражения. В W3C и Ш5: document.getElementByld("myP").childNodes.length document.getElementByld("myP"J.childNodes.item(0).data document.getElementByld("myP").childNodes.item(1).nodeName В\УЗС,ГЕ4иГЕ5: document.forms[1].elements.item(0).type В IE4 и 1Е5: document.all.item("myP").outerHTML myP.outerHTML В последних двух примерах оба оператора возвращают одну и ту же строку. Первый пример применяется при управлении в сценарии строковым вариантом имени объекта. Если в сценарии известна ссылка на объект, то второй подход более эффективен. См. также: все свойства объектов элементов, которые возвращают наборы (массивы) других объектов. 334 Часть III. Объекты документ!
mergeAttributes ("исходныйОбъект") Возвращаемое значение: отсутствует Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Метод mergeAttributes () представляет собой удобный способ присвоения атрибутов новосозданным объектам (вместо их добавления по одному). Если в наличии есть объект, атрибуты которого могут послужить прототипом для других элементов (кроме атрибута id), эти атрибуты можно присвоить новосозданному объекту. Пример В листинге 15.29 продемонстрировано использование метода mergeAttributes () в процессе репликации текстового поля формы. Каждой новой копии текстового поля при этом назначается собственный идентификатор. Функция doMerge () начинает свою работу с создания двух новых элементов: р и input. Поскольку новые элементы еще не имеют свойств, то элементу input назначается уникальный идентификатор с помощью идентификатора unique ID. Далее атрибуты исходного поля из HTML-кода передаются в новый элемент input. Таким образом в созданный элемент копируются все атрибуты, за исключением name и id. После этого элемент input вставляется в элемент р, который, в свою очередь, присоединяется к элементу формы. Наконец, в новом поле отображается значение свойства outerHTML копии элемента. Удостоверьтесь, что в элемент скопированы все атрибуты, за исключением name и id (в том числе атрибуты стилей и обработчики событий). Чтобы проверить работоспособность обработчиков событий в новом элементе, добавьте в него пробел и нажмите <ТаЬ> для вызова обработчика onchange, изменяющего регистр символов. <html> <head> <title>mergeAttributes() Method</title> <script type="text/javascript"> function doMerge(form) { var newPElem = document.createElement("p"); var newInputElem = document.createElement("input"); newInputElem.id = newInputElem.uniquelD; newInputElem.mergeAttributes(form.fieldl); newPElem.appendChiId(newInputElem); form.appendChiId(newPElem); newInputElem.value = newInputElem.outerHTML; } // вызывается обработчиком onchange полей function upperMe(field) { field.value = field.value.toUpperCase(); } </script> </head> <body onload="document.expandable.fieldl.value = document.expandable.fieldl.outerHTML"> <hl>mergeAttributes() Method</hl> <hr /> Глава 15. Основные объекты HTML-элементов 335
<form name= "expandable" onsubmit="return false"> <pxinput type="button" value="Append Field 'Clone'" onclick="doMerge(this.form)" /></p> <pxinput type="text" name="fieldl" id="FIELDl" size="1.20" value="" style="font-size:9pt" onchange="upperMe(this)" /></p> </form> </body> </html> См. также: методы clearAttributes (), cloneNode (), removeAttributes (). normalize() Возвращаемое значение: отсутствует Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari- В случае добавления, вставки, удаления и замещения дочернего узла элемента вполне возможно, что два текстовых узла станут соседними. Зачастую это не влияет на графическое представление содержимого, однако некоторые XML-приложения имеют жесткие ограничь ния на расположение узлов в иерархической структуре документа, в соответствии с которым* два текстовых узла соседними быть не могут. "Правильная" иерархическая структура узжя предполагает, что текстовый узел окружен узлами других типов. Метод normalize () просматривает дочерние узлы текущего объекта и комбинирует соседние текстовые узлы в один. Это влияет на общее количество дочерних узлов элемента, а также изменяет иерархически* отношения вложенных узлов. Пример Используйте приложение The Evaluator для изучения метода normalize () в Mozilb совместимых браузерах. В следующей последовательности действий показано, каким образом можно добавить текстовый узел, соседний с уже имеющимся в элементе туР. С помо* щью метода normalize О в приведенном примере удаляется граница между соседним* текстовыми узлами. / Для начала определите количество дочерних узлов элемента туР. document.getElementByld("туР").childNodes.length Как видите, исходно в этом элементе присутствует три дочерних узла. Далее создайте тек* стовый узел и присоедините его\ к элементу myP после последнего дочернего узла а = document.createTextNode("This means you!") document.getElementByld("myP").appendChild(a) Теперь количество дочерних узлов элемента myP увеличится до четырех, document.getElementByld("myP").childNodes.length Легко можно удостовериться, что последний текстовый узел — именно тот, который вы создали ранее. document.getElementByld("myP").lastChild.nodeValue После выполнения метода normalize () элемента myP все соседние текстовые узлы будут объединены в один большой текстовый узел. document .getEl ementBy Id ("myP") .normalize () Теперь элемент myP (как и раньше) состоит из трех текстовых узлов, хотя последний И- них содержит исходный текст, а также текст добавленного ранее на страницу узла 336 Часть III. Объекты докшяа
document.getElementById("myP").childNodes.length document.getElementByld(HmyP").lastChild.nodeValue См. также: методы document. createTextNode (), appendChild (), insertBef ore (), removeChild (), rep lace Chi Id (). releaseCapture() setCapture (булевКонтейиер) Возвращаемое значение: отсутствует Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- C помощью метода setCapture () можно указать объект, который будет перехватывать все события мыши (onmousedown, onmouseup, onmousemove, onmouseout, onmouseover, onclick и ondblclick). В IE перехват событий мыши, обычно, применяется в следующей ситуации: на странице появляется некоторый элемент, который является генератором действия пользователя (например, раскрывающиеся, контекстные меню или активные области). После отображения такого элемента на экране необходимо будет блокировать все события мыши, кроме тех, которые относятся к текущему объекту. Когда этот элемент исчезнет с экрана, события мыши освободятся: т.е. остальные объекты (кнопки или ссылки на странице) вновь будут откликаться на них. Захват не блокирует события — они лишь перенаправляются к указанному объекту. События возникают, если только они не отменены явно (см. главу 25). Предположим, что дескриптор <body> содержит обработчик события onclick, управляющий всем документом. Если включить захват событий элементом div, содержащимся в документе, то все события вначале будут перенаправляться последнему. Элемент div может иметь обработчик события onclick, выполняющий действия в том случае, когда события относятся к какому-либо из его дочерних элементов. Если в обработчике событий элемента div не отменен переход события вверх по структуре, то обработчик события onclick элемента body также обработает его, хотя изначально оно получено (захвачено) элементом div. Определение того, какой объект должен захватывать события, является серьезным вопросом в разработке документа. При захвате все события мыши (независимо от того, где они происходят) перенаправляются указанному объекту. Поэтому при разработке приложения, интерфейс которого предполагает щелчок на объектах и перетаскивание позиционируемых элементов, обязательно укажите, какой из элементов (или даже объект document) должен производить захват событий. Для всплывающих областей логично и более удобно при программировании назначить механизм захвата событий элементу, содержащему всплывающее содержимое (как правило, позиционируемый элемент div). Метод setCapture () имеет дополнительный аргумент логического типа. Он управляет тем, подчиняются ли события дочерних элементов захватывающего объекта описанному механизму захвата. Значение по умолчанию (true) означает, что все события мыши, определенные для дочерних элементов текущего объекта, направляются последнему, а не в исходную точку назначения (так, метод setCapture () чаще всего используется для всплывающих и контекстных меню). Параметр false соответствует ситуации, когда дочерние элементы обрабатывают события самостоятельно. Затем происходит обычное перемещение событий вверх по структуре (см. главу 25). Поведение метода может стать непредсказуемым, если элемент, перехватывающий события, содержит элементы форм (например, текстовые поля или списки). Этим элементам события требуются для активизации и дальнейшего взаимодействия со сценарием, а механизм захвата событий предотвращает возможность доступа к ним. Чтобы обойти такое поведение, следует проверить свойство srcElement. В случае, если щелчок выполнен на одном из таких элементов, активизируйте его (или же проинформируйте пользователя о необходимости перехода к нужному элементу с помощью клавиши <ТаЬ>). Глава 15. Основные объекты HTML-элементов 337
После указания перехватывающего события объекта, необходимо определить, какие события будут обрабатываться, а также будут ли они перемещаться вверх по иерархической структуре. О всплывании необходимо беспокоиться лишь в том случае, если обработчики событий находятся в элементах-контейнерах, расположенных выше в структуре. Если после захвата события не требуется, чтобы запускался вышерасположенный обработчик, всплывание для него следует отменить. Если дизайн страницы требует, чтобы всплывающий на экране элемент скрывался, а обработка событий вновь приобретала привычный характер (например после того, как пользователь сделает выбор во всплывающем меню), необходимо воспользоваться методом re lease Capture (). Так как захват событий возможен лишь для одного элемента, отмените его, запустив метод releaseCapture () для элемента-контейнера или объекта document. Захват событий автоматически отменяется, когда пользователь производит одно из следующих действий. ■ Активизирует другое окно. ■ Выводит системное диалоговое окно (например, предупреждение). ■ Прокручивает страницу. ■ Открывает контекстное меню браузера (щелчком правой кнопкой мыши). ■ Активизирует строку адреса браузера или нажимает клавишу <ТаЬ>. С помощью обработчика события onlosecapture объекта document можно "скрыть" элемент-контейнер, отображаемый при обработке события. Помните, что для предотвращения доступа к элементам страницы возможен захват событий мыши, но не клавиатуры! Поэтому механизм захвата событий, используемый для эмуляции окон или элементов меню и предотвращающий доступ к остальной части страницы, не является самодостаточным — пользователь может перейти к любому элементу формы или ссылке после нажатия клавиши <ТаЬ>, а затем активизировать элемент нажатием клавиши пробела или <Enter>. Захват событий в W3C DOM отличается от механизма, поддерживаемого в Ш. В W3C DOM браузер имеет возможность заменить захват события любого типа на обычное всплывание события в иерархической структуре. Например, приемник события может помещаться в дескрипторе body и проверять все события, относящиеся к элементам body, до их поступления к соответствующим элементам. (Подробнее о модели обработки событий в W3C DOM и том, как создать приложения, выполняемые в разных браузерах, речь идет в главах 14 и 25.) Пример В листинге 15.30 продемонстрированы особенности использования методов setCapturef) и releaseCapture () при создании контекстного меню в IE5+. Назначение этого контекстного меню весьма простое— определить способ нумерации списка упорядоченных элементов страницы. Как только пользователь щелкнет на элементе ol правой кнопкой мыши, на экране появится контекстное меню. Захват событий происходит таким образом, что щелчок за пределами контекстного меню не вызывает никаких действий. При этом само контекстное меню скрывается. При выборе одного из вариантов контекстного меню изменяется значение свойства listStyleType объекта ol. Как только контекстное меню скрывается с экрана, захват событий отключается — любой щелчок на странице обрабатывается стандартным образом. В рассматриваемом примере используются обработчики событий onclick, onmouseover и onmouseout элемента div, который содержит контекстное меню. Чтобы отобразить контекстное меню, на экране задействуется обработчик события oncontextmenu элемента ol. Все действия в этом обработчике событий выполняет функция showContextMenu (). Данная функция указывает захватывать события для объекта div. Более того, элемент div' располагается в месте щелчка еще до отображения на экране. Чтобы предотвратить появление на 338 Часть III. Объекты документа
экране стандартного контекстного меню, свойство returnValue объекта event устанавливается в значение false. Как мы выяснили ранее, все события мыши теперь происходят в объекте div. Посмотрим, что же происходит при использовании мыши. В результате перемещения указателя мыши возникают события mouseover и mouseout, которыми управляют обработчики, назначенные объекту div. Обратите внимание, что два обработчика событий— highlight () и unhighlight () — выполняются только тогда, когда свойство srcElement объекта event приравнивается к одному из элементов объекта div. Поскольку на странице не обрабатываются события onmouseover или onmouseout других элементов, даже расположенные на более высоких уровнях иерархической структуры, то всплывание событий для них не отменяют. Когда пользователь нажимает кнопку мыши, выполняются самые разные действия, связанные с включением или отключением захвата событий в сценарии. При отключении захвата событие click всплывает от места возникновения к обработчику событий onclick элемента body (на экране отображается сообщение, когда событие достигает элемента body). При включении захвата событий (отображение контекстного меню на экране) обработчик события handledick () применяет выбранный тип нумерации. Для всех событий щелчка, обрабатываемых этой функцией, контекстное меню скрывается, а всплывания событий не происходит (предупреждающее сообщение не отображается). Подобное происходит, когда пользователь выбирает элемент меню или щелкает в другом месте страницы. В последнем случае контекстное меню должно скрываться, за что и отвечает обработчик событий onlosecapture. <html> <head> <titlex/title> <style type="text/css"> #contextMenu {position:absolute; background-color:#cfcfcf; border-style:solid; border-width:lpx; border-color:#EFEFEF #505050 #505050 #EFEFEF; padding:3px lOpx; font-size:8pt; font-family:Arial, Helvetica; line-height:150%; visibility:hidden} .menultem {color:black} .menuItemOn {color:white} ol (list-style-position:inside; font-weight:bold; cursor:hand} li {font-weight:normal} </style> <script type="text/javascript"> function showContextMenu() { contextMenu.setCapture(); contextMenu.style.pixelTop = event.clientY + document.body.scrollTop; contextMenu.style.pixelLeft = event.clientX + document.body.scrollLeft; contextMenu.style.visibility = "visible"; event.returnValue = false; } function revert() { document.releaseCapture{); hideMenu(); } function hideMenu() { Глава 15. Основные объекты HTML-элементов 339
contextMenu.style.visibility = "hidden"; } function handleClickO { var elem = window.event.srcElement; if (elem.id.indexOf("menultem") == 0) { document.getElementByld("shapesList").style. listStyleType = elem.listtype; } revert(); event.cancelBubble = true; } function highlight() { var elem = event.srcElement; if (elem.className == "menultem") { elem.className = "menuItemOn"; function unhighlight() { var elem = event.srcElement if (elem.className == "menuItemOn") { elem.className = "menultem"; </script> </head> <body onclick="alert('You reached the document object.')"> <ol id="shapesList" oncontextmenu="showContextMenu()"> <li style="list-style: none"xa href=" javascript: alert('A%20sample%201ink.')">Three-Dimensional Shapes</a></li> <li value="l">Circular Cylinder</li> <li>Cube</li> <li>Rectangular Prism</li> <li>Regular Right Pyramid</li> <li>Right Circular Cone</li> <li>Sphere</li> </ol> <div id="contextMenu" onlosecapture="hideMenu()" onelick="handledick()" onmouseover="highlight()" onmouseout="unhighlight()"> <span id="menulteml" class="menultem" listtype="upper-alpha">A,B,C, . . .</spanxbr /> <span id="menultem2" class="menultem" listtype="lower-alpha">a,b,c, . . .</spanxbr /> <span id="menultem3" class="menultem" listtype= "upper-roman'^I, II, III, . . . </spanxbr /> <span id=MmenuItem4" class="menultem" listtype="lower-roman">i, ii, iii, . . .</spanxbr /> <span id="menultem5" class="menultem" listtype="decimal">1,2,3,...</span> </div> </body> </html> См. также: методы addEventListener О , dispatchEvent (), fireEventO, removeEvent Listener (); событие onlosecapture; объект Event (глава 25). 340 Часть III. Объекты документа
remove At tribute (" имяАтрибута" [, чувствителъностьКРегистру]) Возвращаемое значение: булевого типа (Ш); отсутствует (NN) Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Атрибут, созданный с помощью метода set At tribute (), можно удалить методом removeAttribute (). Обязательным параметром является имя атрибута. Ш4+ позволяет устанавливать и удалять атрибуты, в именах которых учитывается регистр. По умолчанию в методе removeAttribute () в IE второй аргумент (булевого типа) имеет значение false. Если при вызове метода setAttribute () параметр имел значение true, метод removeAttribute () должен вызываться таким же образом. В W3C DOM (NN/Moz/Safari) метод removeAttribute () имеет только один параметр (имя атрибута без учета регистра) и не возвращает никакого значения. В IE метод возвращает true, если процесс удаления завершился успешно, и false — в ином случае (в том числе, если атрибут был установлен другим способом). Пример Приложение The Evaluator (глава 13) позволяет изучить метод removeAttribute () для элементов страницы (просмотрите примеры для метода setAttribute () далее в этой главе и введите соответствующие операторы removeAttribute () в верхнее поле). С помощью метода get At tribute () проверьте наличие или отсутствие каждого атрибута. См. также: свойство attributes; методы document .createAttribute (), getAttribute() иsetAttribute(). removeAttributeNode (узелАтрибута) setAttributeNode (узелАтрибута) Возвращаемое значение: объект Attribute Совместимость: Winffi6+, MacIE-, NN6+, Mozl+, Safari 1+ Как отмечалось при описании метода getAttributeNode () ранее в этой главе, в W3C DOM пара "имя-значение" является объектом атрибута. Объект атрибута представляет собой отдельный узел в карте именованных узлов — наборе объектов атрибутов, принадлежащих элементу. Карта именованных узлов и объектов атрибутов часто используется в среде XML, где атрибуты могут не только содержать ценные данные, но и не рассматриваются в объектной модели документа как свойства, к которым возможен доступ из сценария. Вместо обращения к свойствам объекта в XML-сценарии возможен доступ только к реальными объектам атрибутов. Если вам требуется вставить атрибут согласно формальной спецификации W3C, то воспользуйтесь методом document. createAttribute (), генерирующим новый объект атрибута. Затем в последующих операторах сценария присвойте значения свойствам nodeName и node Value, указав, таким образом, атрибуту пару "имя-значение". После этого с помощью метода setAttributeNode () новый объект атрибута можно будет добавить в список атрибутов текущего объекта. Единственным параметром метода является объект атрибута, а возвращаемым значением — новый, вставленный в документ, объект. Метод removeAttributeNode () позволяет выполнить обратное действие— удалить атрибут элемента, используя тот же синтаксис. И вновь его единственным параметром является объект атрибута. Если в сценарии известно только имя атрибута, для получения корректной ссылки на объект необходимо воспользоваться методом getAttributeNode (). Метод removeAttributeNode () возвращает ссылку на удаленный объект атрибута. Этот Глава 15. Основные объекты HTML-элементов 341
объект остается в памяти браузера, но перестает быть частью иерархической структуры документа. Такой подход позволяет присвоить удаленный объект атрибута переменной, изменить его, а затем присвоить любому другому объекту документа. На практике работать с атрибутами как с узлами приходится крайне редко. Методы getAt tribute (), removeAt tribute () и set At tribute () выполняют те же операции, когда известно только имя атрибута (в строковом представлении текущего элемента). Пример Приложение The Evaluator (глава 13) также используется для изучения методов setAttributeNade () и removeAttributeNode () элемента р страницы. Ваша задача — создать и добавить атрибут style в элемент р. Начните с создания нового атрибута и сохранения его во временной глобальной переменной а. а = document.createAttribute("style") Далее назначьте значение объекту attribute. a.nodeValue = "color:red" Вставьте новый атрибут в элемент р. document.getElementByld("myP").setAttributeNode(a) Абзац с текстом изменит свой цвет в соответствии с новым добавленным атрибутом. Несмотря на то, что в NN6 этот метод не возвращает ссылку на новый добавленный узел атрибута, вы можете получить ее косвенно. b = document.getElementByld("myP").getAttributeNode("style") Наконец, используйте ссылку на новый добавленный атрибут, чтобы удалить его из иерархической структуры. document.getElementByld("myP").removeAttribute(b) После удаления атрибута абзац примет свой исходный цвет (см. пример использования метода set At tribute О далее в этой главе, чтобы узнать, как выполнить те же действия с помощью метода setAttribute ()). См. также: свойство attributes; методы document .createAttributeО, getAttribute(), getAttributeNode(), setAttribute(). removeAt tributeNS (" итпространстваИмен", "локальноеИмя") Возвращаемое значение: ничего Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Этот метод удаляет атрибут, определенный двумя параметрами. Первый параметр метода определяет строку URI, которая совпадает с URI, назначенного подписи к документу. Второй параметр задает часть с локальным именем атрибута, значение которого определяется. См. также: свойства attributes, namespaceURI, localName; методы remove- Attribute (),getAttributeNS() и setAttributeNS(). removeBehavior(идентификатор) Возвращаемое значение: булевоготипа Совместимость: Winffi5+, МасГЕ-, NN-, Moz-, Safari- Метод removeBehavior () отсоединяет поведение от объекта. Подразумевается, что оно добавлено методом addBehavior (). Значение, возвращаемое методом addBehaviorO, представляет собой уникальный идентификатор поведения. Этот идентификатор является обяза- 342 Часть ///. Объекты документв
тельным аргументом метода removeBehavior (). Таким образом, объекту, например, можно присвоить два поведения, а затем удалить только одно из них. Если процесс удаления завершается успешно, метод removeBehavior () возвращает true; в ином случае — false. Пример Обратитесь к листингам 15.19а и 15.196 (ранее в этой главе), чтобы детальнее ознакомиться с методами addBehavior () и removeBehavior (). См. также: метод addBehavior (). removeChiId(объехтУзла) Возвращаемое значение: ссылка на объект Node Совместимость: Winffi5+, Macffi5+, NN6+, Mozl+, Safari 1+ Метод removeChi Id () удаляет дочерний элемент текущего узла. Содержимое дочернего элемента не отображается на странице, а сам объект перестает быть частью иерархической структуры. Тем не менее, объект не удаляется полностью. Метод removeChi Id () возвращает ссылку на удаленный узел. Присвойте его переменной, и объект можно будет сохранить для последующей вставки. Переменной можно воспользоваться как аргументом следующих методов: appendChild(), replaceChild(), swapNode() и insertBefore(). Помните, что метод remove Chi Id () вызывается относительно родительского элемента. Если требуется просто удалить элемент, это можно сделать напрямую (в IE5+) с помощью метода removeNode (). Пример Пример использования метода removeChi Id () приведен в листинге 15.21 ранее в этой главе. См. также: методы appendChild (), replaceChild (), removeNode (). removeEventListener() См. addEventListener(). removeExpression(■'имяСвойства") Возвращаемое значение: булевоготипа Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Если свойству объекта (включая объект style) значение присваивается с помощью метода setExpression (), удалить его можно методом removeExpression (). Его единственным параметром является строка с именем свойства (с учетом регистра). В случае успешного удаления метод возвращает значение true, и false — в ином случае. Помните, что удаление выражения не изменяет значения, присвоенного свойству. Другими словами, методом setExpressionO можно установить значение свойства, а затем удалить выражение, чтобы далее (когда документ пересчитает выражения) не последовало никаких изменений. Если вы преследуете именно такую цель, то проще задать свойство путем присвоения значения в сценарии. Пример Вы можете смело экспериментировать со всеми тремя методами в приложении The Evaluator (глава 13). Следующая последовательность действий позволяет добавить выражение в свойство style элемента туР страницы, а затем удалить его. Глава 15. Основные объекты HTML-элементов 343
Для начала введите в нижнее текстовое поле значение 24 (но не нажимайте <Enter> и не щелкайте на кнопке List Properties). Тем самым вы ограничите свойство font Size объекта my Р. Далее назначьте объекту style объекта туР выражение, введя в верхнее поле следующий оператор. myP.style.setExpression("fontSize","document.forms[0].inspector. value","JScript") Теперь вы можете вводить в нижнее текстовое поле различные размеры шрифта; при этом изменения немедленно вступят в силу. (События клавиатуры указывают на обновление форматирования.) По умолчанию размер шрифта отображается в пунктах (рх), хотя при желании можно добавить к числовому значению суффикс pt, чтобы указать размер в точках. Перед тем, как перейти к следующему этапу, введите значение, отличное от 16 (именно это значение задается для свойства font Size по умолчанию). Далее введите в верхнее поле следующий оператор, чтобы отсоединить выражение от свойства. myP.style.removeExpression("fontSize") Теперь вы не сможете изменить размер шрифта с помощью нижнего текстового поля, однако элемент будет отображаться шрифтом с последним указанным размером. Чтобы проверить это, в верхнее поле введите следующий оператор. myP.style.foritSize ♦ См. также: методы document. recalc (), getExpression () и setExpression (). гemoveNode (флаг) Возвращаемое значение: ссылка на объект Node Совместимость: WinIE5+, МасШ-, NN-, Moz-, Safari- Метод removeNode () применяется для удаления текущего узла из иерархии элементов в Ш5+. Единственным его аргументом является значение булевого типа, с помощью которого можно удалить либо сам объект (без дочерних узлов), либо узел вместе со всеми его дочерними элементами (значение true). При использовании по умолчанию параметра false следует проявить осторожность: если текущий узел имеет дочерние узлы (например, при попытке удалить только элемент TABLE, но не его дочерние элементы), то Ш5 может вызвать сбой и внезапно завершить свою работу. Более безопасно удалять узел вместе со всеми его дочерними элементами. Метод возвращает ссылку на удаляемый узел. Этот объект перестает быть частью объектной модели документа. Но возвращаемое значение содержит все свойства объекта (включая outerHTML и указанные явно стилевые спецификации). Поэтому им можно воспользоваться для вставки узла в любом другом месте документа. В объектных моделях документа W3C и NN6 метод removeNode () не поддерживается. Аналогичным методом, определенным для всех браузеров, является removeChildO. Область применения метода removeChild () задается в иерархической структуре объектов на один уровень выше объекта, задаваемого в методе removeNode (). Пример В листинге 15.21 показана разница между методами appendChi Id О и removeChi Id (). В функции restore () вы можете заменить выражение mainObj.removeChild(oneChiId); на следующий оператор (в IE5+). oneChiId.removeNode(true); 344 Часть III. Объекты документ»
Разница в этих двух вариантах синтаксиса на первый взгляд незначительна, однако она весьма существенна. В листинге 15.31 далее в этой главе приведен еще один пример использования метода remove Chi Id (). См. также: объект Node; методы appendChild (), cloneChild (), removeChild (), replaceChild (), replaceNode (). replaceAdj acentText ("расположение", " текст") Возвращаемое значение: строка Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Метод replaceAd j acentText О позволяет заменить один фрагмент текста другим; расположение фрагмента отсчитывается относительно текущего объекта. Обратите внимание, что этот метод применяется только для текстовых элементов и неприменим к дескрипторам HTML. Метод возвращает строку, которая была заменена. Оба аргумента являются обязательными. Первый задает один из четырех возможных параметров расположения текстового фрагмента (регистр не учитывается), приведенных в таблице. Положение Описание bef oreBegin Перед открывающим дескриптором текущего элемента af terBegin После открывающего дескриптора перед вложенным содержимым bef oreEnd Перед закрывающим дескриптором после вложенного содержимого af terEnd После закрывающего дескриптора текущего элемента С параметрами bef oreBegin и af terEnd этот метод предпочтительнее применять для элементов внутритекстовых фрагментов (а не блоковых). Например, если воспользоваться методом replaceAd j acentText () с аргументом bef oreBegin для второго из последовательно заданных абзацев, то текст-заместитель будет вставлен после первого абзаца. Метод replaceAd j acentText () нужно рассматривать относительно узлов текстовых фрагментов (хотя ГЕ5 и не полностью поддерживает свойства W3C DOM). Метод заменяет узел текстового фрагмента (при указании одного из четырех возможных параметров) новым текстом. Замена текста простого элемента с помощью параметра af terBegin или bef oreEnd аналогична присвоению текста свойству innerText объекта. Пример Используйте приложение The Evaluator для всестороннего изучения метода replace- Ad j acentText О. Введите каждое из следующих выражений в верхнее текстовое поле, а результат их выполнения просмотрите в элементе туР (и вложенном элементе туЕ). document.getElementByld("myEM").replaceAdjacentText("afterBegin", "twenty") Обратите внимание, что новый текст элемента туЕ наследует поведение своего контейнера (т.е. элемента). Как правило, заменяемый текст (all) возвращается методом в качестве результата и выводится в поле Re su 11 s. document.getElementByld("myEM").replaceAdjacentText("beforeBegin", "We need ") Заменяются все символы текстового фрагмента, включая пробелы. Если заменяемый фрагмент содержит пробелы, то вам придется добавить в заменяющую строку дополнительный пробел. document.getElementByld("myP").replaceAdjacentText("beforeEnd", " good people.") Глава 15. Основные объекты HTML-элементов 345
Существует еще один способ вставки текстового фрагмента после элемента myEm. Если вы попробуете заменить текст после элемента туР следующим образом document.getElementByld("туР").replaceAdj acentText("afterEnd", "Hooray!") то текст будет вставлен после закрывающего дескриптора элемента туР. В дальнейшем этот текстовый фрагмент будет восприниматься как плавающий текстовый узел в объектной модели документа. См. также: свойства innerText, outerText; методы get Ad j acentText (), insert- Ad j acentHTML (), insert Ad j acentText (). replaceChild(объектНовогоУзла, объектСтарогоУзла) Возвращаемое значение: ссылка на объект Node Совместимость: WinIE5+, МасШ5+, NN-, Mozl+, Safari 1+ Метод replaceChild () позволяет заменить существующий объект дочернего узла новым элементом. Параметрами метода служат объекты узлов (вначале указывается заменяющий объект, а после него — заменяемый). "Старый" объект должен быть дочерним по отношению к тому родительскому элементу, для которого запускается метод, а новый— его правильным дочерним элементом в иерархической структуре документа. Метод возвращает ссылку на объект дочернего узла, замененного новым объектом. Этой ссылкой можно воспользоваться как параметром в любом из методов вставки или замены узлов. Помните, что метод replaceChild () вызывается из родительского элемента. Если требуется просто изменить элемент, это можно сделать напрямую с помощью метода swapNode () или replaceNode (). Пример Пример использования этого метода приведен в листинге 15.21 ранее в этой главе. См. также: методы appendChild (), removeChild (), replaceNode (), swapNode (). replaceNode ("объектНовогоУзла") Возвращаемое значение: ссылка на объект Node Совместимость: Winffi5+, МасГЕ-, NN-, Moz-, Safari- Метод replaceNode () подобен replaceChild (), но запускается он для заменяемого узла (а не родительского объекта). Аргументом метода является ссылка на объект узла, который можно создать с помощью метода document .createElement О или скопировать. Возвращаемое значение является ссылкой на заменяемый узел. Таким образом, его можно сохранить в переменной для последующего использования. Если заменяемый узел содержит дочерние элементы, метод replaceNode () удаляет их из документа. Поэтому, если требуется заменить только "внешний" узел, сохранив все внутренние дочерние узлы, необходимо скопировать и вставить их в новый узел (как показано в примере на компакт-диске). Пример В листинге 15.31 продемонстрирован пример использования трех методов управления узлами: removeNode (), replaceNode () и swapNode (). Все они выполняются только в IE5+. Страница, которая отображается после выполнения кода листинга 15.31 в браузере, начинается со списка типа ul, содержащего четыре элемента. С помощью кнопок в нижней части 346 Часть III. Объекты документа
страницы вы можете изменить структуру узлов документа. Первая кнопка запускает функцию replace О, которая изменяет элемент ul на ol. Чтобы выполнить эту задачу, функция должна временно отсоединить все дочерние узлы исходного элемента ul (впоследствии они будут присоединены к новому элементу ol). В то же время старый элемент ul сохраняется в глобальной переменной oldNode (он восстанавливается в следующей функции). Чтобы заменить узел ul на ol, в функции replace () создается новый, пустой элемент ol с идентификатором myOl. Далее все дочерние элементы (li) сохраняются в виде массива, представленного отдельной переменной. После этого дочерние элементы вставляются в новый элемент ol с помощью метода insertBef ore (). Обратите внимание, что каждый дочерний элемент после вставки в новый элемент ol удаляется из массива innards. Наконец, с помощью метода replaceNode О новый элемент ol заменяет старый элемент ul. При этом последний сохраняется в переменной oldNode. Функция restore О выполняет действия, противоположные задаваемым функцией replace (). При этом также сохраняется обратный порядок управления дочерними элементами. Третья кнопка вызывает функцию swap (). Эта функция меняет местами первый и последний узлы. Метод swapNode () задается для одного из узлов, а второй узел указывается в качестве атрибута. Исходя из природы элемента ol, тип нумерации остается прежним; заменяется только текст элементов li. Чтобы продемонстрировать возможности метода removeNode (), в код страницы была добавлена четвертая функция, используемая для удаления последнего дочернего узла элемента списка. При каждом вызове метода в него подставляется атрибут true, указывающий на удаление вместе с элементом li всех вложенных в него текстовых узлов. Поэкспериментируйте с этим методом, задав в качестве параметра значение false. Обратите внимание, что после удаления элемента 1 i родительско-дочерние отношения в документе нарушаются. <html> <head> <title>removeNode(), replaceNode(), and swapNode() Methods</title> ocript type="text/javascript"> // сохранение исходного узла между изменениями var oldNode; // замена узла UL на узел 0L function replace() { if (document.getElementByld("myUL")) { var newNode = document.createElement("OL"); newNode.id = "myOL"; var innards = document.getElementByld("myUL").children; while (innards.length > 0) { newNode.insertBefore(innards[0]); } oldNode = document.getElementByld("myUL"). replaceNode(newNode); .> // восстановление узла OL из узла UL function restore() { if (document.getElementById("myOL") && oldNode) { var innards = document.getElementByld("myOL").children; Глава 15. Основные объекты HTML-элементов 347
while (innards.length > 0) { oldNode.insertBefore(innards[0]); } document.getElementByld("myOL").replaceNode(oldNode); // взаимозамена первого и последнего узлов function swap() { if (document.getElementByldC'myUL") ) { document.getElementByld("myUL").firstChild.swapNode( document.getElementByldC'myUL").lastChild); if (document.getElementByld("myOL")) { document.getElementByld("myOL").firstChild.swapNode( document.getElementByld("myOL").lastChild); ,» // удаление последнего узла function remove() { if (document.getElementById("myUL")) { document.getElementByld("myUL")♦lastChild. removeNode(true); } if (document.getElementById("myOL")) { document.getElementByld("myOL").lastChild. removeNode(true); </script> </head> <body> <hl>Node Methods</hl> <hr /> Here is a list of items: <ul id="myUL"> <li>First Item</li> <li>Second Item</li> <li>Third Item</li> <li>Fourth Item</li> </ul> <form> <input type="button" value="Change to OL List" onclick="replace()" />&nbsp;&nbsp; <input type="button" value="Restore LI List" onclicks"restore()" />&nbsp;&nbsp; <input type="button" value="Swap First/Last" one1ick="swap()" />&nbsp;&nbsp; <input type="button" value="Remove Last" onclick="remove()" /> </form> </body> </html> Вы можете выполнить все действия, запрограммированные в коде листинга 15.31, поддерживая стандарт W3C DOM. Для этого вместо методов removeNode () и replaceNode () используйте методы removeChild () и replaceChild (). Вам также нужно изменить ссылку document .all на document.getElementByld (). См. также: методы removeChild (), removeNode (), replaceChild (), swapNode (). 348 Часть III. Объекты документа
scrollIntoView (флаг) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ4+, NN7+-, Mozl+, Safari 1+ Метод scrollIntoView () прокручивает страницу (по вертикали или горизонтали) таким образом, чтобы текущий объект попал в видимую область окна или фрейма. Параметр булевого типа управляет расположением элемента в видимой области. Значение true (по умолчанию) выравнивает верхнюю часть элемента по верхнему краю окна или фрейма (подразумевается, что документ достаточно велик, чтобы позволить такую прокрутку). Значение false выравнивает нижнюю часть элемента по нижнему краю видимой области. Как правило, используется первое значение, но в некоторых случаях применяется и значение false (когда, например, нежелательно, чтобы пользователь видел информацию ниже определенного элемента). Для элементов форм используется обычная ссылка (document .имяФормы. element- Name, scroll IntoViewO), но можно пользоваться и идентификатором элемента, если он предварительно задан (document.getElementByld("идентификаторЭлемента") .scrollIntoView ()). Пример Приложение The Evaluator применяется также и для изучения метода scrollIntoView (). Измените высоту окна браузера так, чтобы в нем отображались только верхнее поле и область Results. Введите в верхнее поле следующие выражения и ознакомьтесь с видом элемента туР на странице. myP.scrol1IntoView() туР.scrollIntoView(false) Увеличьте высоту окна браузера так, чтобы в нем отображалась нижняя часть страницы. Если ввести в верхнее поле выражение myTable.scrollIntoView(false) то страница будет прокручена таким образом, что ее нижний край совпадет с нижним краем окна. Если же использовать параметр по умолчанию (true или не задавать) myTable.scrollIntoView() то страница будет прокручена таким образом, что ее верхний элемент окажется максимально приближенным к верхнему краю окна. При этом страницу нельзя прокрутить в области, расположенные вне данных страницы (хотя при динамическом изменении расположения элемент может располагаться и за пределами страницы). Если вы попытаетесь прокрутить документ так, чтобы в верхней части окна оказалось начало страницы, то помните, что элемент table имеет подпись (элемент caption), которая расположена в начале таблицы. См. также: методы window. scroll (), window. scrol 1Ву (), window. scrollTo (). setActive () Возвращаемое значение: отсутствует Совместимость: Winffi5.5+, МасШ-, NN-, Moz-, Safari- Метод setActive () позволяет сценарию сделать объект элемента активным. Однако при этом, в отличие от метода focus (), окно не прокручивается так, чтобы элемент попал в видимую область. При вызове метода setActive () запускается обработчик события onf ocus, определенный для элемента; при этом браузер не переходит к этому объекту. Глава 15. Основные объекты HTML-элементов 349
Пример Используйте приложение The Evaluator, чтобы сравнить методы setAct ive () и set Focus (). Прокрутите страницу вверх и увеличьте окно браузера так, чтобы скрыть в нижней части документа флажок; затем введите в верхнее текстовое поле следующее выражение. document.forms[l].myCheckbox.setActive() Прокутите страницу вниз и удостоверьтесь, что флажок активизирован (нажмите <пробел>). Вернитесь к верхнему текстовому полю и введите следующий оператор. document.forms[l].myCheckbox.focus() Тем самым вы активизируете флажок и прокрутите страницу так, чтобы он отображался на экране. См. также: метод focus (). setAttribute (пимяАтрибутап, значение [, ЧувствительностьКРегистру] ) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Метод setAttribute () присваивает новое значение существующему атрибуту текущего объекта или вставляет совершенно новую пару "имя-значение" в набор атрибутов объекта. Этот метод позволяет способом, отличным от непосредственного назначения, установить значение свойства. Стандарт W3C DOM2 рекомендует использовать методы getAttributeO и setAttribute () для получения и задания значений атрибутов объекта элемента вместо применения соответствующих свойств объекта. Если использование этих методов вполне оправдано для элементов XML, стандарт DOM приводит к некоторым проблемам, т.к. поддерживает все свойства объектов элементов HTML. Браузеры, конечно же, будут обеспечивать доступ к атрибутам с помощью свойств и в будущем, поэтому вы вполне можете пользоваться разными методами доступа. Два первых аргумента метода setAttribute () являются обязательными. Первый представляет собой имя атрибута. По умолчанию в нем учитывается регистр. Поэтому, когда метод setAttribute О используется для изменения существующего атрибуга в режиме по умолчанию, необходимо корректно указать имя с учетом регистра. Помните, что имена всех атрибутов, присвоенных в исходном коде, автоматически преобразуются в нижний регистр. Значение, присвоенное атрибуту, является вторым параметром метода. Для совместимости разных браузеров значение должно принадлежать или строковому, или булевому типу. ТЕ обеспечивает дополнительный третий аргумент, управляющий регистром символов в имени атрибуга. Значение по умолчанию (true) обеспечивает разные результаты, что зависит от того, используется ли метод setAttribute () для присвоения нового атрибуга или изменения значения существующего. В первом случае значение третьего параметра true означает, что в первом параметре учитывается регистр. Во втором случае оно указывает, что новое значение присваивается атрибуту лишь в том случае, если первый аргумент в точности (с учетом регистра) совпадает с существующим именем атрибуга. Иначе создается новый атрибут, именем которого служит первый параметр. Применять зависимые от регистра имена новых атрибутов не рекомендуется, если используются имена, отличающиеся только регистром символов. В методах setAttribute!) и get At tribute () используйте установки по умолчанию. / На заметку 350 Часть III. Объекты документ*
В Ш4+ существуют некоторые ограничения на действия метода set At tribute (); атрибут, который добавляется этим методом не становится частью набора attributes, присоединенного к элементу. Несмотря на то, что значение нового атрибута можно получить с помощью метода get At tribute (), его невозможно извлечь из набора attributes. Если новый атрибут создается оператором document.getElementById("myTable").setAttribute("currYear", (new DateO) .getFullYear () ) к нему можно получить доступ с помощью одного из двух следующих выражений. var tableYear = document.getElementById("myTable"). getAttribute("curryear"); var tableYear = document.getElementByldCmyTable").currYear; Оператор var tableYear = document.getElementByld("myTable") . attributes["currYear"]; не позволяет получить значение нового атрибута. Возможности W3C DOM по управлению атрибутами как объектами узлов рассматриваются в разделах, посвященных методам getAttrlbuteNode () и removeAtt ributeNode () (ранее в этой главе). Пример Используйте приложение The Evaluator для детального изучения метода setAttribute () элементов страницы. В Ш4 в ссылках используется выражение document .all, а в Ш5+ поддерживается WSC-стандарт — метод getElementByld (). Установка атрибутов влечет за собой немедленное изменение макета страницы (равно как и изменение свойств объектов). Введите в верхнее текстовое поле следующие выражения, чтобы ознакомиться со значениями атрибутов. Ш4+ document.all.myTable.setAttribute("width", "80%") document.all.myTable.setAttribute("border", "5") IE5+/W3C document.getElementByld("myTable").setAttribute("width", "80%") document.getElementByld("myTable").setAttribute("border", "5") См. также: свойство attributes; методы document .createAttribute О, getAttribute (), getAtt ributeNode (), removeAt tribute (), removeAtt ributeNode (),setAttributeNode(). setAttributeNode () Cm. removeAttributeNode(). setAttributeNodeNS ("узелАтрибута") Возвращаемое значение: объект Attribute Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari- Этот метод вставляет или заменяет атрибут в текущем элементе. Единственный параметр представляет объект атрибута, а возвращаемое значение — это ссылка на новый вставленный объект атрибута. При вызове этого метода браузер просматривает локальные имена и URI пространства имен в поисках указанного узла. Если совпадение найдено, то узел заменяется; если нет, то вставляется. См. также: свойства attributes, namespaceURI, localName; методы getAttributeNS (), removeAttributeNS (), setAttributeNS (). j Глава 15. Основные объекты HTML-элементов 351
setAttributeNS (" итпространстваИмен", " локальноеИмя", " значение") Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Этот метод вставляет или заменяет атрибут в текущем элементе, заданном тремя параметрами. Первый параметр указывает строку URI, совпадающую с соответствующей подписью в документе. Второй параметр задает локальное имя атрибута, значение которого необходимо получить. Если атрибут, заданный первыми двумя параметрами, найден, то его значение изменится на указанное в третьем параметре. В противном случае значение будет вставлено в виде отдельного атрибута. См. также: свойства attributes, namespaceURI, localName; методы getAttributeNS (), removeAttributeNS (), setAttributeNS(). setCapture(булевКонтейнер) См. releaseCapture(). setExpression("имяСвойства", 11 выражение41, "язык") Возвращаемое значение: отсутствует Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Метод setExpression () применяется для присвоения результата выполнения выражения свойству объекта элемента. Метод позволяет присваивать значения объектам HTML- элементов и объектам стилей. Метод setExpression () — это способ присвоения значений атрибутам в сценарии. Однако для присвоения напрямую значений стилям, определенным в дескрипторе HTML, можно воспользоваться синтаксисом метода expression (), как показано в следующем примере. <р style="width:expression(document.body.style.width * 0.75)"> Метод setExpression () принимает три параметра. Первым из них является строка с именем свойства (учитывается регистр), которому присваивается выражение. Второй — строка с выражением, значение которого вычисляется. В выражениях могут использоваться глобальные переменные или другие объекты текущего документа (при условии, что свойство не является массивом). Выражение может также содержать математические операторы. Обратите внимание на тип данных выражения. Тип значения должен совпадать с типом свойства, которому оно присваивается. Например, URL фонового изображения страницы должен быть строкой. Для числовых значений можно использовать и числовой, и строковый тип, поскольку значения преобразуются автоматически в соответствии с типом свойства. Даже выражения, результатом которых является число, следует заключать в кавычки. Они нужны далеко не во всех случаях, но если вы выработаете привычку использовать кавычки, то сможете избежать проблем в строковых или более сложных выражениях, в которых без них не обойтись. Третий параметр метода позволяет указать используемый язык написания сценариев. Он принимает такие значения. Jscript VBScript JavaScript Во всех проявлениях JScript и JavaScript совпадают. Оба языка совместимы со стандартом ЕСМА-262. 352 Часть ///. Объекты документ*
v Одна из причин использования метода setExpression () заключается в том, чтобы динамические свойства всегда отвечали текущему состоянию страницы. Например, если свойство зависит от текущей ширины документа, его необходимо изменить при изменении пользователем размеров окна. Браузер автоматически реагирует на многие события и обновляет аекоторые динамические свойства. По существу, браузер пересчитывает и присваивает свойствам новые значения. В частности, такой автоматический пересчет выполняется при поступлении событий клавиатуры. Однако в том случае, когда сценарий сам выполняет действия (другими словами, не связанные с предопределенными событиями), потребуется вычислить выражения явно. Данную задачу выполняет метод document. recalc () — его необходимо вызвать для пересчета значений динамических свойств. Пример В коде листинга 15.32 используются методы setExpression (), recalc () и getExpres- sion () для создания своеобразных цифровых часов. Текущее время обозначается тремя полосами (часы, минуты, секунды), длина которых увеличивается с течением времени. В то же время с помощью элементов innerHTML и span справа от каждой полосы указывается числовое значение показателей. Динамически пересчитываемые значения в этом примере создаются на основе нового объекта даты (сохраняется в переменной now), данные которого заимствуются из системных часов компьютера. Для преобразования часов, минут и секунд в длины соответствующих полос необходимо выполнить дополнительные вычисления. Полосы делятся на 24 (часы) и 60 (минуты и секунды) частей. В двух последних полосах каждая часть имеет длину 5 пикселей (сохраняется в переменной shortWidth). Часть полосы часов равна значению shortWidth, умноженному на 2,5. iii^iiji^^ii^^^ipgimipi^y^ ©*•* • «> й & игр*-* -&™~ *»*&0*% и ♦ и а т®*# get Express! on 0> setExpressionQ, recalcQ Methods This clock uses Dynamic Properties to calculate bar width and time numbers: Hours: ШШШШШШШШШШШШШШШШШ 23 Minntei: 25 Second* ojmp j j Рис. 15.1. Графические цифровые часы с необычным интерфейсом Глава 15. Основные объекты HTML-элементов 353
При загрузке документа элементам span, представляющим цветные полосы часов, длина не задается. После полной загрузки страницы, обработчик события onload запускает функцию init (). Эта функция устанавливает начальные длины всех полос и подписи к ним. После этого в функции init () вызывается функция updateClock (). Последняя функция создает объект даты для текущего времени. В ней вызывается метод document .recalc (), который указывает пересчитать документ, соответственно выражениям в функции init (), а также назначить свойствам новые значения. При динамическом отображении на странице времени функция updateClock () вызывается каждую секунду. Чтобы увидеть результат выполнения метода getExpressionO, щелкните на кнопке страницы. При этом будет возвращено значение одного из атрибутов, назначенных с помощью метода set Express ion (). <html> <head> <title>getExpression(), setExpressionO , and recalc() Methods</title> <style type="text/ess"> th {text-align:right} span {vertical-align:bottom} </style> <script type="text/javascript"> var now = new Date(); var shortWidth = 5; var multiple = 2.5; function initO { with (document.all) { hoursBlock.style.setExpression("width","now.getHours() * shortWidth * multiple","jscript"); hoursLabel.setExpression("innerHTML","now.getHours()", njscript"); minutesBlock.style.setExpression("width", "now.getMinutesO * shortWidth","jscript"); minutesLabel.setExpression("innerHTML", "now.getMinutes()"/"j script"); secondsBlock.style.setExpression("width", "now.getSecondsO * shortWidth","jscript")/ secondsLabel.setExpression("innerHTML", "now.getSecondsO ", "jscript") ; } updateClock(); } function updateClock() { now = new DateO ; document.recalc(); setTimeout("updateClock()",1000); } function showExprO { alert("Expression for the \'Hours\' innerHTML property is:\r\n" + document.getElementByld("hoursLabel"). getExpression("innerHTML") + "."); ' и ■ i ■■■■ Щ 354 Часть III. Объекты документ*
} </script> </head> <body onload="init () "> <hl>getExpression(), setExpression(), recalc () Methods</hl> <hr /> <p>This clock uses Dynamic Properties to calculate bar width and time numbers:</p> <table border="0"> <tr> <th>Hours:</th> <tdxspan id="hoursBlock" style= "background-color:red"> </span> &nbsp;<span id="hoursLabelH></span></td> </tr> <tr> <th>Minutes:</th> <tdxspan id="minutesBlock" style= "background-color:ye1low"></span>&nbsp; <span id="minutesLabel"></spanx/td> </tr> <tr> <th>Seconds:</th> < <tdxspan id="secondsBlock" style= "background-color:green"></span>&nbsp; <span id= " secondsLabel" x/spanx/td> </tr> </table> <hr /> <form> <input type="button" value="Show 'Hours' number innerHTML Expression" onclick="showExpr()" /> </form> </body> </html> См. также: методы document. recalc (), removeExpression (), setExpression (). swapNode {объктДругогоУзла) Возвращаемое значение: ссылка на объект Node Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Метод swapNode () меняет местами в иерархии элементов два узла. При этом содержимое узлов полностью сохраняется. Аргументом выступает объект узла (созданный методом document. createElement () или скопированный). Возвращаемое значение — это ссылка на объект, метод swapNode () которого был вызван. Пример Пример использования swapNode () приведен в листинге 15.31. См. также: методы removeChild (), removeNode (), replaceChild (), replace- Node (). tags (nимяДескриптора") Возвращаемое значение: массив объектов элементов Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Глава 75. Основные объекты HTML-элементов 3SS
Метод tags () имеют не все элементы, однако он включен во все наборы элементов (например all, forms или elements). Его можно представить как фильтр, отбирающий определенные элементы из набора. Например, для получения массива всех элементов Р документа используется выражение. document.all.tags("Р") Аргументом является строка с именем дескриптора, который нужно извлечь. Регистр в данном случае не учитывается. Возвращаемое значение представляет собой массив ссылок на объекты текущего набора, имена которого совпадают с заданным параметром. Если совпадений нет, результирующий массив имеет нулевую длину. Для обеспечения совместимости с другими браузерами предпочтительнее пользоваться методом getElementsByTagName (), описанным ранее в этой главе. Пример Приложение The Evaluator позволяет детально изучить метод tags (). Поочередно введите в верхнее поле каждое из приведенных ниже выражений. document.all.tags("div") document.all.tags("div").length myTable.all.tags("td").length Поскольку метод tags () возвращает массив объектов, вы можете использовать любое возвращенное значение в качестве корректной ссылки на элемент. document.all.tags("form")[l].elements.tags("input").length См. также: метод getElementsByTagName (). urns (" иШ1поведенияп) Возвращаемое значение: массив объектов элементов Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Методом urns () обладают не все элементы, однако он включен во все наборы объекте* Аргументом является строка, которая содержит URN (Uniform Resource Name— Универб сальное имя ресурса) поведения (как правило, .htc в Ш5), присвоенного одному или нескольким элементам набора. Параметр не включает расширение имени файла. Если для укь занного параметра не найдено URN, метод urns () возвращает массив нулевой длины: Данный метод связан со свойством behaviorUrns, которое содержит массив URN-повф- дений, присвоенных объекту элемента. Пример Чтобы иметь возможность переназначения поведения в будущем с помощью метод| urns О, на страницу можно добавить кнопку и функцию (листинг 15.196), которая будет проверять, присоединено ли поведение makeHot. htc к элементу туР. Эта функция выш- дит следующим образом. function behaviorAttachedO { if (document.all.urns("makeHot")) { alert("There is at least one element set to \'makeHot\'.") ; См. также: свойство behaviorUrns. 356 Часть III. Объекты докумеяп
Обработчики событий onactivate onbeforedeactivate ondeactivate Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Обработчики событий onactivate и ondeactivate появились в Ш5.5. При определенных обстоятельствах они похожи на обработчики событий onf ocus и onblur, соответственно. Если элемент активизируется, то событие onactivate запускается перед onf ocus; и наоборот, до деактивизации элемента события запускаются в следующей последовательности: onbef oredeactivate, ondeactivate, onblur. Только элементы, которые по своей природе могут активизироваться (например, ссылки или элементы управления форм) или для которых установлен атрибут tab index, могут запустить эти события. В IE5.5+ поддерживаются исходные обработчики событий onf ocus и onblur. Но поскольку их поведение подобно onactivate и ondeactivate, не рекомендуется использовать старые и новые обработчики событий в одном приложении. Если сценарий создается только для ЕЕ5.5+, воспользуйтесь новой терминологией. Пример Вы можете изменить листинг 15.34 так, чтобы вместо обработчиков onf ocus и onblur в нем использовались обработчики onactivate и ondeactivate. Используйте приложение The Evaluator для изучения обработчика события onbef oredeactivate. Для начала определите активный элемент туР. myP.tablndex = 1 Несколько раз нажмите клавишу <ТаЬ>, и вы активизируете элемент туР, на что укажет пунктирная рамка вокруг него. Чтобы не допустить деактивизацию элемента, назначьте обработчику событий onbef oredeactivate безымянную функцию, как показано в следующем выражении. myP.onbeforedeactivate = new Function("event.returnValue=false") Теперь, когда вы нажмете клавишу <Tab>, элемент туР будет оставаться активным до тех пор, пока вы не перезагрузите документ. Не стоит увлекаться этим приемом, если вы не планируете заблокировать доступ к их содержимому. См. также: обработчики событий onblur, onf ocus. onbeforecopy Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Обработчик события onbeforecopy запускается до того, как происходит копирование, инициированное пользователем в результате вызова опции меню Edit (включая и комбинацию клавиш <Ctrl+C>) или контекстного меню. Если пользователь выполняет команду Сору из меню Edit или контекстного меню, событие onbeforecopy запускается до того, как отображаются элементы меню. На практике событие иногда запускается повторно. Запуск события onbeforecopy не гарантирует, что пользователь завершит операцию копирования (например, он может закрыть контекстное меню до выбора соответствующего пункта). В отличие от событий вставки, обработчик события onbeforecopy не работает с элементами ввода текста на формах. Глава 15. Основные объекты HTML-элементов 357
Пример Вы можете использовать обработчик onbef огесору для обработки данных перед их копированием. В листинге 15.33 показано, как с помощью обработчика onbef огесору элемента второго абзаца можно скопировать только выделенные текстовые фрагменты. Скопированные данные вставляются в текстовую область, чтобы наглядно представить результат выполненного действия. Если бы в данном случае использовался обработчик опсору, то выделение создавалось бы после выбора команды копирования, а не до этого. <html> <head> <title>onbefогесору event handler</title> <script type="text/javascript"> function selectwholeO { var obj = window.event.srcelement; var range - document.body.createtextrange(); range.movetoelementtext(obj); range.select (); event.returnvalue = false; } </script> </head> <body> <hl>onbefогесору event handler</hl> <hr /> <p>select one or more characters in the following paragraph. Then execute a copy command via edit or context menu.</p> <p id="myp" onbeforecopy="selectwholeO">lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <form> <p>paste results here:<br /> <textarea name="output" cols="60" rows="5"> </textareax/p> </form> </body> </html> См. также: обработчики событий onbef orecut, oncopy. onbeforecut Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Обработчик события onbeforecut запускается до того, как лроисходит вырезка, инициированная пользователем в результате выбора опции меню Edit (включая и комбинацию клавиш <Ctrl+X>) или контекстногб меню. Если пользователь выполняет команду Cut из меню Edit или контекстного меню, событие onbeforecut запускается до того, как отображается меню. На практике событие иногда запускается дважды. Запуск события onbeforecut не гарантирует, что пользователь завершит операцию вырезки (например, он может закрыть контекстное меню до выбора соответствующего пункта). Если добавить обработчик события onbeforecut в элемент HTML, в контекстном меню операция Cut будет запрещена. Однако присвоение вызова функции JavaScript этому обработчику делает активным данный пункт меню. 358 Часть ///. Объекты документа
Пример Вы можете использовать обработчик событий onbe fore cut для выполнения операций до того, как выделенные данные будут вырезаны в буфер обмена. Чтобы ознакомиться с этим обработчиком, в листинге 15.33 измените onbeforecopy на onbef orecut. В исходном случае операция вырезания и вставки текстового фрагмента в текстовую область не выполнялась. После изменения листинга команда вырезания становится активной для выполнения. См. также: обработчики событий onbeforecopy, oncut. onbef oredeactivate См. обработчик событий onactivate. onbeforeeditfocus Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Обработчик события onbef or eedit focus (не поддерживаемый в МасШ5) запускается при редактировании элемента на странице в такой среде DHTML, как элемент управления ActiveX или при редактировании содержимого страницы в IE5.5+. В данном случае рассматривается второй сценарий, поскольку он полностью реализуется на клиентской стороне средствами JavaScript. Событие onbeforeeditfocus запускается до того, как элемент активизируется. (При этом на экране процесс редактирования может никак не отобразиться, если только это не запрограммировано в сценарии напрямую.) Событие запускается каждый раз, когда пользователь щелкает мышью на элементе, даже если этот элемент уже активен. Пример Приложение The Evaluator применяется и для изучения обработчика onbef oreeditf ocus в Ш5.5+. Следующее выражение назначает этому обработчику события объекта туР безымянную функцию. Данная функция изменяет цвет текста на красный. myP.onbeforeeditfocus = new Function("myP.style.color='red'") Далее разрешите редактировать содержимое с помощью следующего оператора. myP.contentEditable = true По щелчку на элементе myP его текст будет окрашиваться в красный цвет непосредственно перед редактированием данных. Если вы хотите реализовать подобную функциональность в собственных приложениях, то обязательно включите в сценарии функцию блокировки редактирования данных и возврата исходного цвета текста. См. также: свойства document .designMode, contentEditable, isContent- Editable. onbeforepaste Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Как и события onbeforecopy и onbef orecut, событие onbef orepaste происходит до отображения контекстного меню или меню Edit (пока текущий объект или его часть выделены). Это событие оказывается полезным, когда сценарий проводит копирование и вставку сложного объекта. Управляемый объект может соответствовать нескольким типам данных, однако сценарий обработает только один из них. Или же в буфер обмена помещаются дополнительные данные (например, свойство id элемента). Использование обработчика события onbe for epaste для установки свойства event. ret urnValue в значение false гарантирует, что вставляемым элементом можно будет управлять из контекстного меню или меню Edit (при условии, что элемент содержится в буфере обмена). Обработчик события onpaste позволяет переносить содержимое из буфера обмена в текущий выделенный элемент. Глава 15. Основные объекты HTML-элементов 359
Пример В листинге 15.45 (далее в этой главе) приведен пример использования обработчиков onbef orepaste и onpaste. См. также: обработчики событий oncopy, oncut, onpaste. onblur Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Событие onblur происходит тогда, когда изменяется активный элемент документа. Например, элемент текстового поля генерирует событие onblur, когда пользователь переходит к следующему элементу формы с помощью клавиши <ТаЬ>. Событие onblur первого элемента происходит раньше события onf ocus второго. Свойства события onblur расширяются, так как появляются новые поколения браузеров, поддерживающих языки сценариев. В ранних версиях деактивизация (blur) и активизация (focus) задавались лишь для элементов ввода текста (включая и элемент select). Поэтому их можно использовать для активизации подобных элементов управления в браузерах любых типов и версий. У объекта window обработчик события onblur появился, начиная с NN3 и Ш4. В IE4 обларть его применения стала охватывать и другие элементы форм, в основном, в операционной системе Windows, поскольку в пользовательском интерфейсе именно этой ОС пунктирным прямоугольником выделяются такие активные элементы, как кнопки и ссылки (после чего их можно активизировать нажатием клавиши пробела). В Ш5 обработчик события onblur задается почти для каждого элемента HTML. Тем не менее, для большинства из них активизация и деактивизация невозможны, если в дескрипторе элемента не задан атрибут tabindex. Например, если присвоить tabindex="lM в дескрипторе <р>, то пользователь сможет сделать активным этот абзац (выделить пунктирным прямоугольником в Windows), только если щелкнет на нем или последовательно нажмет клавишу <ТаЬ>. Если вы собираетесь использовать обработчик события onblur для окна или элементов, предназначенных для ввода текста, помните, что при программировании функции- обработчика возможны неожиданные или нежелательные эффекты. Например, в Ш активный объект window может стать неактивным (или сгенерировать событие onblur), когда пользователь сделает активным другой элемент страницы (или просто щелкнет в пустой области страницы). Подобным образом взаимодействие между onblur, onf ocus и диалоговой функцией alert () может оказаться проблематичным для элементов текстовых полей. Поэтому для запуска процедуры проверки правильности заполнения формы рекомендуется использовать обработчик события onchange. Если один и тот же элемент имеет два обработчика (onblur и onchange), то onchange происходит перед onblur. Подробно о применении обработчиков событий для проверки правильности данных рассказано в главе 43. В Ш5.5+ добавлен обработчик события ondeactivate, который запускается непосредственно перед onblur. События onblur и ondeactivate блокируются, если функция обра- ботчика события onbef or edeacti vat e устанавливает свойство event ♦ re turn Value равным false. Пример Чаще всего разработчики страниц используют обработчик события onblur для отслеживания выполняемых пользователем действий. Например, можно остановить деактивизацию из текстового поля до тех пор, пока в нем не будут введены корректные данные. Такой подход используется редко, поскольку существуют более дружественные способы принуждени* пользователей вводить все необходимые данных (см. главу 43). В следующем листинге показано влияние атрибута tabindex элемента (в Winffi5) на выполнение обработчиков событий onblur и onf ocus. Обратите внимание, что события обрабатываются только для второго абзаца, хотя заданы они для всех трех абзацев. 360 Часть III. Объекты документа
t5.34. Обработчике^ <html> <head> <title>onblur and onblur Event Handlers</title> <script type="text/javascript"> / function showBlurO { var id = event.srcElement.id; alert("Element \M" + id + "\" has blurred."); } function showFocusO { var id = event.srcElement.id; alert("Element \M" + id + "\" has received focus."); } </script> </head> <body> <hl id="Hl" tabindex="2">onblur and onblur Event Handlers</hl> <hr /> <p id="PI" onblur="showBlur()" onfocus="showFocus()">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <p id="P2" tabindex="l" onblur="showBlur()" onfocus="showFocus()">Bis nostrud exercitation ullam mmodo consequet. Duis aute involuptate velit esse cillum dolore eu fugiat nulla pariatur. At wer eos et accusam dignissum qui blandit est praesent luptatum delenit aigueexcepteur sint occae.</p> <p id="P3" onblur="showBlur()" onfocus="showFocus()">Unte af phen neigepheings atoot Prexs eis phat eit sakem eit vory gast te Plok peish ba useing phen roxas. Eslo idaffacgad gef trenz beynocguon quiel ba trenzSpraadshaag ent trenz dreek wire procassidt program.</p> </body> </html> См. также: методы blur (), focus О; обработчики событий ondeactivate, onbeforedeactivate, onfocus, onactivate. onclick Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Событие onclick происходит в том случае, когда пользователь нажимает и отпускает основную кнопку мыши в области одного элемента. Кроме того, такое событие может вызваться не только щелчком кнопки мыши (в системах Windows 95 и выше). С помощью клавиатуры можно сделать активным элемент, а затем нажать клавишу пробела или <Enter> — это действие эквивалентно щелчку мыши. Если объект элемента поддерживает метод click (), то в Ш событие onclick запускается до вызова метода (обратите внимание, что в браузере NN это не происходит). Свойства события onclick расширялись по мере появления новых поколений браузеров, поддерживающих языки написания сценариев. Важно знать последовательность событий, происходящих в результате однократного или двукратного нажатия пользователем кнопки Глава 15. Основные объекты HTML-элементов 361
мыши. Похожими событиями являются onmousedown, onmouseup и ondoubl ее licit Событие onmousedown запускается, когда пользователь нажимает кнопку мыши (замыкает контакт). Затем (когда контакт разрывается) запускается событие onmouseup. Лишь по* еле этого происходит событие onclick; оно подтверждает, что события onmousedown и onmouseup уже произошли. События onmousedown и onmouseup с примерами их применения рассматриваются далее в этой главе. Взаимодействие с событием ondblclick выглядит достаточно просто: вначале (после первого нажатия) происходит событие onclick, за ним (после второго нажатия) следует событие ondblclick. О событии ondblclick подробнее рассказано далее в этой главе. При использовании объектов, которые вызывают в сценарии внутренние операции прк щелчке на них (в частности, ссылки и области), обработчик события onclick способен выполнить все действия самостоятельно (включая переход к другой странице, обычно реализуемый атрибутом href элемента). Например, для совместимости со всеми браузерами, поддерживающими языки написания сценариев, можно реализовать поддержку щелчка на изображения, заключив его в дескриптор <а>. Обработчик события onclick размещается в дескриптор! <а> (что невозможно в дескрипторах <img> ранних версий браузеров). Если настроить обработчик события onclick, не предприняв специальных мер, то вначале будет вызван обработчик, а затем будут выполнены внутренние действие элемента. Предположим, вам необходимо блокировать вьшолнение внутреннего действия элемента. Для этого обработчик: события должен возвращать значение false. Добиться такого эффекта можно двумя способами. Первый из них заключается в добавлении оператора return false к обработчику. <а href="#" onclick="yourFunction() ; return false"ximg. ♦ . ></a> Другой способ позволяет перенести оператор return false внутрь функции, реш зующей обработку события (как показано ниже). function yourFunction() { [операторы, выполняющие действия] return false; } <а href=M#" onclick= "return yourFunctionO "ximg. . .></a> Используются оба способа. Можно применить и третий — вообще не использовать обработчик события onclick, а присвоить атрибуту href значение javascript: псевдо-ий (см. объект ссылки в главе 19). Модель событий в ГЕ4+ позволяет предотвратить выполнение внутренних действий прш щелчке на объекте: достаточно, чтобы функция обработчика события onclick устанавлизд ла свойство returnValue объекта события в значение false. Для этого в функцию следует включить такой код. event.returnValue = false; Модель событий W3C DOM предлагает совсем другой подход к отмене действий предпринимаемых по умолчанию: в функции обработчика события следует вызвать метод eventObj.cancelDefault(). Распространенной ошибкой начинающих программистов является использование кнопки отправки данных формы (Submit) для выполнения сценария, а не своего первоначального действия. Обычно элементу input типа submit присваивается обработчик событий onclick для выполнения некоторых локальных операций. Кнопка отправки данных формы (Submit) имеет встроенное внутреннее поведение, подобно ссылкам и областям. Если это поведение блокируется так, как это было описано выше, то рекомендуется использовать элемент input типа button. 362 Часть III. Объекты доктет
Если вы испытываете трудности с реализацией обработчика события onclick (например при определении используемой кнопки мыши), может оказаться, что программированию сценария мешает поведение операционной системы или браузера по умолчанию. Как правило, добиться желаемого результата позволяет обработчик события onmousedown. (Событие onmouseup может не генерироваться при нажатии второй кнопки мыши.) При взаимодействии с пользователем предпочтительно использовать обработчик события onclick, поскольку поведение браузера в этом случае похоже на то, к чему он привык в повседневной практике. В экстренных случаях можно прибегнуть к событию onmousedown. Пример Обработчик события onclick проще всего использовать в создаваемых сценариях. В листинге 15.35 приведен пример обработки событий щелчка и двойного щелчка. При щелчке и/или двойном щелчке на ссылке в строке состояния отображаются сообщения, связанные с событием. Обратите внимание на то, что при двойном щелчке сначала возникает событие одинарного щелчка, а сообщение двойного щелчка в строке состояния сразу же заменяет сообщение обычного щелчка. <html> <head> <title>onclick and ondblclick Event Handlers</title> <script type=Htext/javascript"> var timeout; function clearOutput() { document.getElementByld("clickType").innerHTML = ""; } function showClickO { document.getElementByld("clickType").innerHTML = "single"; clearTimeout(timeout); timeout = setTimeout("clearOutput()", 3000); } function showDblClickO { document.getElementByld("clickType").innerHTML = "double"; clearTimeout(timeout); timeout = setTimeout("clearOutput()", 3000); } </script> </head> <body> <hl>onclick and ondblclick Event Handlers</hl> <hr /> <a href="#" onclick="showClick();return false" ondblclick=,freturn showDblClickO ">A sample link.</a> (Click type: <span id="clickType"></span>) </body> </html> См. также: метод click О ; обработчики событий oncontextmenu, ondblclick, onmousedown, onmouseup. Глава 15. Основные объекты HTML-элементов 363
oncontextmenu Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Событие oncontextmenu происходит, когда пользователь щелкает на объекте второй (как правило, правой) кнопкой мыши. Этот щелчок вызывает лишь два события: onmousedown и oncontextmenu. Для блокировки отображения меню при щелчке правой кнопкой мыши необходимо использовать один из трех методов, доступных в Ш5+ (как отмечалось при описании обработчика события onclick: два варианта с возвращаемым значением false и присвоение значения false свойству event. returnValue). Часто разработчики пытаются заблокировать появление контекстного меню с целью предотвращения загрузки изображений или просмотра исходного кода фреймов. Однако помните: если пользователь отключит опцию Active Scripting в Ш5+, то обработчик события не сможет помешать появлению контекстного меню. Другая возможность использования события заключается в отображении специального контекстного меню, созданного средствами DHTML. В этом случае необходимо запретить вызов исходного контекстного меню, чтобы два меню не могли появиться одновременно. Пример Пример использования обработчика oncontextmenu приведен ранее в этой главе в листинге 15.30 (при рассмотрении способов управления контекстным меню). См. также: методы releaseCapture (), setCapture (). oncontrolselect Совместимость: WinIE5.5+, Macffi-, NN-, Moz-, Safari- Событие oncontrolselect происходит до того, как пользователь выделяет область, называемую разработчиками Microsoft управляющим выделением. Из документации Microsoft не совсем понятно, что же такое управляющее выделение, но, кажется, оно непосредственно связано с режимом пользовательского редактирования. См. также: обработчики событий onresizeend, onresizestart. oncopy oncut Совместимость: WinIE5+, MacIE4+, NN-, Moz-, Safari- События oncopy и oncut происходят после того, как пользователь или сценарий инициируют действие копирования или вырезки текущего объекта. Каждому событию предшествует соответствующее событие before, которое происходит перед выбором опции меню Edit или появлением контекстного меню (а также перед операциями копирования, вырезки, инициированных комбинациями клавиш). Данные обработчики позволяют добавить возможность редактирования к тем элементам, которые обычно невозможно скопировать или вырезать. В таких ситуациях следует сделать доступными опции Сору или Cut в контекстном меню или меню Edit, установив свойство event. return Value для обработчика onbeforecopy или onbeforecut в значение false. Затем обработчики событий oncopy или oncut должны поместить содержимое объекта в буфер обмена, применив метод setData () для объекта clipboardData. В этом случае в функции обработчика необходимо установить свойство event. returnValue равным false — это предотвратит обработку содержимого буфера обмена методами копирования или вырезки по умолчанию. 364 Часть III. Объекты документ!
Поскольку вы сами распоряжаетесь данными, помещаемыми в буфер обмена, то можете выполнять не только их непосредственное копирование. Например, вы вправе сохранить значение свойства src объекта изображения, чтобы пользователь имел возможность вставить его в произвольном месте страницы. В случае использования обработчика события oncut сценарий отвечает также и за удаление элемента или выделенного содержимого со страницы. Для удаления всего содержимого элемента достаточно просто установить его свойство innerHTML или innerText равным пустой строке. Для выделенной области следует использовать метод selection.createRange (), генерирующий объект Text Range. Содержимое последнего можно затем обработать методами, соответствующими данному объекту. Пример В листинге 15.36 продемонстрирован пример совместного использования обработчиков onbef ore cut и oncut (а также обработчиков onbef or epaste и onpaste). Как видите, функция handleCut () не только заносит выделенное слово в объект clipboarddataData, но и удаляет исходный элемент ячейки таблицы. Если же заменить обработчик onbef or ecut и oncut на onbef огесору и опсору (и отменить удаление исходного элемента в таблице), то будет выполняться операция копирования-вставки, а не вырезания-вставки. Этот вариант рассматривается в листинге 15.45 далее в этой главе. 15.36. Вырезанмимггмм даима <html> <head> <title>onbeforecut and oncut Event Handlers</title> <style type="text/css"> td (text-align:center} th {text-decoration:underline} .blanks {text-decoration:underline} </style> <script type="text/javascript"> function selectwhole() { var obj = window.event.srcElement; var range = document.body.createTextRange(); range.moveToElementText(obj); range.select(); event.returnValue = false; } function handleCut() { var rng = document.selection.createRange0; clipboardData.setData(M Text",rng.text); var elem = event.srcElement; elem.innerText = ""; event.returnValue = false; у } function handlePasteО { var elem = window.event.srcElement; if (elem.className == "blanks") { elem.innerHTML = clipboardData.getData("Text"); } event.returnValue = false; } Глава 15. Основные объекты HTML-элементов 36S
function handleBeforePaste() { var elem = window.event.srcElement; if (elem.className == "blanks") { event.returnValue = false; . ■ </script> </head> <body> <hl>onbeforecut and oncut Event Handlers</hl> <hr /> <p>Your goal is to cut and paste one noun and one adjective from the following table into the blanks of the sentence. Select a word from the table and use the Edit or context menu to cut it from the table. Select one or more spaces of the blanks in the sentence and choose Paste to replace the blank with the clipboard contents.</p> <t£ble cellpadding="5" onbeforecut="selectWhole()" oncut="handleCut()"> <tr> <th>Nouns</th> <th>Adjectives</th> </tr> <tr> <td>truck</td> <td>round</td> </tr> <tr> <td>doll</td> <td>red</td> </tr> <tr> <td>ball</td> <td>pretty</td> </tr> </table> <p id="myP" onbeforepaste="handleBeforePaste()" onpaste="handlePaste()"> Pat said, "Oh my, the <span id="blankl" class="blanks">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</span> is so <span id="blank2" class="blanks">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;</span>!"</p> <button onclick="location.reload()">Reset</button> </body> </html> См. также: обработчики событий onbeforecopy, onbeforecut, onbeforepaste и onpaste. ondblclick Совместимость: WinIE4+, MacIE4-i-, NN4+, Mozl+, Safari 1+ Событие ondblclick происходит после второго быстрого щелчка мышью. Время между нажатиями зависит от настроек в папке Панель управления (Control Panel) компьютера конечного пользователя. Событие onclick происходит после первого из двух щелчков. Не стоит разрабатывать страницу, на которой элемент выполняет одно действие по одинарному щелчку и другое — по двойному. Учитывая, как в современных браузерах реализуется последовательность событий, нецелесообразно использовать это событие (событие onclick все равно происходит даже при двойном щелчке). Часто по щелчку кнопки мыши выдается 366 Часть III. Объекты документа
некоторая справка. Такая схема реализована в большинстве менеджеров файлов, использующих графические средства: по щелчку на значке файл выделяется, а двойной щелчок его выполняет. В любом случае, одно действие не мешает другому и не запутывает пользователя. Пример Пример использования обработчика ondblclick приведен в листинге 15.35 ранее в этой главе. См. также: обработчики событий onclick, onmousedown, onmouseup. ondrag, ondragend, ondragstart Совместимость: Winffi5+, МасШ-, NN-, Moz-, Safari- Событие ondrag происходит после события ondragstart и затем продолжает постоянно запускаться, пока пользователь "перетаскивает" по экрану выделенную область или объект. В отличие от onmousemove, которое происходит лишь при движении указателя мыши, событие ondrag продолжает происходить и тогда, когда указатель остается неподвижным. В Ш5+ пользователи имеют возможность "перетащить" объект в другие окна браузера или другие приложения. Событие продолжает запускаться, пока указатель находится в пределах окна браузера. Поскольку событие происходит независимо от того, что находится под объектом, им можно воспользоваться в играх или тренажерах, когда пользователь выполняет операцию "перетаскивания'* за ограниченное время (например при сравнении пар объектов). Если в следующих версиях браузеров появится возможность загружать указатели, с помощью события ondrag можно будет эмулировать анимированный указатель. Четкое понимание последовательности событий, связанных с "перетаскиванием" объекта, необходимо в случаях, когда в сценарии реализуется управление внутренними действиями (в основных операциях "перетаскивания" этого обычно не требуется). Рассмотрим обычную операцию "перетаскивания" (рис. 15.2). Представим, что названия ячеек таблицы совпадают с содержимым ячеек: "truck" в ячейке А1; ."round" в Bl; "doll" в А2 и т.д. Во время операции "перетаскивания" многие объекты способны генерировать события, связанные с ней. Последовательность событий, а также цели их назначения представлены в табл. 15.10. На практике некоторые события, приведенные в табл. 15.10, могут и не происходить. Это связано с тем, сколько обработчиков событий используется в сценарии. Еще одним важным фактором является скорость, с которой пользователь выполняет операцию "перетаскивания" (а также производительность процессора). Чаще всего опускаются такие события, как ondragenter и ondragleave, а также некоторые из событий ondragover, если пользователь "проходит" по объекту быстрее, чем может произойти событие ondragover. Несмотря на указанную неопределенность, существует несколько событий, которые происходят всегда. События ondragstart, ondrop (для целевого объекта) и ondragend, а также промежуточные события ondrag происходят всегда при "перетаскивании" объекта по экрану. Все события, кроме ondrop, запускаются для исходного элемента, a ondrop — для целевого элемента. Пример Пример использования обработчиков событий операций "перетаскивания" приведен в листинге 15.37. Эта страница основана на примере, представленном в листинге 15.36, но в ней применены несколько другие программные конструкции. В данном случае пользователю предлагается выбрать отдельные слова в столбцах Nouns и Adjectives, а затем перетащить их в пустые места предложений. Зачастую на операцию перетаскивания пользователю отводится всего несколько секунд. Глава 15. Основные объекты HTML-элементов 367
ы тип inii Willi шжшшшпшг™ : File Edit View Favorites Teoto Help ; O^- © [*J [Ц $J) P5"** t^Fevo,te* Dragging Event Handlers щт wm фммЯа щтщштттттт 0[0-% ■ • :J S У$ '** Your goal is to drag one noun and one adjective from the following table mto the blanks of the sentence. Select a word from the table and drag it to the desired blank. When you release the mouse, the word will appear in the blank. You have two seconds to complete each blank. Nouns Adjectives Щ round doll red ball pretty Pat said. "Oh my, the _. is so !" [ Reset J ^ (floor» " ....'..,',,','■. Z^:,r~Z.I:.'Z~ * ;j My Computer » J Рис. 15.2. Стандартная операция "перетаскивания" Тшбтш 1&1В» Событии и йк тши\ iffii^i тшшгмй пппппнии "пеовт Событие Цель Описание ondragstart ячейка А1 ondrag ячейка А1 ondragenter ячейка А1 ondragover ячейка А1 (повторение) ячейка А1 ondragenter table ondragleave ячейка А1 ondrag ячейка А1 Первое событие, запускаемое при операции "перетаскивания" Продолжает запускаться во время всей операции. В промежутках могут происходить и другие события Несмотря на то, что указатель еще не покинул ячейку А1, событие ondragenter происходит при первом движении в пределах исходного элемента Запускается во время операции для элементов, над которыми перемещается указатель. Если пользователь просто удерживает кнопку мыши и не перемещает указатель, то события ondrag и ondragover постоянно запускаются одно за другим События ondrag и ondragover запускаются попеременно, пока указатель находится в ячейке А1 Элемент table, заданный границей и/или областью между ячейками, получает событие ondragenter, когда в эту область попадает указатель Событие ondragleave запускается после того, как для другого элемента ПРОИСХОДИТ событие ondragenter Событие продолжает происходить 368 Часть ///. Объекты документа
Окончание табл. JO. 15 Событие Цель Описание ondr agove r t ab 1 е ondragenter ячейка В1 ondragleave ondrag ondragover table ячейка А1 ячейка В1 ondragenter ondragleave ondrag ondragover ondragenter ondragleave ondrag ondragover ondrop ondragend body table ячейка А1 body blankl body ячейка А1 blankl blankl ячейка А1 Исходным элементом этого события становится элемент table, поскольку указатель перемещается в его область. Если указатель остается в ней неподвижным, ТО события ondrag (ячейка А1) и ondragover (table) продолжают генерироваться попеременно В результате "перетаскивания" указатель смещается с границы таблицы в область ячейки В1 Событие ondrag продолжает происходить для объекта ячейки А1 Указатель находится в ячейке В1, поэтому событие ondragover происходит для этого объекта. Оно запускается несколько раз (в зависимости от производительности компьютера и действий пользователя) попеременно с событием ondrag "Перетаскивание" выходит за пределы элемента table и происходит теперь внутри элемента body Событие происходит после того, как указатель покидает элемент table Событие продолжает происходить Указатель находится внутри элемента body. Событие запускается несколько раз (в зависимости от производительности компьютера и действий пользователя) попеременно с событием ondrag Указатель достигает элемента span, идентификатором которого является blankl и где находятся области вставки, выделенные подчеркиванием Указатель покидает элемент body Продолжает запускаться Указатель находится на элементе blankl. Событие запускается несколько раз (в зависимости от производительности компьютера и действий пользователя) попеременно с событием ondrag Элемент span информируется о текущем "перетаскивании" Исходный элемент получает событие, указывающее на завершение процесса перетаскивания. Это событие происходит даже в том случае, если процесс завершается не совсем успешно по причине того, что элемент не дошел до объекта назначения Обработчики событий ondragstart и ondrag помещены в теле страницы, поскольку соответствующие события всплывают от перетаскиваемого пользователем элемента. Действия, выполняемые этими обработчиками, выполняются только в том случае, когда "перетаскивается" элемент таблицы. Этот метод обработки событии весьма эффективен, поскольку исключает повторный вызов обработчиков событий для одних и тех же ячеек таблицы. Обработчик события ondragstart вызывает функцию setupDrag (). Эта функция отменяет обработку события (за исключением случаев, когда перетаскиваемый элемент представлен объектом td таблицы). Чтобы сделать приложение более эффективным при перетаскивании слов в выбранные части приложения, в пустое место вставляется не только слово, но и дополнительные сведения. Таким образом, другой обработчик события может определить, что в первое пустое место предложения перетаскивается существительное, а во второе — Глава 15. Основные объекты HTML-элементов
прилагательное. Чтобы выполнить подобную задачу, мы отнесли слова из первого и второго столбцов к разным классам. Функция setupDrag () генерирует массив, каждый элемент которого состоит из свойства innerText исходных элементов событий, а также имени его класса. Но объект event. dataTransf er не поддерживает массивы, поэтому с помощью метода Array. j о in () массив преобразуется в строку, в которой отдельные записи разделены точкой с запятой. Эта строка и сохраняется в объекте event .dataTransf er. Предназначение данного объекта простое — отображать на экране в процессе перетаскивания курсор правильного вида. Поскольку функция setupDrag {) выполняется в этом сценарии первая, то таймер в ней устанавливается в значение текущего времени (это время считается началом операции перетаскивания). Обработчик событий ondrag (в теле страницы) перехватывает все события перетаскивания, происходящие с элементами таблицы. Как только возникает событие, вызывается функция timerltO, которая сравнивает текущее время с начальным временем (сохраненное в переменной timer). Если разница во времени превышает 2 секунды, то на экране появляется извещающее сообщение. Для его закрытия, пользователю необходимо отпустить кнопку мыши. Чтобы использовать в качестве целевых элементов пустые объекты span, их обработчики событий ondragend, ondragover и ondrop должны устанавливать свойство event. return- Value в значение false. Кроме того, свойство event .dataTransf er.droppEf feet должно указывать тип выполняемого действия (в нашем случае сору). Указанные обработчики событий помещаются в элемент р, содержащий пустые элементы span (опять-таки для простоты). Обратите внимание, что функция cancelDefaults () выполняется только тогда, когда целевой элемент представлен пустым объектом span с идентификатором, начинающимся со слова blank. При отпускании пользователем кнопки мыши вызывается обработчик события ondrop, который вызывает функцию handleDropO. Эта функция получает данные объекта event. dataTransf er и создает на их основе исходный массив (с помощью метода String.split О). В результате простого тестирования в сценарии можно легко определить, что слово соответствующего типа вставляется в необходимую часть предложения. <html> <head> <title>Dragging Event Handlers</title> <style type="text/ess"> td {text-align:center} th {text-decoration:underline} .blanks {text-decoration:underline} </style> <script type="text/javascript"> var timer; function setupDrag() { if (event.srcElement.tagName != "TD") { // запрет перетаскивания других элементов event.returnValue = false; } else { // настройка массива данных, перетаскиваемых в цель var passedData = [event.srcElement.innerText, event.srcElement.className] ; // сохранение массива в строке event.dataTransfer.setData("Text", passedData.join(":")); 370 Часть III. Объекты документа
event.dataTransfer.effectAllowed = "copy"; timer = new Date(); } function timeltO { if (event.srcElement.tagName == "TD" && timer) { if ((new DateO) - timer > 2000) { alert("Sorry, time is up. Try again."); timer = 0; } } } function handleDropO { var elem = event.srcElement; var passedData = event.dataTransfer.getData("Text"); var errMsg = ""; if (passedData) { // извлечение массива из строки passedData = passedData.split(":"); if (elem.id == "blankl") { if (passedData[1] == "noun") { event.dataTransfer.dropEffeet = "copy"; event.srcElement.innerText = passedData[0]; } else { errMsg = "You can't put an adjective into the noun placeholder. " ;' } } else if (elem.id == "blank2") { if (passedData[1] == "adjective") { event.dataTransfer.dropEffeet = "copy"; event.srcElement.innerText = passedData[0]; } else { errMsg = "You can't put an noun into the adjective placeholder."; } } if (errMsg) { alert(errMsg); } } } function cancelDefault() { if (event.srcElement.id.indexOf("blank") ==0) { event.dataTransfer.dropEffeet = "copy"; event.returnValue = false; } } </script> </head> <body ondragstart="setupDrag()" ondrag="timeIt()"> <hl>Dragging Event Handlers</hl> <hr /> <p>Your goal is to drag one noun and one adjective from the following table into the blanks of the sentence. Select a word from the table and drag it to the desired blank. Глава 15. Основные объекты HTML-элементов 371
When you release the mouse, the word will appear in the blank.You have two seconds to complete each blank.</p> <table cellpadding=M5M> <tr> <th>Nouns</th> <th>Adj ectives</th> </tr> <tr> <td class="nounM>truck</td> <td class="adjective">round</td> </tr> <tr> <td class="nounM>doll</td> <td class="adjective">red</td> </tr> <tr> <td class=MnounM>ball</td> <td class="adjective">pretty</td> </tr> </table> <p id="myP" ondragenter="cancelDefault()" ondragover="cancelDefault()" ondrop="handleDrop()"> Pat said, "Oh my, the <span id="blankl" class="blanks"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> is so <span id-"blank2" class="blanks">&nbsp;&nbsp;fcnbsp;&nbsp;fcnbsp; </span>!"</p> <button onclick="location.reload()">Reset</button> </body> </html> См. также: объект event .dataTransfer; обработчики событий ondragenter, ondragleave, ondragover, ondrop. ondragenter ondragleave ondragover Совместимость: WinEE5+, MacIE-, NN-, Moz-, Safari- Эти события происходят во время операции "перетаскивания'*. Когда указатель помещается в прямоугольную область, ограничивающую элемент на странице, для последнего происходит событие ondragenter. После этого для элемента, который только что покинул указатель мыши, происходит событие ondragleave. События всегда запускаются в таком порядке (обратном по отношению к физическому действию). В зависимости от производительности компьютера и скорости, с которой пользователь "перетаскивает" объект, одно из событий может не произойти, особенно если физическая скорость действий пользователя превышает возможности компьютера запускать события вовремя. Событие ondragover происходит постоянно, пока указатель находится поверх элемента. При "перетаскивании" объекта из одной точки страницы в другую событие ondragover происходит для всех объектов, по которым "проходит" указатель. Если какие-либо другие события, связанные с "перетаскиванием", не запускаются (т.е. кнопка мыши остается нажатой, но указатель не движется), то события ondrag и ondragover происходят по очереди. Обработчик события ondragover объекта, на котором завершается процесс "перетаскивания", должен устанавливать свойство event. re turn Value в значение false (см. описание обработчика события ondrag ранее в этой главе). 372 Часть III. Объекты документа
Пример Пример использования обработчиков ondragenter и ondragleave приведен в листинге 15.38. На этой простой странице отображается (в строке состояния) время возникновения события перетаскивания. Событие отпускания элемента не происходит, поэтому указатель не изменяет своего вида. При стаскивании указателя с верхнего заголовка обработчик ondragleave удаляет сообщение в строке состояния. <html> <head> <title>ondragenter and ondragleave Event Handlers</title> <script type="text/javascript"> function showEnter() { status = "Entered at: " + new Date(); 'event.returnValue = false; } function clearMsgO { status = ""; event.returnValue = false; } </script> </hdad> <body> <hl ondragenter="showEnter()" ondragleave^"clearMsg()"> ondragenter and ondragleave Event Handlers</hl> <hr /> <p>Select any character(s) from this paragraph, and slowly drag it around the page. When the dragging action enters the large header above, the status bar displays when the onDragEnter event handler fires. When you leave the header, the message is cleared via the onDragLeave event handler.</p> </body> </html> См. также: обработчики событий ondrag, ondragend, ondragover, ondragstart, ondrop. ondragstart Cm. ondrag ondrop Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Событие ondrop (не поддерживаемое в МасШ5) происходит тогда, когда пользователь отпускает кнопку мыши, завершая, тем самым, операцию "перетаскивания". Компания Microsoft рекомендует применять к элементу назначения обработчики событий ondragenter, ondragover и ondrop. В каждом из них необходимо установить свойство data- Trans fer.dropEf feet равным тому эффекту, который изображается во время операции "перетаскивания" (о чем свидетельствует различный вид указателя). Эти настройки должны соответствовать свойству dataTransfer .ef fee tAl lowed, устанавливаемому в обработчике события ondragstart. В каждом из трех обработчиков событий свойство event. returnValue должно быть установлено в значение false (см. описание обработчика события ondrag ранее в этой главе). Глава 15. Основные объекты HTML-элементов 373
Пример В листинге 15.37 приведен пример использования обработчика ondrop. См. также: объект event.dataTransfer; обработчики событий ondrag, ondragend, ondragenter, ondragleave, ondragover, Ondragstart. onfiIterchange Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Событие onfilterchange происходит тогда, когда фильтр переводит элемент в новое состояние, или преобразование объекта завершается (преобразование иногда изменяется со временем). Событие может происходить только для объектов, к которым применимы фильтры и эффекты преобразования в Ш (в первую очередь, блоковые элементы и элементы управления форм). Событие onf interchange часто применяется для запуска следующего преобразования в последовательности из нескольких подобных операций. В результате может получиться бесконечный цикл, когда объект, получающий событие, переключается между двумя состояниями преобразования. Если вам не требуется такой цикл, разместите два различных типа содержимого в отдельные позиционируемые элементы и используйте обработчик события onf i Iter change для "перехода" от одного элемента к другому. Пример Ознакомиться с обработчиком onf ilterchange вы можете в листинге 15.39. В этом примере данный обработчик события позволяет выполнить второй эффект преобразования сразу после завершения первого. Несмотря на то, что обработчик события onf ilterchange поддерживается в Г£4 и DE5 практически одними и теми же объектами, свойства объекта фильтра трактуются в браузерах весьма неоднозначно. В коде, приведенном в листинге 15.39, активно используются элементы управления ActiveX, представленные в Ш5.5 (описываются в главе 30). <html> <head> <title>onfilterchange Event Handler</title> <script type="text/javascript"> function init() { imagel.filters[0].apply(); image2.fiIters[0].apply(); start(); } function start() { image1.style.visibility = "hidden"; imagel.filters[0].play(); } function finish() { if (imagel.filters[0].status == 0) { image2.style.visibility = "visible"; image2.filters [0] .playO ; </script> </head> 374 Часть III. Объекты документа
<body onload="init()M > <hl>onfilterchange Event Handler</hl> <hr /> <p>The completion of the first transition ("circle-in") triggers the second ("circle-out"). <button onclick= "location.reload() ">Play It Again</buttonx/p> <div id="imagel" style="visibility:visible; position:absolute; top:150px; left:150px; filter:progID:DXImageTransform.Microsoft. Iris(irisstyle='CIRCLE', motion='in')" onfiIterchange= "finish()"> <img alt="image" src="deskl.gif" height="90" width="120" /> </div> <div id="image2" style="visibility:hidden; position:absolute; top:150px; left:150px; filter:progID:DXImageTransform.Microsoft. Iris(irisstyle='CIRCLE', motion='out')"> <img'alt="image" src="desk3.gif" height="90" width="120" /> </div> </body> </html> См. также: объект filter. onfocus Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Событие onfocus происходит тогда, когда элемент активизируется; как правило, в этот момент деактивизируется другой элемент. (Элемент, который становится неактивным, получает событие onblur до того, как текущий элемент получает событие onfocus.) Например, элемент ввода текста запускает событие onfocus, когда пользователь переходит к этому элементу с помощью клавиши <ТаЬ>. К такому же эффекту приводит щелчок мышью на элементе. Свойства события onfocus были расширены в связи с появлением новых поколений браузеров, поддерживающих языки написания сценариев. В ранних версиях деактивизация и активизация были ограничены лишь элементами ввода текста (включая и элемент select). У объекта window обработчик события onfocus появился, начиная с NN3 и Ш4. В Ш4 область его применения стала охватывать и другие элементы форм, в основном, в операционной системе Windows, поскольку пользовательский интерфейс именно этой ОС позволяет выделять пунктирным прямоугольником такие элементы, как кнопки и ссылки (после чего их можно активизировать нажатием клавиши пробела). В ЕЕ5 обработчик события onfocus имеют почти все элементы HTML. Тем не менее, для большинства из них активизация и деактивизация не выполняется, если в дескрипторе элемента не установлен атрибут tabindex. Например, если присвоить значение tabindex^"!" в дескрипторе <р>, то пользователь сможет активизировать этот абзац (выделение пунктирным прямоугольником в Windows), щелкнув мышью или нажав клавишу <ТаЬ>. В Ш5.5 добавлен обработчик события onactivate, который запускается непосредственно перед onfocus. Можно использовать любой из них, но нет смысла включать в сценарий оба обработчика, если только вы не преследуете цель заблокировать активизацию определенных элементов. Для этого в IE5.5 в обработчик события onactivate необходимо включить оператор event.returnValue=false. В ранних версиях браузеров достаточно создать следующий обработчик события для элементов управления форм: onfocus="this.blur () ". Однако этого недостаточно, чтобы не допустить изменения управляющих настроек пользователем. К сожалению, альтернативы этому нет. Глава 15. Основные объекты HTML-элементов 375
Пример Пример использования обработчика onfocus приведен в листинге 15.34 ранее в этой главе (при рассмотрении обработчика onblur). См. также: обработчики событий onactivate, onblur, ondeactivate. onhelp Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Обработчик события onhelp в Windows запускается для активного элемента, когда пользователь нажимает на клавиатуре функциональную клавишу. В МасШ5 это событие происходит только для окна (другими словами, обработчик события должен быть указан в дескрипторе <BODY>) при нажатии клавиши <Не1р> на клавиатуре компьютера Macintosh. Опции меню Help в браузере не активизируют этого события. Чтобы не допустить появления на экране окна справочной системы браузера, обработчик события должен возвратить значение false (в IE4+) или установить свойство event. returnValue равным false (й Ш5+). Поскольку обработчик события в версии для Windows можно включить в любой отдельный элемент страницы, он часто используется для создания контекстной справочной системы. Если же активно поле адреса или само окно браузера, то сценарий не может перехватить событие — в таких случаях появляется стандартное окно справочной системы браузера. Пример В листинге 15.40 продемонстрирован пример контекстно-зависимой справочной системы. В этом приложении справочные сведения приводятся для данных, вводимых в текстовые поля. При установке курсора в поле над ним появляется надпись-подсказка, которая указывает на то, что справочные сведения отображаются при нажатии клавиши <F1>. ' * "' * . ? <html> <head> <title>onhelp Event Handler</title> <script type="text/javascript"> function showNaraeHelp() { alert("Enter your first and last names."); event.cancelBubble = true; return false; function showYOBHelpO { alert("Enter the four-digit year of your birth. For example: 1972"); event.cancelBubble = true; return false; } function showGenericHelp() { alert("All fields are required."); event.cancelBubble = true; return false; function showLegendO { document.getElementById("legend").style.visibility = "visible"; } function hideLegendO { 376 Часть III. Объекты документ!
document.getElementById("legend").style.visibility = "hidden"; } function init() { var msg = ""; if (navigator.userAgent.indexOf("Mac") != -1) { msg = "Press \'help\' key for help."; } else if (navigator.userAgent.indexOf("Win") != -1) { msg = "Press Fl for help."; } document.getElementByld("legend").style.visibility = "hidden"; document.getElementByld("legend").innerHTML = msg; } </script> </head> <body onload="init()" onhelp="return showGenericHelp()"> <hl>onhelp Event Handler</hl> <hr /> <p id="legend" style="visibility:hidden; font-size:10px"> &nbsp;</p> <form> Name: <input type="text" name="name" size="30" onfocus="showLegend()" onblur="hideLegend()" onhelp="return showNameHelpO " /><br /> Year of Birth: <input type="text" name="YOB" size*"30" onfocus ="showLegend()" onblur="hideLegend()" onhelp="return showYOBHelp()" /> </form> </body> </html> См. также: методы window. showHelp (), window. showModalDialog (). onkeydown onkeypress onkeyup Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ При нажатии клавиши на клавиатуре происходит последовательность трех событий. При нажатии клавиши происходит событие onkeydown; за ним следует onkeypress, а при отпускании клавиши — событие onkeyup. Если клавиша остается нажатой и символ вводится повторно автоматически, события onkeydown и onkeypress происходят при вводе каждого последующего символа. Последовательность событий имеет важное значение при обработке некоторых событий клавиатуры. Рассмотрим сценарий, в котором автоматически и последовательно активизируются текстовые поля в процессе введения пользователем заданного количества символов (например, числа, месяца и года). К моменту, когда происходит событие onkeyup, символ уже добавляется к содержимому поля — это позволяет гарантировано узнать длину текста в нем. <html> <head> <script type="text/javascript"> function jumpNext(fromFld, toFld) { if (fromFld.value.length ==2) { document.forms[0].elements[toFld].focus(); Глава 15. Основные объекты HTML-элементов 377
document.forms[0].elements[toFld].select(); } } </script> </head> <body> <form> Month: <input name="month" type="text" size="3" value="" onkeyup="jumpNext(this, day)" maxlength="2" /> Day: <input name ="day" type="text" size="3" value="" onkeyup ="jumpNext(this, year)" maxlength="2" /> Year: <input name="year" type="text" size="3" value="" onkeyup ="jumpNext(this, month)" maxlength="2" /> </form> </body> </html> Три этих события происходят не для всех клавиш на обычной клавиатуре в браузерах, поддерживающих события клавиатуры. Клавиши, для которых такие события происходят во всех браузерах, — это буквенно-цифровые клавиши, имеющие ASCII-коды (пробел и <Entei>), к ним не относятся функциональные клавиши, клавиши со стрелками и другие средства навигации. Клавиши-модификаторы— <Shift>, <Ctrl>, <Alt>— генерируют свои собственные события (в зависимости от типа и версии браузера). Состояние этих клавиш-модификаторов можно проверить в функциях, запускаемых для других событий клавиш. Обработчик onkeydown поддерживается Mozilla-совместимыми браузерами (поколения старше Mozilla 1.4 (NN7.1)). Программирование обработки событий клавиатуры, как правило, означает проверку нажатия клавиши. Ситуация усложняется, если сценарий должен выполняться в различных типах браузеров. В некоторых случаях написание сценариев только для браузера Internet Explorer может оказаться непростой задачей, поскольку небуквенно-цифровые клавиши генерируют только события onkeydown и onkeyup. Чтобы полностью обрабатывать события клавиатуры, необходимо различать коды клавиш и коды символов. Каждая клавиша на клавиатуре имеет свой код. Этот код постоянный, он не зависит от одновременно нажатых клавиш. Буквенно-цифровые клавиши (буквы, цифры, пробел и т.д.) генерируют также и коды символов. Эти коды представляют символы, связанные с клавишами. Их значение изменяется при нажатии клавиши-модификатора. Например, если отдельно нажать клавишу <А>, то она сгенерирует символ нижнего регистра "а" (код 97); если при этом держать нажатой клавишу <Shift>, она сгенерирует символ "А" (код 65). Код самой клавиши (65 для клавиатур западных языков (Western)) остается постоянным. Информация о кодах клавиш сохраняется в свойствах объекта event. Объект event в Ш имеет только одно такое свойство — key Code. Оно содержит код клавиши для событий onkeydown и onkeyup, а также код символа для события onkeypress. Объект event в NN6 имеет два отдельных свойства: с ha r Code (код символа) и key с ode (код клавиши) (примеры использования этих свойств объекта event см. в главе 25). Если требуется обработать не буквенно-цифровые клавиши (например, функциональные клавиши, клавиши навигации и т.д.), следует использовать обработчик события onkeydown или onkeyup. Для обработки тех символов, которые отображаются в текстовых полях, достаточно применить обработчик события onkeypress. Поэкспериментировать с событиями и кодами можно в листинге 15.41, а также примерах из главы 25. 378 Часть III. Объекты документа
Распространенные задачи по обработке событий клавиатуры IE4+ (но не NN) позволяет изменить символ, вводимый пользователем в текстовом поле. Обработчик события onkeypress модифицирует свойство event. keyCode, причем событие продолжается дальше обычным образом (другими словами, обработчик не возвращает false и не устанавливает свойство event. ret urnValue равным false). Следующая функция IE (вызываемая обработчиком события onkeypress) проверяет, чтобы текст, вводимый в поле, принадлежал верхнему регистру, даже если пользователь пытается ввести символ нижнего регистра. function assureUpper () { if (event.charCode >= 97 && event.charCode <= 122) { event.charCode = event.charCode — 32; Подобная операция может запугать пользователей, поэтому тщательно проанализируйте ее. Чтобы символ, введенный с помощью клавиатуры, не появлялся сразу же в текстовом поле, обработчик события onkeypress должен отменить действие по умолчанию. Например, следующий HTML-код (NN4+, Ш4+) позволяет вводить в текстовое поле только цифры. <html> <head> <title>Keyboard Capture</title> <script language=,,JavaScript"> function checklt(evt) { var charCode = (evt.which) ? evt.which : event.keyCode if (charCode > 31 && (charCode < 48 || charCode > 57)) { alert("Please make sure entries are numbers only."); return false; } return true; } </script> </head> <body> <form> Enter any positive integer: <input type="text" name="numeric" onKeyPress="return checklt(event)"> </form> </body> </html> При попытке ввести нецифровой символ пользователь получает предупреждение, а сам символ не появляется в текстовом поле. События клавиатуры позволяют сценарию отправить форму по нажатию клавиши <Enter>, когда курсор находится в текстовом поле. ASCII-код клавиши <Enter> равен 13. Поэтому достаточно просто проверить код каждой клавиши и отправить форму, когда появится значение 13. function checkForEnter(evt) { evt = (evt) ? evt : event; var charCode = (evt.charCode) ? evt.charCode : (( evt.which) ? evt.which : evt.keyCode); if (charCode ==13) { document.forms[0].submit(); return false; } return true; } Глава 15. Основные объекты HTML-элементов 379
Присвоение функции checkForEnter () в обработчике события onkeypress каждого текстового поля добавляет новые возможности обычной HTML-форме. В браузере Internet Explorer можно перехватывать некоторые комбинации <Си*1+клавиша (только буквы)>, но лишь в том случае, если их не использует сам браузер. Значение свойства key Code события onkeypress для комбинаций <Си*1+клавиша> находится в диапазоне от 1 до 26 для букв от А до Z (для комбинаций, используемых браузером, никаких событий не происходит). Пример Приложение, приведенное в листинге 15.41, представляет собой лабораторию по исследованию обработчиков событий клавиатуры и изучению кодов клавиш в браузерах Ш5+ и W3C. Сам код приложения не столь важен, как выполняемые им функции. Для каждой нажимаемой комбинации клавиш отображается значение свойства key Code, представляемое для событий onkeydown, onkeypress, onkeyup. Если в комбинации используется модифицирующая клавиша, то ее название выделяется для всех трех событий. При запуске этого приложения в NN6+ свойство keyCode не содержит код символа (хотя строка для его отображения пре* дусмотрена, и в самом приложении об ошибке ничего не сказано). Лучший способ увидеть, как происходят события клавиатуры, — понажимать клавиши (включая модифицирующие) и понаблюдать за выводимыми в таблице значениями. Не забудьте понажимать клавиши со стрелками. Как видите, для события onkeypress коды символов не отображаются, хотя для двух остальных событий они успешно генерируются. .JMifcliiir4tljtif'Otoattttiiaicoftiinikrtiiwiiiiiiiiii v--' 4-" <html> <head> <title>Keyboard Event Handler Lab</title> <style type="text/ess"> td {text-alignreenter} </style> <script type="text/javascript"> function init() { document.onkeydown = showKeyDown; document.onkeyup = showKeyUp; document.onkeypress = showKeyPress; } function showKeyDown(evt) { evt = (evt) ? evt : window.event; document. getElementByld ("pressKeyCode") . innerHTML = 0 ; document.getElementById("upKeyCode").innerHTML = 0; document.getElementByld("pressCharCode").innerHTML = 0; document.getElementByld("upCharCode")\innerHTML = 0; restoreModifiers(""); restoreModifiers("Down"); restoreModifiers("Up"); document.getElementByld("downKeyCode").innerHTML = evt.keyCode; if (evt.charCode) { document.getElementByld("downCharCode").innerHTML = evt.charCode; } showModifiers("Down", evt); ■■ ■■ ■"— mi 380 Часть III. Объекты докуменл
} function showKeyUp{evt) { evt = (evt) ? evt : window.event; document.getElementByld("upKeyCode").innerHTML = evt.keyCode; if (evt.charCode) { document.getElementByld("upCharCode").innerHTML = evt.charCode; } showModifiers("Up", evt); return false; } function showKeyPress(evt) { evt = (evt) ? evt : window.event; document.getElementByld("pressKeyCode").innerHTML = evt.keyCode; if (evt.charCode) { document.getElementByld("pressCharCode").innerHTML = evt.charCode; } showModifiers("", evt); return false; } function showModifiers(ext, evt) { restoreModifiers(ext); if (evt.shiftKey) { document.getElementByld("shift" + ext).style. backgroundColor = "#ff0000"; } if (evt.ctrlKey) { document.getElementByld("Ctrl" + ext).style. backgroundColor = "#00ff00"; } if (evt.altKey) { document.getElementByld("alt" + ext).style. backgroundColor = "#0000ff"; function restoreModifiers(ext) { document.getElementByld("shift" + ext).style. backgroundColor = "#ffffff"; document.getElementByld("Ctrl" + ext).style. backgroundColor = "#ffffff"; document.getElementByld("alt" + ext).style. backgroundColor = "#ffffff"; } </script> </head> <body onload="init()"> <hl>Keyboard Event Handler Lab</hl> <hr /> <form> <table border="2" cellpadding="2"> <tr> Глава 15. Основные объекты HTML-элементов 381
<thx/th> <th>onKeyDown</th> <th>onKeyPress</th> <th>onKeyUp</th> </tr> <tr> <th>Key Codes</th> ctd id="downKeyCode">0</td> <td id="pressKeyCode">0</td> <td id="upKeyCode">0</td> </tr> <tr> <th>Char Codes (IE5/Mac; NN6)</th> <td id="downCharCode">0</td> <td id="pressCharCoden>0</td> <td id="upCharCode">0</td> </tr> <tr> <th rowspan="3">Modifier Keys</th> <tdxspan id="shiftDown">Shift</spanx/td> <tdxspan id="shift">Shift</spanx/td> <tdxspan id="shiftUp">Shift</spanx/td> </tr> <tr> <tdxspan id="ctrlDown">Ctrl</spanx/td> <tdxspan id="ctrl">Ctrl</spanx/td> <tdxspan id="ctrlUp">Ctrl</spanx/td> </tr> <tr> <td><span id="altDown">Alt</spanx/td> <tdxspan id="alt">Alt</spanx/td> <tdxspan id="altUp">Alt</spanx/td> </tr> </table> </form> </body> </html> См. также: метод String. f romCharCode (). onlosecapture Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Обработчик события onlosecapture запускается тогда, когда отключается захват событий для данного объекта. Это происходит, если пользователь выполняет одно из следующих действий: ■ активизирует другое окно; ■ выводит любое системное диалоговое окно (например окно предупреждения); ■ прокручивает страницу; ■ открывает контекстное меню браузера (щелкнув правой кнопкой мыши); ■ активизирует поле адреса окна браузера, нажав клавишу <ТаЬ>. Функция, добавленная в обработчик события onlosecapture, должна производить всю необходимую "очистку данных" после отключения объектом захвата событий. 382 Часть III. Объекты документа
Пример Пример использования onlosecapture приведен ранее в листинге 15.30 (при рассмотрении сценария управления контекстным меню). С помощью этого обработчика в сценарии скрывалось контекстное меню. См. также: методы releaseCapture (), setCapture (). onmousedown onmouseup Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Обработчик события onmousedown запускается тогда, когда пользователь щелкает одной из кнопок мыши. Событие onmouseup происходит при отпускании кнопки мыши, причем объект, получивший такое событие, до этого получил также и событие onmousedown. Когда пользователь щелкает мышью на объекте, события происходят в такой последовательности: onmousedown, onmouseup, onclick. Если же пользователь нажимает кнопку, а затем перемещает указатель за пределы объекта, то происходит только событие onmousedown. В NN4 эти два события ограничены объектами button, radio button, checkbox, link и area. Данные события позволяют дизайнерам использовать широкие возможности по управлению изображениями и пиктограммами. В большинстве случаев кнопки в приложениях работают следующим образом: при нажатии кнопки мыши внешний вид кнопки на странице изменяется, а при отпускании (или перемещении указателя)— возвращается к исходному состоянию. Описанные события мыши позволяют эмулировать именно такое поведение элементов на странице. Объект события, созданный для каждого действия, имеет свойство, которое показывает, какая кнопка мыши была нажата. В модели событий NN4 это свойство называется which, ав1Е4+ и NN6/Mozl+— button (для разных кнопок оно принимает различные значения). Проверять номер кнопки мыши надежнее для событий onmousedown или onmouseup, но не для onclick, так как объект события onclick не всегда содержит информацию о нажатой кнопке мыши. Пример Для демонстрации типичного сценария ролловера (изменяющегося при наведении указателя мыши изображения) ниже приведен листинг 15.42. На соответствующей странице отображаются две небольшие навигационные кнопки (в виде стрелок). Поскольку в ШЗ и NN2 объект изображения не включается в объектную модель документа, то далеко не все браузеры корректно отображают кнопки на экране. Только браузеры, поддерживающие предварительное кэширование изображений (создающие массив document. images), можно смело использовать для выполнения этого приложения. <html> <head> <title>onmousedown and onmouseup Event Handlers</title> <script type="text/javascript"> if (document.images) { var RightNormlmg = new Image(16,16); var RightUpImg *= new Image(16,16); var RightDownlmg * new Image(16,16); Глава 15. Основные объекты HTML-элементов 383
} var LeftNormlmg = new Image(16,16); var LeftUpImg = new Image(16,16); var LeftDownlmg « new Image(16,16); RightNormlmg.src = "RightNorm.gif"; RightUpImg.src = "RightUp.gif"; RightDownlmg.src = "RightDown.gif"; LeftNormlmg.src = "LeftNorm.gif"; LeftUpImg.src = "LeftUp.gif"; LeftDownlmg.src = "LeftDown.gif"; function setImage(imgName, type) { i f (document.image s) { var imgFile = eval(imgName + type + "Img.src"); document.images[imgName].src = imgFile; return false; } } </script> </head> <body> <hl>onmousedown and onmouseup Event Handlers</hl> <hr /> <p>Roll atop and click on the buttons to see how the link event handlers swap images:</p> <center> <a href="j avascript:void(0)" onmouseover="return setImage('Left','Up')" onmousedown="return setImage('Left','Down')M onmouseup="return setImage('Left','Up')" onmouseout=" return set Image ('Left' , 'Norm') "ximg alt = " image" name="Left" src="LeftNorm.gif" height="16" width="16" border="0" /></a> &nbsp;&nbsp; <a href="javascript:void(0)" onmouseover="return setImage('Right','Up')" onmousedown="return setImage('Right','Down')" onmouseup="return setImage('Right',■Up')" onmouseout=" return setlmage ('Right' , 'Norm') "ximg alt=" image" name="Right" src="RightNorm.gif" height="16" width="16" border="0" /></a> </center> </body> </html> См. также: обработчик события onclick. onmouseenter onmouseleave Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- В Ш5.5 появилось два новых обработчика событий: onmouseenter и onmouseleave. Оба они работают так же, как onmouseover и onmouseout, соответственно. Компания Microsoft предложила лишь альтернативную терминологию. В Ш5.5 происходят и старые, и новые события (старые перед новыми). В сценариях, создаваемых сугубо для ГЕ5.5+, можно воспользоваться новой терминологией, в иных случаях необходимо придерживатьс! старых типов событий. 384 Часть III. Объекты докумет
Пример *.' Вы можете изменить листинг 15.43 так, чтобы в нем вместо onmouseover и onmouseout ^пользовались обработчики onmouseenter и onmouseleave. См. также: обработчики событий onmouseover, onmouseout. onmousemove Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safaril+ Событие onmousemove происходит тогда, когда указатель мыши перемешается по текущему объекту. При этом кнопка мьпшгне обязательно должна быть нажатой, хотя данное событие в большинстве случаев используется при "перетаскивании" элемента, особенно в NN/Mozilla, где не поддерживается обработчик события ondrag. Несмотря на то, что степень детализации этого события находится на уровне пикселей, не стоит использовать количество событий как средство измерения пройденного расстояния. В зависимости от скорости движения указателя, а также от быстродействия компьютера, событие происходит не в каждой точке, через которую проходит указатель. В NN4 обработчик события onmousemove нельзя присвоить атрибуту дескриптора элемента. Вместо этого необходимо использовать механизм захвата событий (в сценарии) для тагах объектов, как window, document или layer. Такой подход позволяет "перетаскивать" позиционируемые элементы в NN4. В ГЕ4+ и NN6+ обработчик события onmousemove можно присвоить любому элементу (хотя "перетаскивать" можно только позиционируемые элементы). При разработке страницы, где пользователи могут "перетащить" несколько элементов, обработчик события onmousemove, чаще всего присваивают объекту document, что позволяет событиям всплывать для последующей обработки. Пример В главах 39 и 56 приведены примеры использования обработчика onmousemove. См. также: обработчики событий ondrag, onmousedown, onmouseup. onmouseout onmouseover Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Событие onmouseover происходит тогда, когда указатель попадает в прямоугольную область, содержащую объект (при этом выполняется только одно событие— кроме ошибки eWinNN4, где оно происходит постоянно во время движения указателя). Событие onmouseout происходит тогда, когда указатель покидает пределы описанной области. Обычно эти события применяются для вывода вспомогательного текста об объекте в строке состояния окна, а также при смене изображений (эффект перетекания). Для изменения изображения используется обработчик события onmouseover; для возврата к обычному состоянию — onmouseout. Такие события присутствовали в объектных моделях браузеров с самого начала их возникновения, однако в ранних версиях они доступны не для всех объектов. В Ш4+ и W3C DOM данные события поддерживаются всеми объектами, отображаемыми на экране. В Ш5.5 существуют дополнительные обработчики событий— onmouseenter и onmouseleave, дублирующие onmouseover и onmouseout. Старые версии событий запускаются непосредственно перед новыми. А Обработчик события onmouseout обычно не запускается, если событие добав- тшвщ лено к элементу, находящемуся у края фрейма или окна, а пользователь доста- ,,*<''' точно быстро перемещает указатель за пределы текущего фрейма. Глава 15. Основные объекты HTML-элементов 385
Пример На странице, представленной листингом 15.43, приведено предложение с четырьмя ссылками, на примере которых рассматриваются обработчики onmouseover и onmouseout. Каждая ссылка при активизации запускает функцию общего назначения, которая отображает сообщение в строке состояния. <html> <head> <title>onmouseover and onmouseout Event Handlers</title> <script type="text/javascript"> function setStatus(msg) { status = msg; return true; } function emulate() { alert("Not going there in this demo."); } </script> </head> <body> <hl>onmouseover and onmouseout Event Handlers</hl> <hr /> <hl>Pledge of Allegiance</hl> <hr /> I pledge <a href="javascript:emulate()" onmouseover="return setStatus('View dictionary definition')" onmouseout="return setStatus('')">allegiance</a> to the <a href="javascript:emulate()" onmouseover="return setStatus('Learn about the U.S. flag (http://lcweb.loc.gov)!)" onmouseout="return setStatus('')">flag</a> of the <a href-"j avascript:emulate()" onmouseover="return setStatus('View info about the U.S. government')" onmouseout="return setStatus('')">United States of America</a>, and to the Republic for which it stands, one nation <a href= "j avascript:emulate()" onmouseover="return setStatus('Read about the history of this phrase in the Pledge')" onmouseout="return setStatus('')">under God</a>, indivisible, with liberty and justice for all. </body> </html> См, также: обработчики событий onmouseenter, onmouseleave, onmousemove. onpaste Совместимость: WihIE5+, MacIE-, NN-, Moz-, Safari- Возникает сразу же после того, как пользователь или сценарий инициирует операцию вешки для текущего объекта. Ему предшествует событие onbef orepaste, которое запускается » 386 Часть III. Объекты докуют
того, как выбирается опция Paste меню Edit или соответствующий пункт контекстного меню (а также непосредственно до вставки, если она осуществляется нажатием комбинации клавиш). Обработчик события используется для добавления новых возможностей редактирования тем элементам, которые обычно не позволяют производить вставку. В этом случае необходимо сделать активной опцию Paste контекстного меню или меню Edit, установив свойство event. re turnValue для обработчика события onbeforepaste равным false. Затем обработчик события onpaste должен извлечь данные из буфера обмена (методом getData () объекта clipboardData) и вставить в текущий объект. Поскольку за то, какие данные сохраняются в буфере обмена, отвечает сценарий, вы не ограничены прямым копированием данных. Поэтому можно, например, сохранить значение свойства src объекта изображения для его последующей вставки в указанном месте страницы. Пример В листинге 15.44 продемонстрировано использование обработчиков onmouseout и onmouseover (совместно с обработчиками onbef огесору и опсору) для управления операцией передачи данных при копировании и вставке информации. В таблице страницы содержатся копируемые данные (столбец существительных и столбец прилагательных). Скопированные данные вставляются в пустые части приложения. Обработчики onbef огесору и опсору назначены элементу table, поскольку события элемента td всплывают к контейнеру table. Нижнее предложение содержит два пустых элемента span. Чтобы вставить в них текст, пользователь должен сначала выделить хотя бы один символ "пустого" места. (В листинге 15.37 приведена версия этого приложения для событий перетаскивания.) Обработчик onbeforepaste предложения устанавливает свойство event. re turnValue в значение false. Таким образом команда вставки становится доступной для выполнения (по умолчанию она отключена). При вставке свойство innerHTML целевого объекта span приравнивается к текстовым данным, которые сохранены в буфере обмена. <html> <head> <title>onbeforepaste and onpaste Event Handlers</title> <style type="text/ess"> td (text-alignreenter} th {text-decoration:underline} .blanks {text-decoration:underline} </style> <script type="text/javascript"> function select-Whole () { var obj = window.event.srcElement; var range = document.body.createTextRange(); range.moveToElementText(obj); range.select(); event.returnValue = false; function handleCopyO { var rng = document.selection.createRange(); clipboardData.setData("Text",rng.text); event.returnValue = false; } function handlePaste() { var elem = window.event.srcElement; Глава 15. Основные объекты HTML-элементов 387
if (elem.className == "blanks") { elem.innerHTML = clipboardData.getData("Text"); } event.returnValue = false; function handleBeforePaste() { var elem = window.event.srcElement; if (elem.className == "blanks") { event.returnValue = false; } } </script> </head> <body> <hl>onbeforepaste and onpaste Event Handlers</hi> <hr /> <p>Your goal is to copy and paste one noun and one adjective from the following table into the blanks of the sentence. Select a word from the table and copy it to the clipboard. Select one or more spaces of the blanks in the sentence and choose Paste to replace the blank with the clipboard contents.</p> <table cellpadding="5" onbeforecopy="selectWhole()" oncopy="handleCopy()"> <tr> <th>Nouns</th> <th>Adjectives</th> </tr> <tr> <td>truck</td> <td>round</td> </tr> <tr> <td>doll</td> <td>red</td> </tr> <tr> <td>ball</td> <td>pretty</td> </tr> </table> <p id="myP" onbeforepaste="handleBeforePaste()" onpaste="handlePaste()"> Pat said, "Oh my, the <span id="blankl" сlass="blanks">&nbsp;fcnbsp;fcnbsp; &nbsp;&nbsp;</span> is so <span id="blank2" class= "blanks">&nbsp;&nbsp;fcnbsp;fcnbsp;fcnbsp;</span>I"</p> <button onclick="location.reload()">Reset</button> </body> </html> См. также: обработчики событий oncopy, oncut, onbef orepaste. onpropertychange Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Событие onpropertychange происходит в ТЕ5+ для Windows, когда сценарий изменяет какое-либо свойство объекта. Это относится и к стилю объекта. Изменение свойств методом setAttribute () также запускает данное событие. 388 Часть III. Объекты документ*
Свойство event .propertyName содержит имя (в строковом формате) свойства, которое было изменено. В случае изменения объекта style текущего объекта значение event, proper tyName начинается с префикса "style.", например style, backg- roundcolor. Обработчик данного события применяется для последующей обработки измененных свойств объекта. Вместо того, чтобы вносить операторы внутрь функции, изменяющей свойства, их можно вынести в отдельную функцию общего характера (например, для изменения свойств нескольких объектов). Пример В листинге 15.45 приведен пример использования обработчика onpropertychange. В нем показано, как запрограммировать ответную реакцию на изменение свойств объекта. Соответствующая страница содержит четыре переключателя, которые изменяют свойства innerHTML и style. color абзаца. Обработчик onpropertychange вызывает функцию showChange (), которая извлекает информацию о событии и отображает сведения в строке состояния окна. <html> <head> <title>onpropertychange Event Handler</title> <script type="text/javascript"> function normalTextO { myP.innerText = "This is a sample paragraph."; } function shortTextO { myP.innerText = "Short stuff."; } function normalColor() { myP.style.color = "black"; } function hotColorO { myP.style.color = "red"; } function showChange() { var objID * event.srcElement.id; var propName = event.propertyName; var newValue = eval(objID + "." + propName); status = "The " + propName + " property of the " +-objID; status += " object has changed to \"" + newValue + "\"."; } </script> </head> <body> <hl>onpropertychange Event Handler</hi> <hr /> <p id="myP" onpropertychange="showChange()">This is a sample paragraph.</p> <form> Text: <input type="radio" name="btnl" checked="checked" onclick="normalText()" />Normal <input type="radio" name="btnl" onclick="shortText0" />Short<br /> Color: <input type="radio" name="btn2" checked="checked" onclick="normalColor()" />Black <input type="radio" Глава 15. Основные объекты HTML-элементов 389
name="btn2" onclick="hotColor()" />Red </form> </body> </html> См. также: свойство style; метод set At tribute (). onreadys tatechange Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Обработчик события onreadystatechange запускается тогда, когда изменяется состояние загрузки элемента. Подробнее об этом рассказывалось при обсуждении свойства readyState ранее в этой главе (обратите внимание на ограничения для Ш4). Изменение состояния еще не гарантирует, что сценарий может прочесть свойства объекта. В каждом сценарии, где используется обработчик события onreadystatechange, необходимо всегда проверять свойство readyState объекта. Событие происходит для объектов, способных загружать данные: applet, document, frame, frameset, iframe, img, link, object, script и xml. Для других типов объектов событие происходит только в том случае, если им определено поведение DHTML. Событие onreadystatechange не всплывает, и его нельзя отменить. См. также: свойство readyState. onresize Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Обработчик события onresize запускается при изменении размеров объекта в ответ на действия пользователя или сценария. Почти все элементы, обладающие содержимым, имеют данный обработчик события при условии, что ^объекте существуют пространственные атрибуты (например, высота, ширина или координаты положения). В Ш4+ и NN6+/Mozl+ событие onresize не всплывает. Изменение размеров окна браузера или фрейма не запускает обработчик события onload. Пример При желании вы можете захватывать события изменения пользователем размера окна (фрейма) браузера. Обработчику событий в сценарии обычно назначается функция. window.onresize = handleResize; Эта же операция выполняется и в коде HTML. <body onresize="handleResize()"> См. также: метод window, resize (). onresizeend onresizestart Совместимость: Winffi5.5+, Macffi-, NN-, Moz-, Safari- Обработчики событий onresizeend и onresizestart запускаются в режиме редактирования Windows только для тех объектов, изменение которых возможно. Как отмечалось при обсуждении обработчика события oncontrolselect, компания Microsoft еще не предоставила подходящего описания или примера. См. также: обработчик события oncontrolselect. 390 Часть III. Объекты документ»
onselectstart Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Обработчик события onselectstart запускается тогда, когда пользователь начинает выделять содержимое страницы. Последним может быть текст страницы, изображение или текст внутри поля. Если пользователь выделяет несколько объектов, то событие происходит для первого из них. Пример Используйте страницу из листинга 15.46 изучения обработчика onselectstart. Как только пользователь начнет выделять данные на странице, в строке состояния отобразится идентификатор объекта, принимающего событие. Обратите внимание на то, что событие не возникает до тех пор, пока вы полностью не выделите элемент. Если ни один объект не располагается под указателем, то событие принимает объект body. <html> <head> <title>onselectstart Event Handler</title> <style type="text/ess"> td {text-align:center} </style> <script type="text/javascript"> function showObj() { var objID = event.srcElement.id; status = "Selection started with object: " + objID; </script> </head> <body id="myBody" onselectstart="showObj()"> <hl id="myHl"> onselectstart Event Handler </hl> <hr id="myHR" /> <p id="myP">This is a sample paragraph.</p> <table border="l"> <tr id="rowl"> <th id="headerl">Column A</th> <th id="header2">Column B<;/th> <th id="header3">Column C</th> </tr> <tr id="row2"> <td id=McellA2">text</td> <td id=McellB2">text</td> <td id="cellC2">text</td> </tr> <tr id="row3"> <td id=,,cellA3">text</td> <td id=,,cellB3">text</td> <td id="cellC3">text</td> </tr> </table> </body> </html> См. также: обработчик события onselect для различных объектов. Глава 15. Основные объекты HTML-элементов 391
Объекты window и frame II II иаграмма объектной модели документа в главе 14 fp«i] (рис. 14.1) показывает, что объект window является внешним глобальным контейнером всех объектов документа, используемых в сценариях JavaScript. Все операции HTML и JavaScript осуществляются в пределах окна. Им может быть стандартное окно приложения Windows, Mac или XWindows, содержащее полосы прокрутки, панели инструментов и другие элементы; или же созданное вами окно без некоторых обычных средств. Фрейм также является окном, хотя он и не имеет дополнительных элементов, кроме полос прокрутки. Все ссылки JavaScript начинаются с объекта window. Браузеры Ш4+, NN64 и W3C трактуют набор фреймов как специальный тип объекта window, поэтому о нем тоже рассказано в этой главе. Из всех объектов браузера, доступных при создании сценариев, не только window, но все связанные с ним элементы обладают объектно-специфическими средствами. Чтобы работа с такими объектами стала более понятной, в этой главе приведено немало вспомогательной информации. Терминология При первом знакомстве с объектной моделью документа объект window кажется очень странным и непонятным. Чего стоит только количество синонимов объектов window: top, self, parent и frame. Ухудшает ситуацию еще и то, что эти термины являются свойствами объекта window. В некоторых случаях окно является родительским для самого себя, но если определить набор из двух фреймов, то из трех объектов window только один будет родительским. При работе с такими объектами несложно и запутаться. Если вы не используете фреймы, то никогда не столкнетесь с большинством проблем, однако, если они составляют. часть дизайна вашего проекта, то вы должны знать, как они влияют на объектную модель документа.
Фреймы Вопрос применения является неоднозначным среди Web-дизайнеров: одни разработчики горячо выступают за их применение, другие — так же горячо против. Я считаю, что иногда без фреймов просто не обойтись. Например, если документ достаточно велик и требует прокрутки при просмотре его содержимого, желательно, чтобы элементы навигации все время находились в видимой области окна. Размещение таких элементов (ссылок или карт изображений) в отдельном фрейме делает их всегда доступными, независимо от состояния основного документа. Создание фреймов На создание фреймов в документе не влияет использование JavaScript. Простейший документ с набором фреймов выглядит следующим образом. <html> <?iead> <title>My Frameset</title> </head> <frameset> , <frame namej=" Frame 1" src="document1.html"> < frame name="Frame2" s г с = "document 2.html"> </frameset> </html> Приведенный HTML-документ (он не отображается для пользователя) определяет набор фреймов. Каждый из них должен содержать URL (заданный атрибутом src) документа, загружаемого во фрейм. Присвоение имени каждому фрейму с помощью атрибута name упрощает написание сценариев. Объектная модель фрейма Window Document Возможно, ключом к успешному созданию сценариев, работающих с фреймами, является понимание того, как объектная модель документа выглядит в памяти, отведенной для браузера, в определенный момент времени. Схематические структуры, приведенные в этой книге (рис. 16.1), не отображают точную объектную модель документа или набора документов. Для одного документа без фреймов объектная модель состоит из единственного объекта window, в котором содержится документ (рис. 16.1). В такой простой структуре объект window является начальной точкой для ссылок на любой загруженный объект. Поскольку окно всегда присутствует (чтобы мог быть загружен и представлен документ), в ссылках на объекты в документе объект текущего окна можно не указывать. В простой модели с двумя фреймами (рис. 16.2) браузер трактует контейнер исходного документа как родительское окно. Единственным сви- детельством того, что документ, задающий набор фреймов, существует, ис1 рос' / w r -er •> j j у теишее взаимоот- служит его заголовок, отображаемый в строке заголовка браузера. ношение "окно-до- Каждый дескриптор < frame > внутри набора < frameset > создает свой кумент » объект window, в который загружается соответствующий документ. Каждому фрейму соответствует свой объект document. Документ сам по себе имеет единственный контейнер, как и в модели, приведенной на рис. 16.1. Родительский объект не виден пользователю, однако он все равно присутствует в объектной модели. Его удобно использовать для хранения данных, применяемых в дочерних фреймах, или загрузки различных документов в них. Глава 16. Объекты window и frame 393
<frame> <frar ле> Top, Parent Дочерний фрейм Document <fra me> Дочерний фрейм Document Рис. 16.2. Родительское окно и фреймы являются частью объектной модели В более сложных конструкциях, как, например, на рис. 16.3, дочерний фрейм сам может содержать документ с набором фреймов. В таких случаях проявляется разница между объектами parent и top. Верхнее (top) окно является общим для всех фреймов на рис. 16.3. Как мы скоро увидим, при взаимодействии одних фреймов с другими (и документов в них), ссылки на дальние объекты начинаются с общего для всех фреймов объекта window. <frame> <frame> Top, Parent Дочерний фрейм Document <fram <frame> Дочерний фрейм, Parent | е> Дочерний фрейм I <f rame> Дочерний фрейм Document Document Рис. 16.3. Три поколения объектов окон Ссылки на фреймы Ссылки на объекты необходимы JavaScript, чтобы найти требуемый объект в объектной модели, находящейся в данный момент в памяти браузера. Ссылка представляет собой "карту", в соответствии с которой браузер ведет поиск (например, чтобы узнать значение некоторого текстового поля в определенном документе). Поэтому при создании ссылки необходимо четко представлять, где в объектной модели находится сценарий и как ссылка определяет самый далекий от исходного объект. В случае объектов двух поколений (рис. 16.2) возможны три типа отношений. 394 Часть ///. Объекты документа
■ Родительско-дочерние. ■ Дочерне-родительские. ■ Дочерне-дочерние. Для доступа к объекту, функции или переменной используются следующие ссылки. ■ имяФрейма. имяОбъ екта ПеременнойФункции ■ parent. имяОбъектаПеременнойФункции ■ parent.имяФрейма. имяОбъектаПеременнойФункции Помните: если ссылка указывает на другой фрейм, она должна начинаться с объекта window, общего для обоих фреймов. Рассмотрим этот принцип на примере сложной модели (рис. 16.3): . если документ из левого дочернего фрейма ссылается на правый нижний фрейм, то структура ссылки будет следующей. top.имяФрейма.имяФрейма.документ. ... Ссылка начинается с верхнего (top) объекта window через два фрейма к искомому документу. JavaScript следует именно по такому маршруту. Объект top против объекта parent У читателей может возникнуть вопрос: почему бы не использовать объект top для всех ссылок? Для объектной модели, такой подход вполне оправдан: родительским объектом в структуре из двух поколений является также и верхнее окно. Тем не менее, документ, задающий набор фреймов, не всегда является объектом top в "чужом" браузере. Представьте, например, Web-узел, загружающий другие Web-узлы в свои фреймы. В такой ситуации объект top является другим. Ссылки, построенные через него, или не будут работать, или приведут к ошибкам в сценарии. Поэтому рекомендуется использовать объект parent, когда речь идет о поколении, предыдущем по отношению к текущему документу. Предотвращение использования фреймов Ссылками top и parent можно воспользоваться для того, чтобы не допустить отображение вашего Web-узла внутри набора фреймов другого узла. Для этого необходимо, чтобы документ верхнего уровня просто проверял, в какое окно он загружен (это должно быть верхнее (top) или родительское (parent) окно). Когда документ находится в таком окне, ссылка на свойство top совпадает со ссылкой на текущее окно (в данном случае используется синоним объекта window— self). Если два значения не совпадают, то сценарий загружает документ заново, но уже в окно верхнего уровня. Сценарий, выполняющий эти действия, приведен в 16.1 (его следует разместить в начале документа). <script type="text/javascript" > if (top != self) { top.location = location; } </script> В начале документ может загружаться внутрь фрейма, но затем (после выполнения сценария) он станет документом самого верхнего уровня в окне браузера. Глава 16. Объекты window и frame 395
Проверка загрузки фреймов При разработке Web-приложения иногда необходимо убедиться, что страница загружает полный набор фреймов. Рассмотрим, например, следующую возможность: посетитель Web-узла добавляет в список закладок только один из фреймов. При следующем посещении в браузере отображается документ только из одного фрейма. Вполне вероятно, что меню навигации при этом находится в другом фрейме набора, который в данной ситуации загружается не полностью. Сценарий может проверить, загружается ли страница в своем наборе фреймов (сравнивается URL окон topnself). Если они совпадают, для страницы необходимо загрузить набор фреймов. Простая версия этого сценария, загружающая необходимый набор фреймов, показана в листинге 16.2. В сценарий включен специальный код для NN4, не допускающий отображение отдельного фрейма. (NN4 для Windows и Unix загружает страницу в отдельном скрытом окне и запускает ее сценарии.) Чтобы получить более полную реализацию этого сценария, в котором набору передается параметр, определяющий открытие страницы в одном из фреймов, обратитесь к свойству location. search, описанному в главе 17. cscript type="text/javascript"> var isNav4 = (navigator.appName == "Netscape" && parselnt(navigator.appVersion) == 4); if (top.location.href == window.location.href) { if (isNav4) { if (window.innerWidth != 0) { top.location.href = "myFrameset.html"; } } else { top.location.href = " myFrameset.html"; </script> Включение и отключение фреймов Некоторые Web-узлы по умолчанию загружают свое содержимое в набор фреймов, но предлагают пользователю возможность их отключения. Только браузеры ГЕ4+ и W3C позволяют на ходу изменять свойства cols и rows набора, эмулируя этим добавление или удаление фреймов в текущем окне (см. объект элемента frameset далее в этой главе). В других браузерах нельзя динамически изменить структуру набора фреймов после загрузки страницы, но можно загрузить содержимое начальной страницы в основное окно. Для этого следует добавить кнопку или ссылку, загружающую документ в окно объекта top. top.location.href = "mainBody.html"; Переход обратно к многофреймовой версии реализуется только в результате перезагрузки исходного документа (набора фреймов). Наследование Разработчики сценариев, имеющие опыт в объектно-ориентированном программировании, вероятно, ожидают, что фреймы наследуют свойства, методы, функции и переменные' родительского объекта. Тем не менее, именно этого и не обеспечивают браузеры. Доступ 396 Часть III. Объекты докуменп
к элементам родительского объекта все же возможен, но по полной ссылке. Например, виртуальная функция из родительского документа доступна всем фреймам по следующей ссылке. parent. myFunc () Ей можно передать аргументы и получить возвращаемое* значение. Синхронизация фреймов Серьезной проблемой при написании сценариев становится то, что включение сценариев в многофреймовый документ опасно и даже приводит к сбоям в отдельных браузерах. Такие сценарии полагаются на наличие документов во фреймах, однако, если фреймы предварительно не созданы, а их документы — не загружены, сценарии приведут или к ошибкам, или к сбою. Один из способов обойти проблему заключается в запуске всех сценариев в обработчике события onload. Теоретически этот обработчик не запускается, если все документы не были успешно загружены во все фреймы набора. К сожалению, ГЕ4+ для Windows содержит ошибку— событие onload запускается даже в том случае, если загрузка была прервана щелчком на кнопке Stop или нажатием клавиши <Esc>. В то же время необходимо проявить особую осторожность, задавая обработчик события onload в документах отдельных фреймов. Если сценарий полагается на присутствие документа в другом фрейме (например сестринском), он, скорее всего, будет выполняться с ошибками. Многие причины (начиная с низкопроизводительной Сети или сервера и заканчивая ненадежным модемом) могут привести к неверному порядку загрузки документов во фреймах. Одним из способов обойти проблемы является создание переменной логического типа в родительском документе, состояние которой отражает состояние необходимого фрейма. После загрузки документа его обработчик события onload устанавливает флажок в значение true. Все сценарии, обрабатывающие содержимое фрейма, должны использовать оператор if для проверки значения этой переменной. Несмотря на серьезную ошибку в Ш4+, описанную выше, рекомендуется запрограммировать запуск всех сценариев по событию onload родительского документа. Зависимость от других фреймов — достаточно сложная проблема, однако чем старше версия браузера, тем меньше риск. Пустые фреймы Вы часто будете создавать фреймы в наборе, не помещая в них каких-либо документов до тех пор, пока пользователь не начнет взаимодействовать с элементами управления в других фреймах. NN и последние версии ТЕ поддерживают элемент пустого документа, имеющий внутренний URL (about: blank). Но в NN2 и NN3 для Macintosh при его "отображении" выводится специальное сообщение. Кроме того, этот URL доступен не во всех браузерах. Поэтому, когда требуется создать пустой фрейм, необходимо включить HTML-документ общего вида непосредственно во фрейм, используя атрибут src, как показано в листинге 16.3. Загрузка "пустого" HTML-документа не требует никаких дополнительных операций. Рршг 1ЬЗ. Создание пустого фр^ ' " 3ЩЩЩЩ/Ш <html> <head> ocript type="text/javascript"> <!-- function blank() { return "<html></html>"; } Глава 16. Объекты window и frame 397
</script> </head> <frameset> <frame name= ••FrameIй src="someURL.html"> <frame name= "Frame2" src="javascript:parent.blank()"> </frameset> </html> Просмотр исходного кода фрейма Знакомство с работами других программистов — одно из лучших средств изучения JavaScript (и любого другого языка программирования). В большинстве браузеров, поддерживающих сценарии, можно легко просмотреть исходный код документа фрейма, даже если он частично или полностью генерируется на JavaScript. Щелкните на фрейме, чтобы активизировать его (в некоторых браузерах он выделяется рамкой, в других — нет). Затем выберите пункт Frame Source (Исходный код фрейма) (или его эквивалент) в меню View (Вид) (или в контекстном меню, вызываемом щелчком правой кнопкой мыши). Выбранный фрейм можно также распечатать или сохранить в виде отдельного файла. Фреймы и элементы frame С расширением объектных моделей, когда почти все элементы HTML стали доступны сценариям (браузеры Ш4+ и W3C DOM), возникло несоответствие в терминологии. Все, что рассказывалось о фреймах в этой главе, относится к исходной объектной модели, где фрейм является отдельным типом окна, причем разница заключается лишь в создании ссылок на объекты. Это справедливо даже для последних версий браузеров. Тем не менее, элемент frame отличается от объекта фрейма исходной модели. Элемент frame представляет собой объект, свойства которого определяются атрибутами дескриптора <f rame>. Они предоставляют доступ в сценарии к таким параметрам, как границы фрейма и полосы прокрутки, — свойствам, не присущим исходному объекту фрейма. Ссылки на фрейм и элемент frame также различны. Ранее в этой главе было приведено немало примеров того, как необходимо создавать ссылки на фреймы старым способом. Доступ к объекту элемента frame осуществляется с помощью атрибута id или родительско- дочерних ссылок в элементе frameset (свойством parentNode для перехода к элементу frame, содержащему документ, воспользоваться нельзя). Я предпочитаю присваивать значение атрибуту ID дескриптора <f rame> и осуществлять доступ к элементу frame с помощью объекта document, находящегося в родительском (parent) (или верхнем (top)) окне иерархической структуры набора фреймов. Поэтому для доступа к свойству frameBorder элемента frame используется следующий синтаксис parent. document. all. идентификаторФрейма1. frameBorder или в ГЕ5+, NN6+ и W3C DOM. parent. document. getElementByld (■' идентификаторФрейма1") . frameBorder Когда ссылка задается с помощью элемента frame, доступ к документу, содержащемуся во фрейме, невозможен. 398 Часть III. Объекты документа
Объект window Свойства Методы Обработчики событий аррСоге client Information clipboardData closed components [] controllers [] crypto defaultStatus dialogArgument s dialogHeight dialogLeft dialogTop dialogWidth directories document event external frameElement frames [] history innerHeight innerWidth length loading location locationbar menubar name navigator offscreenBuffering opener outerHeight outerWidth pageXOffset pageYOffset parent personalbar alert() attachEvent()* back() blurO* captureEvents() clearlnterval() clearTimeout() close() confirm() createPopup() detachEvent()* disableExternalCapture() execScript() findO fireEvent()* focus()* forward() handleEvent 0 home() moveBy() moveTo() navigate() open() print () prompt() releaseEvents() resizeBy() resizeToO routeEvent() scroll() scrollByO scrollToO setActiveO * setCursor() setlnterval() setTimeout() showHelp() onabort** onafterprint onbeforeprint onbe foreunload onblur* onchange** onclick** onclose** ondragdrop onerror onfocus* onhelp onkeydown* * onkeypress** onkeyup** onload onmousedown* * onmousemove * * onmouseout** onmouseover** onmouseup** onmove onreset** onresize onscroll onselect** onsubmit** onunload Глава 16. Объекты window и frame 399
Окончание таблццы Свойства Методы "" Обработчики событий pkcsll showModalDialog() prompter showModelessDialog() returnValue sizeToContent() screen stopO screenLeft screenTop screenX screenY scrollbars scrollMaxX scrollMaxY self sidebar status toolbar top window * См. главу 15. * * Для обработки захватываемых или всплывающих событий других объектов в браузерах IE4+ UW3CDOM. Синтаксис Создание окна. var windowObject = window.open([параметры]); Доступ к свойствам и методам окна. window. свойсвтво | метод ( [параметры] ) self. свойство | метод ( [параметры] ) объектОкна . свойство \ метод ( [параметры] ) Описание объекта Объект window находится на вершине иерархии, включая даже объект document. Это высокое положение наделяет объект window рядом свойств, не доступных другим объектам. Поскольку, как правило, все происходит внутри окна, ссылку на объект window можно опустить. В предыдуидих главах методы объекта document вызывались так: document, write О. Полная ссылка выглядит следующим образом: window.document .write (). Поскольку действие происходит в окне, содержащем документ, частью которого является сценарий, окно считается частью ссылки. Для окон с одним фреймом эта концепция сильно упрощается. Как отмечалось выше, в списке свойств объекта window присутствует атрибут self. Он является синонимом самого объекта (поэтому в иерархической структуре отображается как объект)» 400 Часть ///. Объекты документе
Применение свойства, имя которого совпадает с самим объектом, может быть не совсем понятным, но такая ситуация распространена в объектно-ориентированных средах. Причины, по которым свойство self используется вместо ссылки на объект окна, обсуждаются далее. Как было показано при определении синтаксиса, в коде JavaScript не обязательно специально создавать объект window. После запуска браузер, как правило, открывает окно. Оно является полноценным объектом (даже если является пустым). Поэтому после загрузки пользователем страницы, объект window автоматически создается как часть документа, доступная для управления в сценарии. И тут мы сталкиваемся с потенциальной ловушкой: часто разработчики предполагают, что обработчики событий объекта window или значения свойств, присвоенные в сценарии, могут "пережить" документ, в котором выполняется сценарий. За исключением очевидных физических свойств окна, каждый новый документ, загружаемый в окно, обновляет свойства и обработчики окна в исходное состояние. Управление в сценарии элементами пользовательского интерфейса существующего (уже открытого) окна во многом зависит от типа и версии браузера. В браузерах до версии 4 можно изменить только строку состояния (внизу окна браузера). В IE4+ и NN4+ в режиме реального времени можно управлять такими свойствами, как размер, расположение и (в защищенных сценариях NN) отображение отдельных элементов (например, панелей инструментов и полос прокрутки). Многие свойства можно изменять только в специальных безопасных диапазонах, если сценарии криптографически защищены (см. главу 46) и/или пользователь разрешает сценариям производить такие операции. Во всех браузерах свойства окон более гибкие, когда в сценарии создается новое окно (методом window.open ()): для него изменяются размеры окна, отображаются панели инструментов, полосы прокрутки и определяются дополнительные элементы окна. Последние версии браузеров поддерживают такие настройки окна, как его положение на экране и скрытие строки заголовка. И вновь, если определенная опция может использоваться для извлечения личных данных пользователя (например, попытка скрыть окно, которое отображает действия, производимые в другом окне), то используйте защищенные сценарии. На уровне объекта window сценарий умеет отображать диалоговое окно одного из трех возможных типов (окно предупреждения, окно подтверждения типа ОК/Отмена и окно запроса данных). Несмотря на то, что диалоговые окна очень удобны для проведения отладки (см. главу 45), они могут показаться непрактичными и непривлекательным для пользователей Web-узла. Поскольку большинство диалоговых окон JavaScript являются модальными (т.е. они не позволяют производить никаких действий в основном окне браузера, а на платформе Macintosh — вообще никаких действий, пока окно не будет закрыто), попытайтесь избежать их использования. Помните, что некоторые пользователи создают макросы для посещения Web-узлов. Если при таком автоматизированном доступе появится диалоговое окно, процесс потребует обязательного вмешательства пользователя. Все диалоговые окна, генерируемые JavaScript, идентифицируют себя как "генерируемые JavaScript" (менее навязчиво в браузерах версии 4 и выше). Такое поведение, в первую очередь, вызвано необходимостью защиты данных системы: чтобы скрытые сценарии не могли создавать диалоговые окна, подобные системным, и запрашивать у пользователя личные данные. Кроме того, такой подход направлен на сокращение использования диалоговых окон в Web-дизайне. И это правильно, поскольку они обычно лишь раздражают пользователей. За исключением имеющихся только в IE модальных и безрежимных диалоговых окон (см. методы window. showModalDialog () и window. showModeless ()), обычные диалоговые окна JavaScript не позволяют использовать в них текстовые или графические элементы. В них нельзя даже изменить текст кнопок или добавить новую кнопку. В браузерах, поддерживающих DHTML, допускается использовать позиционируемые элементы div или if rame для эмуляции диалогового окна (не зависящего от типа браузера). Глава 16. Объекты window и frame 401
Свойства appCore Components[] controllers [] prompter sidebar Значения: см. текст Только для чтения Совместимость: WinlE-, МасГЕ-, NN6+, Mozl+, Safari- Браузеры NN6+/Mozilla обеспечивают сценариям доступ к различным службам из пакета xpconnect ("xp" означает "cross-platform"— не зависящий от платформы, или межплатформенный). Такие службы позволяют сценариям работать со свойствами СОМ-объектов и языка mozilla.org XUL (XML-based User Interface Language — язык пользовательского интерфейса на основе XML). Обсуждение этого вопроса выходит за рамки данной книги. Советуем обратиться к документации по NN6 и проанализировать сценарии по адресу http://www.mozilla.org/scriptable/. clientInformation Значение: объект navigator Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Чтобы обеспечить сценариям доступ к свойствам на уровне браузера и в то же время избежать упоминания конкурирующей торговой марки (Navigator), компания Microsoft разработала свойство client Information. Его значение идентично объекту navigator (он также доступен в Ш). Для совместимости различных типов браузеров следует использовать объект navigator (см. главу 38). См. также: объект navigator. с1ipboardData Значение: объект Чтение/Запись Совместимость: Winffi5+, МасГЕ-, NN-, Moz-, Safari- Объект с 1 ipboardDatа (не поддерживаемый в Мас1Е5) используется для передачи данных в таких операциях, как вырезка, копирование и вставка данных под управлением сценария. Объект содержит данные одного или нескольких типов, которые связаны с выполнением операции. Этим свойством следует пользоваться только при редактировании данных с помощью меню Edit (или комбинаций клавиш, соответствующих его опциям), а также контекстного меню, управляемого сценарием (обычно в сочетании с обработчиками событий редактирования объектов). Работа с объектом clipboardData требует знания трех методов, приведенных в табл. 16.1. Советуем также ознакомиться с обработчиками событий редактирования объектов (версиями before и after событий вырезки, копирования и вставки) (см. главу 15). Объект clipboardData нельзя использовать для обмена данными между страницами, источником которых послужили разные домены или протоколы (например http и https). 402 Часть III. Объекты документа
Метод Возвращаемое 0писание значение clearData ([format]) Отсутствует Удаляет данные из буфера обмена. Если параметр формата не указан, происходит очистка всех данных. Формат данных может включать одну или несколько ОПЦИЙ: Text, URL, File, HTML, Image GetData (format) Строка Извлекает данные указанного формата из буфера обмена. Формат имеет одно из следующих значений: Text, URL, File, HTML, Image. При получении данных очистка буфера не происходит, поэтому их можно извлекать несколькими последовательными операциями SetDat a (format, dat а) Булевого типа Сохраняет данные в буфере обмена. Формат принимает следующие значения: Text, url, File, html, image. Для нетекстовых форматов данные должны представлять собой путь или URL, указывающий на содержимое. Метод возвращает значение true, если запись данных в буфер обмена произошла успешно Пример В листинге 15.30 приведен пример использования объекта clipboardData совместно с несколькими обработчиками событий. См. также: свойство event .dataTransfer; обработчики событий onbef orecopy, onbef orecut, onbef orepaste, oncopy, oncut, onpaste. closed Значение: булевого типа Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ При создании нового окна методом window. open () часто возникает необходимость доступа к свойствам его объектов (например, для установки значения текстового поля). Доступ к новому окну осуществляется с помощью ссылки, возвращаемой методом window. open (), как показано в следующем фрагменте кода. var newWind = window.open("someURL.htmlи,"subWind"); newWind.document .entryForm.ZIP. value = •'00000" ; В данном примере переменная newWind не связана с окном "напрямую", а является лишь ссылкой на него. Если пользователь закроет окно, она все равно будет содержать ссылку на него. Поэтому любая попытка в сценарии обратиться к объекту отсутствующего окна приведет, скорее всего, к ошибке. Перед работой с элементами нового окна необходимо убедиться в том, что оно все еще открыто. Свойство closed возвращает значение true, если объект window был закрыт сценарием или пользователем. Всякий раз, когда оператор сценария выполняется после того, как у пользователя была возможность закрыть окно, обязательно проверяйте значение свойства closed. Глава 16. Объекты window и frame 403
Пример В листинге 16.4 приведен код, с помощью которого открывается и закрывается окно браузера. Сценарий начинается с инициализации глобальной переменной newWind, в которой сохраняется ссылка на объект второго окна. Эта переменная имеет глобальную область действия, поскольку доступ к ней должны иметь другие функции, выполняющие операции по управлению окном. Например, новое окно содержит HTML-код, вставляемый в него динамическим образом, а не в результате загрузки отдельного HTML-файла. Тем не менее, параметр URL метода window. open () приравнивается к пустой строке (по умолчанию). Далее следует код предоставления Ш (особенно версий 3 и 4) возможности динамического ввода в окно содержимого. После задержки (задается с помощью метода setTimeout (), описанного далее в этой главе) вызывается функция f inishNewWindows (), которая обращается к окну с помощью переменной newWind. Метод document. close () закрывает сеанс записи данных в новое окно браузера, а отдельная функция closeWindow () отвечает за закрытие подокна. В конце примера с помощью оператора if проверяется выполнение двух условий: объект window инициализирован значением null (пользователь успел щелкнуть на кнопке закрытия окна до создания его содержимого) и свойство closed окна установлено в значение null или false. Если хотя бы одно из условий выполняется, то по отношению ко второму окну выполняется метод close (). <html> <head> <title>window.closed Property</title> ocript type="text/javascript"> // инициализация глобальной переменной для объекта нового окна // этот объект доступен для всех функций страницы var newWind; // создание окна и добавление в него содержимого function newWindowO { newWind = window.open("","subwindow","height=200,width=200") ; setTimeout("finishNewWindowO", 100) ; function finishNewWindowO { var output = "" ; output += "<html><bodyxhl>A Sub-window</hl>"; output += "<formxinput type='button' value=fClose Main Window'"; output +="onclick='window.opener.close{) ' ></formx/body> </html>"; newWind.document.write(output); newWind.document.close(); } // закрытие подокна function closeWindow() { if (newWind && 1newWind.closed) { newWind.close(); </script> </head> 404 Часть III. Объекты документа
<body> <form> <input type="button" value="Open Window" onclick="newWindow() " /xbr /> <input type="button" value="Close it if Still Open" onclick="closeWindow()" /> </form> </body> ¥ </html> Чтобы завершить пример закрытия и открытия окна, в подокно была добавлена кнопка, с помощью которой можно закрыть основное окна. В современных браузерах перед выполнением последней операции на экране появится запрос на подтверждение действия. См. также: методы window. open (), window. close (). components См. аррСоге. Controllers Cm. appCore crypto pkcsll Значения: ссылка на объекты Только для чтения Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Свойства crypto и pkcsll содержат ссылки на объекты браузера, связанные с внутренними механизмами криптографии с открытым ключом (мы не будем их рассматривать в данной книге; чтобы узнать о них подробнее, обратитесь по адресу http: //www.mozilla. org/ projects/security/). defaultStatus Значение: строка Чтение/Запись Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safaril+ Когда документ будет загружен в окно или фрейм, строка состояния может отображать сообщение, за исключением случаев, когда указатель мыши находится на объекте, задающем содержимое строки состояния (например, ссылка или карта изображения). Свойство window.defaultStatus обычно содержит пустую строку, однако его можно установить равным определенному значению. Любая указанная опция временно заменяется другим значением, когда пользователь наводит указатель мыши на ссылку (о том, как установить временное сообщение в строке состояния, вы узнаете из описания свойства window. status). Чаще всего свойство window.defaultStatus устанавливают после загрузки документа в окно. Сценарий располагается непосредственно в разделе head или body документа или же запускается обработчиком события onload. Пример За исключением случаев изменения содержимого строки состояния при перемещении пользователя по Web-странице, рекомендуется выводить сообщения в нижней части окна при загрузке в нем документа. В листинге 16.5 приведен пример использования свойства Глава 16. Объекты window и frame 405
default Status для восстановления содержимого строки состояния при выполнении обработчика onmouseout. Изменение в строке состояния также выполняется при задании другого значения свойства status. <html> <head> <title>window.defaultStatus property</title> <script type="text/javascriptf,> window.defaultStatus = "Welcome to my Web site."; </script> </head> <body> <a href="http://www.microsoft.com" onmouseover="window.status = 'Visit Microsoft's Home page.'; return true" onmouseout="window.status = '■/return true">Microsoft</a> <p><a href="http://mozilla.org" onmouseover="window.status = 'Visit Mozilla\'s Home page.'; return true" onmouseout="window.status = window.defaultStatus; return true">Mozilla</ax/p> </body> </html> Если вам необходимо отобразить в строке состояния двойные или одинарные кавычки (как во второй ссылке листинга 16.5), то введите перед ними обратную косую черту (\' или \"). См. также: свойство window .status. dialogArguments Значение: различное Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство dialogArguments доступно только для окон, открытых специфическими для Г£ методами showModalDialogO или showModelessDialogO. Последние позволяют передать диалоговому окну параметр, а свойство dialogArguments обеспечивает доступ к нему сценариям диалогового окна. Значение может быть строкой, числом или массивом JavaScript (массив удобен для передачи нескольких значений). Пример Пример использования свойства dialogArguments приведен в листинге 16.39. С его помощью подставляются и извлекаются аргументы диалогового окна, отображаемого методом window.showModalDialog О . См. также: методы window. showModalDialog (), window. showModelessDialog (). dialogHeight dialogWidth Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- 406 Часть III. Объекты документ*
Сценарии документа, размещаемые внутри модального или безрежимного диалогового окна (генерируемого специфическими для Ш методами showModalDialog () или showModelessDialog ()), обладают возможностью получать или изменять высоту и ширину окна с помощью свойств dialogHeight и dialogWidth. Доступ к этим свойствам из сценариев основного окна возможен только для безрежимных диалоговых окон, которые остаются отображаемыми, когда пользователь работает в главном окне. Значения свойств задаются в виде строк и включают сокращение (рх) для единиц измерения пикселей. Пример В диалоговых окнах часто содержатся кнопки или значки, предоставляющие заинтересованным пользователям больше детальных сведений или дополнительные параметры для настройки приложения. Вы можете создать функцию переключения окна с одного размера на другой. Следующая функция предполагает использование в диалоговом окне кнопки с названием Show Details (Больше) или Hide Details (Меньше). К обработчику onclick кнопки и привязывается текущая функция. function toggleDetails(btn) { if (dialogHeight == "200px") { dialogHeight = "350px"; btn.value = "Hide Details"; } else { dialogHeight = "200px"; btn.value = "Show Details"; } } На практике вы также можете изменить свойство display со значения попе на block, чтобы убедиться в сокрытии полос прокрутки в меньшей версии диалогового окна. См. также: свойства window. dialogLef t, window. dialogTop. dialogLeft dialogTop Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Сценарии документа, размещаемые внутри модального или безрежимного диалогового окна (генерируемого специфическими для Ш методами showModalDialog О или showModelessDialog ()), имеют возможность получать или изменять координаты левого верхнего угла окна с помощью свойств dialogLeft и dialogTop. Доступ к этим свойствам из сценариев основного окна возможен только для безрежимных диалоговых окон, которые остаются отображаемыми, когда пользователь работает в главном окне. Значения свойств задаются в виде строковых данных и включают сокращение (рх) для единиц измерения пикселей. Если попытаться изменить значения так, чтобы часть окна вышла за пределы видимой области экрана, браузер автоматически откорректирует значения. Пример Хотя изменять расположение окна, размер которого был изменен с помощью сценария (или пользователем, если им предоставляется подобная возможность) не рекомендуется, хотя программно эту задачу выполнить не сложно. Следующие операторы в документе, из которого вызывается диалоговое окно, располагают последнее по центру окна. Глава 16. Объекты window и frame 407
dialogLeft = (screen.availWidth/2) - (parselnt(dialogWidth)/2) + "px"; dialogHeight = (screen.availHeight/2) - (parselnt(dialogHeight)/2) + "px"; Обратите внимание, что функция parselnt () используется для получения числовой части значений dialogWidth и dialogHeight. См. также: свойства window. dialogHeight, window. dialogTopWidth. directories locationbar menubar personalbar scrollbars statusbar toolbar Значение: объект Чтение/Запись (для защищенных сценариев) Совместимость: WinlE-, MacIE-, NN4+, Mozl+, Safaril+ За пределами области содержимого окна, где непосредственно размещается документ, браузер Netscape Navigator отображает целый набор панелей инструментов и других средств, называемых элементами управления окна. Все браузеры позволяют отображать эти элементы при создании нового окна (третий параметр метода window. open ()), но до появления в NN4 защищенных сценариев эти элементы нельзя было добавить или удалить в главном или любом другом окне. В NN4 эти элементы являются основными объектами в объекте window. В NN6 предусмотрено дополнительное свойство — панель каталогов (часть окна, подобная фрейму, которая может быть отображена или скрыта в левой части окна). В то же время браузеры NN6/W3C не позволяют отображать или скрывать полосы прокрутки окна браузера. Изменение состояния отображения этих элементов на ходу влияет на взаимоотношение между внутренними и внешними размерами окна браузера. Если для представления содержимого требуется настроить размер окна, то откорректировать элементы управления следует раньше. Все же тщательно обдумайте возможность изменения отображаемых элементов управления окна. Опытные пользователи, как правило, настраивают вид окон своих браузеров так, как они привыкли, поэтому любые изменения лишь раздражают их. К счастью, эти изменения не сохраняются в настройках пользователя, но остаются после выгрузки страницы. Если ваш сценарий изменяет эти настройки, сначала сохраните исходные параметры, а затем в обработчике события onunload восстановите их. Строка меню на платформе Macintosh не является элементом управления окна Совет браузера. Поэтому состояние ее отображения нельзя изменить средствами ^ сценария. Пример В листинге 16.6 показан пример изменения внешнего вида окна браузера с помощью свойств directories, locationbar, menubar, personalbar, scrollbars, statusbar, toolbar. Чтобы запустить этот сценарий, вам необходимо подписать его или настроить доверителя (см. главу 16). Для выполнения операторов подписанного сценария необходши включить поддержку Java. 408 Часть III. Объекты доктент
После загрузки страницы в сценарии сохраняется состояние каждого элемента окна. Каждая кнопка страницы позволяет отобразить или скрыть определенный элемент окна. Функция инвертирует состояние элемента, указанного в качестве аргумента. Обратите внимание, что функция restore () вызывается обработчиком onunload документа. Кроме того, если вы запустите этот сценарий в NN6+, то возникнет некритическая ошибка при отображении или сокрытии полос прокрутки. <html > <head> <title>Bars Bars Bars</title> ' <script type="text/javascript"> // сохранение исходных внешних размеров при загрузке страницы var originalLocationbar = window.locationbar.visible; var originalMenubar = window.menubar.visible; var originalPersonalbar = window.personalbar.visible; var originalScrollbars = window.scrollbars.visible; var originalStatusbar = window.statusbar.visible; var originalToolbar = window.toolbar.visible; // общая функция установки внутренних размеров function toggleBar(bar) { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserWrite"); bar.visible = !bar.visible; netscape.security.PrivilegeManager. revertPrivilege("UniversalBrowserWrite"); } // восстановление установок function, restore() { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserWrite"); window.locationbar.visible = originalLocationbar; window.menubar.visible = originalMenubar; window.personalbar.visible = originalPersonalbar; window.scrollbars.visible = originalScrollbars; window.statusbar.visible = originalStatusbar; window.toolbar.visible = originalToolbar; net scape.security.PrivilegeManager. revertPrivilege("UniversalBrowserWrite"); } </script> </head> <body onunload="restore() " > <form> <b>Toggle Window Bars</bxbr /> <input type="button" value="Location Bar" onclick="toggleBar (window, locationbar) " /xbr /> <input type="button" value="Menu Bar" onclick="toggleBar (window.menubar) " /xbr /> <input type="button" value="Personal Bar" onclick="toggleBar (window.personalbar) " /xbr /> <input type="button" value="Scrollbars" onclick="toggleBar (window, scrollbars) " /xbr /> Глава 16. Объекты window и frame 409
«cinput type="button" value*"Status Bar" onclick="toggleBar(window.statusbar)" /><br /> <input type="button" value="Tool Bar" onclick= "toggleBar (window.toolbar) " /xbr /> <hr /> <input type="button" value="Restore Original Settings" onclick="restore () " /xbr /> </form> </body> </html> См. также: метод window. open (). document Значение: объект Только для чтения Совместимость: WinEE3+, MacIE3+, NN2+, Mozl+, Safaril+ Свойство document приведено в данном случае лишь для полноты. Каждый объект window содержит один объект document (хотя в NN4 окно может содержать слои, каждый из которых имеет свой объект document; см. главу 39). В качестве значения свойства document, которое не отображается, выступает объект document. Вместо этого свойство document применяется при задании ссылок на свойства и методы документа или других объектов (например форм), содержащихся в нем. Для загрузки в окно другого документа используется объект location (см. главу 17). Подробное описание объекта document приведено в главе 18. См. также: объект document. event Значение: объект Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari 1+ Объект event рассматривается как свойство объекта window только в браузерах IE4+. В объектной модели NN4+ и W3C DOM копия объекта event передается как аргумент функции обработчика события. Связь с объектом window в IE достаточно непоследовательна, поскольку все действия с объектом event происходят в функциях обработчиков событий*. Единственное отличие состоит в том, что объект может рассматриваться как глобальный, когда одна функция обработчика вызывает другую. Вместо передачи объекта event как параметра, функции в Ш могут обращаться к нему напрямую (с или без префикса window. в ссылке). За полной информацией о применении объекта event во всех браузерах обратитесь к главе 25. См. также: объект event. external Значение: объект Только для чтения Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Свойство external (не поддерживаемое в МасШ5) применяется лишь тогда, когда окно браузера выступает компонентой другого приложения. Это свойство обеспечивает своего рода шлюз между текущим окном браузера и приложением, действующим как хост для него. Когда WinIE4+ действует как компонент операционной системы-хоста, свойством external можно воспользоваться для доступа к методам, управляющим поведением документа за пределами браузера. Три самых полезных метода управления компонентами для разработчиков Web- 410 Часть ///. Объекты документ*
страниц— это AddDesktopComponent (), AddFavorite () и NavigateAndFind (). Два первых метода отображают такое же диалоговое окно предупреждения, как и при выборе команды из меню браузера или контекстного меню рабочего стола, которое не позволяет создателям Web-узлов добавлять документы на рабочий стол или в список Избранное (Favorites) без разрешения на то пользователя. Параметры всех трех методов приведены в табл. 16.2. Метод Описание &. AddDesktopComponent ("URL", "type"[, left, top width, height]) AddFavorite ("URL"[, "title"]) NavigateAndFind ("URL", "findString", Добавляет Web-узел или изображение на активный рабочий стол (Active Desktop) (если он включен в системе Windows пользователя). Параметр value имеет значение website или image. (He обязательно.) Параметры размера окна являются целочисленными Добавляет заданный URL в список Избранное (Favorites). Необязательный параметр для строки заголовка определяет запись в списке меню (если он опущен, то отображается один URL) Переходит к заданному в первом аргументе URL и открывает "targetи) страницу в указанном целевом объекте (в текущем фрейме открывается пустая строка). Параметр f indstring задает текст, поиск которого осуществляется на странице. После нахождения текстовый фрагмент выделяется Пример Первый пример запрашивает у пользователя разрешения на добавление Web-узла на активный рабочий стол Windows. Если активный рабочий стол не доступен, то пользователю предоставляется возможность активизировать его. externalAddDesktopComponent("http://www.nytimes.com","website", 200, 100,400, 400); В следующем примере у пользователя спрашивается разрешение на добавление адреса URL в список избранного. Пользователь может придерживаться стандартной процедуры добавления Web-страницы в папку Избранное. external.AddFavorite("http://www.dannyg.com/updatell.html", "JSBible 5 Support Center"); Последний пример предполагает, что пользователь выбирает один из вариантов в списке select. Обработчик onchange объекта select вызывает следующую функцию, которая отображает в окне необходимую страницу и прокручивает ее к указанному разделу. function locate(list) { var choice = list.options[list.selectedlndex].value; external.NavigateAndFind("http://www.collegesports.net/ scores.html", choice, "scores"); } frameElement Значения: ссылка на объект frame или if rame Совместимость: WinTE5.5+, МасГЕ-, NN-, Moz-, Safari - Только для чтения Глава 16. Объекты window и frame 411
Если текущее окно задается дескриптором <frame> или <iframe>, его свойство f rameElement содержит ссылку на элемент, содержащийся в нем. Как вы узнаете из знакомства с объектом элемента frame (далее в этой главе), ссылка на объект frame или iframe обеспечивает доступ к свойствам, повторяющим атрибуты объекта элемента HTML. Для окна, не являющегося частью набора фреймов, свойство f rameElement имеет значение null. Преимущества этого свойства становятся очевидными, когда один и тот же документ загружается в несколько наборов фреймов. Сценарий в документе может ссылаться на внешний элемент frame, даже если элемент имеет различные идентификаторы в разных наборах. К элементу frameset возможен доступ также и с помощью свойства parentElement свойства f rameElement. var frameSetObj = self.frameElement.parentElement; Ссылка на элемент frameset предоставляет возможность изменять размеры фреймов. См. также: объекты frame, iframe. frames Значение: массив Только для чтения Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ В многофреймовом окне верхнее (или родительское) окно может содержать любое количество отдельных фреймов, каждый из которых представляет собой полноценный объект window. Свойство frames применяется тогда, когда оператор ссылается на объект, расположенный в другом фрейме. Например, если по щелчку на кнопке в одном фрейме в другом загружается документ, его обработчик события должен содержать ссылку, указывающую точно, куда следует поместить новый HTML-документ. Данную задачу выполняет свойство frames. Полная ссылка, использующая свойство frames, начинается с объекта parent или top. Последнее требование позволяет JavaScript правильно переместиться по иерархии всех загруженных на данный момент объектов к требуемому элементу. Узнать текущее количество активных фреймов в окне позволяет следующее выражение. parent.frames.length Это выражение возвращает количество фреймов, определенных в родительском окне. Однако оно не учитывает фреймы более высокой степени вложенности (третьего уровня и больше). Другими словами, при наличии таких фреймов не существует свойства, позволяющего определить точное количество всех фреймов в окне браузера. Браузер сохраняет информацию о всех отображаемых фреймах в массиве, причем первый фрейм (т.е. первый определенный дескриптором <f rame> элемент в наборе фреймов) имеет индекс 0. parent.frames[0] Если в окне находится три фрейма (с индексами frames [0], frames [1] и frames [2], « соответственно), то ссылка на свойство title документа во втором из них выглядит следующим образом. parent.frames[l].document.title Эта ссылка рассматривается подобно пути следования транспортного средства: она начинается в родительском окне и ведет через документ второго фрейма к свойству title. В браузерах, предшествующих Ш4 и NN6, кроме количества фреймов, определенных в родительском окне, и их имен (top. frames [i] .name), другие свойства напрямую недоступны (см. элемент frame далее в этой главе). В следующих версиях браузеров элементы frame отдельных фреймов имеют несколько свойств, отражающих дополнительные значения атрибутов дескриптора < f rame >. 412 Часть III Объекты документа
Использование индексов для задания фреймов— небезопасный метод, поскольку структура набора фреймов может измениться, что приведет и к изменению индексов. Поэтому лучше воспользоваться преимуществами, предоставляемыми атрибутом name дескриптора <frarae>, и присвоить каждому фрейму уникальное описательное имя. Значение name используется в атрибутах target ссылок, когда страница загружается во фрейм, отличный от содержащего ссылку. Имя фрейма представляет собой альтернативу индексу при задании ссылок. Например, в листинге 16.7 двум фреймам присвоены различные имена. Для доступа к заголовку документа во фрейме JustAKid2 используется следующая ссылка. parent.JustAKid2.document.title где имя фрейма (с учетом регистра) заменяет frames [1]. Для обеспечения гибкости в JavaScript имя объекта можно использовать вместо индекса массива. parent. frames [" JustAKid2 и ] . document .title Основным преимуществом применения имен является их постоянство: как бы ни изменилась структура набора фреймов (а значит, и индексы отдельных фреймов), имена останутся теми же. Пример В листингах 16.7-16.8 приведен пример того, как JavaScript обращается к объектам внутри фреймов. Во все кадры загружается один и тот же документ. Сценарий извлекает сведения о текущем фрейме и всем наборе фреймов. На рис. 16.4 показан результат загрузки документа, представленного листингом 16.7. <html> <head> <title>window.frames property</title> </head> <frameset cols="50%/50%"> <frame name="JustAKidl" src="lstl6-08.htm" /> <frame name="JustAKid2" src="lstl6-08.htm" /> </frameset> </html> Определив количество фреймов в наборе (длину набора фреймов), вы получите ноль. Этот результат вполне закономерен, поскольку все фреймы представлены отдельными окнами, и ни один из них не вложен в другое окно. Если же добавить в ссылку свойство parent, то в область учета попадут все фреймы, сгенерированные основным окном документа. <html> <head> <title>Window Revealer II</title> <script type=" text/javascript" > function gatherWindowData() { var msg = ""; msg += "<pxb>From the point of view of this frame: </bxbr />"; msg += "window.frames.length: " + window.frames.length + "<br />"; msg += "window.name: " + window.name + "</p>"; msg += "<pxb>From the point of view of the framesetting Глава 16. Объекты window и frame 413
} document :</bxbr />"; msg += "parent.frames.length: " + parent.frames.length + "<br />"; msg += "parent.frames[0].name: " + parent.frames[0].name + "</p>"; return msg; </script> </head> <body> <script type^'text/javascript'^ document.write(gatherWindowData()); </script> </body> </html> Последний оператор в этом примере демонстрирует, как правильно использовать синтаксис массивов (скобки) для обращения к определенному фрейму. Индексация массивов фреймов начинается с нуля. Поскольку документ запрашивает имя первого фрейма (parent. frames [0]), то будет возвращен результат JustAKidl для обоих фреймов. См. также: объекты frame, frameset; свойства window. parent, window. top. £1 УЙ1- KJfe Наш fc, гшш cm viw w\ Ф Back т.* ** ~-xf- mpm*m?mmm From tho point of view of this frimo: wmdow.frimef.length. 0 wmdow name: JustAKidl From До point of view of the framoiotting document ptrenlframes.length: 2 parent frames[0]aame: JustAKidl шшшшшшшмшмш^ш^шш From tho point of viow of tint fromo: window, frtmei.length: 0 wmdow name: JustAKid2 From tbo point of viow of tho fromoiotting documont: parent.framei.length; 2 parent.framee[0].name: JustAKidl Рис. 16.4. Возвращение свойств из двух фреймов, созданных с помощью кода листинга 16J history Значение: объект Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ См. описание объекта history в главе 17. Только для чтения 414 Часть III. Объекты документа
innerHeight irmerWidth outerHeight outerWidth Значение: целочисленное Чтение/Запись Совместимость: WinlE-, Macffi-, NN4+, Mozl+, Safari 1+ Браузеры NN4+ позволяют сценариям корректировать высоту и ширину любого окна (включая главное окно браузера), благодаря установке соответствующих свойств. Такое изменение размеров необходимо проводить для страниц, дизайн которых предопределяет высоту и ширину окна. Благодаря им, размер окна можно установить, не полагаясь на пользователя (хотя он в любой ситуации имеет возможность вручную изменить размеры главного окна). Поскольку объект navigator (см. главу 38) позволяет установить тип операционной системы, размеры окна можно делать разными в зависимости от используемых шрифтов и представления элементов управления форм на разных платформах. Современные браузеры обеспечивают две метода указания высоты и ширины окна: внешний (outer) и внутренний (inner). В обоих методах размеры вычисляются в пикселях. Внутренние размеры относятся к области содержимого документа (иногда ее называют активной областью окна). Если оптимальный способ отображения документа зависит от внутренней области, тогда следует установить значения innerHeight и innerWidth. В отличие от этого, внешние размеры относятся к окну целиком, включая все элементы управления (полосы прокрутки, строку состояния и т.д.). Установка свойств outerHeight и outerWidth обычно выполняется совместно с определением параметров объекта screen (глава 38). Как правило, внешние свойства используют для заполнения окном области, доступной на мониторе пользователя. Более эффективным способом изменения этих двух размеров окна является метод window, resizeTo (), поддерживаемый браузерами ГЕ4+. Параметрами метода служат ширина и высота в пикселях (целочисленные значения). Таким образом, изменение размеров производится в одном операторе. Помните, что этот метод не задает расположения окна. Таким образом, для заполнения окном доступной на мониторе области требуется выполнить еще и метод window. moveTo (), размещающий левый верхний угол окна в точке с указанными координатами. В отличие от тех преимуществ, которые эти свойства предоставляют авторам страниц, в поддерживаемых браузерах существуют ограничения на минимально задаваемый размер в тех сценариях, которые не защищены криптографически. Поэтому внешние размеры окна нельзя установить меньшими 100 пикселей. Это ограничение не допускает использования окна малого размера (практически невидимого), чтобы следить за действиями, производимыми в других окнах. В защищенных сценариях окна могут иметь высоту или ширину меньше 100 пикселей, но только с разрешения разработчика. Пример В листинге 16.9 представлен пример, в котором с помощью кнопок изменяются свойства innerHeight, innerWidth, outerHeight, outerWidth (в NN4 и NN6). Все остальные браузеры попросту игнорируют операцию настройки этих свойств. <html> <head> <title>Window Sizer</title> Глава 16. Объекты window и frame 415
<script type=ntext/javascript"> // сохранение исходный внешних размеров при загрузке страницы var originalWidth = window.outerWidth; var originalHeight = window.outerHeight; // общая функция установки внутренних разм^ров function setlnner(width, height) { window.innerWidth = width; window.innerHeight = height; } // общая функция установки внешних размеров function setOuter(width, height) { window.outerWidth = width; window.outerHeight = height; } // восстановление исходных размеров окна function restore() { window.outerWidth = originalWidth; window.outerHeight = originalHeight; } </script> </head> <body> <form> <b>Setting Inner Sizes</bxbr /> <input type="button" value="600 Pixels Square" onclick="setInner (600,600) " /xbr /> <input type="button" value="300 Pixels Square" onclick="setInner (300, 300) " /xbr /> <input type="button" value="Available Screen Space" onclick="setInner(screen.availWidth, screen.availHeight)" /xbr /xhr /> <b>Setting Outer Sizes</bxbr /> <input type= "button" value="'600 Pixels Square" onclick*"setOuter(600,600) " /xbr /> <input type*"button" value="300 Pixels Square" onclick="setOuter(300,300) " /xbr /> <input type="button" value="Available Screen Space" onclick="setOuter(screen.availWidth, screen.availHeight)" /xbr /xhr /> <input type="button" value="Cinch up for Win95" onclick="setlnner(273,304) " /xbr /> <input type="button" value="Cinch up for Mac" onclick="setlnner(273,304) " /xbr /> <input type="button" value="Restore "Original" onclick= "restore () " /xbr /> </form> </body> </html> См. также: методы window. resizeTo (), window.moveTo (); объект screen; объект navigator. loading Значение: булево Только для чтения Совместимость: WinlE-, МасШ-, NN4, Moz-, Safari- 416 Часть ///. Объекты документ*;
Это свойство, уникальное для браузера NN4, позволяет узнать, загружает ли окно содержимое. Если да, то оно имеет значение true или false после завершения загрузки содержимого страницы. location Значение: объект Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ См. обсуждение объекта location в главе 17. locationbar См. directories. name Значение: строка Чтение/Запись Совместимость: Winffi3+, МасГЕЗ-ь, NN2+, Mozl+, Safari 1+ Всем объектам window можно присвоить имена. Их следует использовать при работе с фреймами, особенно в многофреймовой среде. Главное окно браузера по умолчанию в качестве имени содержит пустую строку. Этому окну присваивать имя нет необходимости, так как в JavaScript и HTML существует немало способов обращения к главному объекту window (свойство top, константа _top для атрибута target и свойство opener для открываемых окон). Если необходимо присвоить имя главному окну, то для этого используется свойство window.name. Помните, что свойство окна сохраняется независимо от состояния загрузки или выгрузки документов в нем, поэтому может оказаться, что все сценарии обращаются к одному и тому же документу или набору фреймов. Если не восстановить исходное значение свойства (пустая строка), имя окна будет сохранено при загрузке всех последующих документов. Я предлагаю в таких ситуациях присвоить имя окну в обработчике события onload, а затем обнулить его в обработчике onunload. <body onload="self.name = 'Main'" onunload="self.name = ■'"> Пример приведен в листинге 16.16 (установка имени родительского окна поможет при изучении взаимоотношений между родительским и дочерним окном). См. также: свойство top; методы window. open (), window. sizeToContent (). navigator Значение: объект Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Несмотря на то, что объект navigator является свойством объекта window только в последних версиях браузеров, сам этот объект появился довольно давно (см. главу 38). В предыдущих версиях браузеров он рассматривался как полностью отдельный объект. Поскольку ссылку на объект window при доступе к его свойствам можно опустить, для совместимости со всеми версиями браузеров (по крайней мере с теми, в которых поддерживается объект navigator) можно использовать старый вариант синтаксиса. В ссылках на объект navigator рекомендуется поступать именно таким образом. См. также объект navigator. » ' * ■ »■■■ ' '■ ■ Шва 16. Объекты window и frame 417
offscreenBuffering Значение: булево или строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Браузеры Internet Explorer 4+ (на платформах Win32) по умолчанию заносят страницу в буфер (фрагмент памяти) до ее представления на экране. Этим поведением можно управлять явно с помощью свойства window. of fscreenBuf fering. По умолчанию свойство содержит строку auto. Чтобы отменить автоматическое поведение Ш по умолчанию, свойству можно присвоить значение булевого типа true или false. Пример Если вы хотите отключить буферизацию всей страницы, то в начале сценария разместите следующую строку кода. window.offscreenBuffering = false; onerror Значение: функция Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Свойство onerror представляет собой исключение из правила этой книги: не описывать обработчики событий как свойства объектов. Причина заключается в том, что с событием onerror связаны некоторые специальные свойства, полезные при настройке обработчиков событий в сценариях. Современные браузеры (Ш5+, NN4+ и W3C) разработаны таким образом, чтобы предотвратить навязчивый вывод сообщений об ошибках, встречающихся при загрузке страницы или навигации по ней. Даже самые простые извещения о возникших проблемах (сообщения или значки в строке состояния) могут оказаться сложными для пользователей, не знакомых с JavaScript. JavaScript позволяет отключить вывод предупреждений об ошибках или сообщений о них при запуске сценариев на странице. Вопрос заключается в следующем: в каких случаях необходимо отключать вывод этих сообщений? Обычно ошибки свидетельствуют о неполадках в сценарии. Ошибка может быть результатом неправильного программирования действия или несовместимости определенных средств JavaScript (например, отсутствие поддержки объекта текущей версией браузера для используемой платформы, в которой сценарий при отладке не был протестирован). При возникновении таких ошибок сценарий обычно не может продолжить работу и выполнить свою задачу. Отменять вывод ошибок выполнения сценария в процессе его разработки не имеет смысла, поскольку так вы вряд ли узнаете о скрытых ошибках. Так же опасно скрывать диалоговые окна ошибок от пользователей, которые будут считать, что страница загружается нормально, тогда как это может быть не так. В такой ситуации некоторые данные иногда обрабатываются или отображаются некорректно. Тем не менее, существуют такие ситуации, когда можно отключить вывод диалоговых окон с сообщениями об ошибках. Например, если известно, что версия браузера для определенной платформы сообщает об ошибке, но сценарий при этом выполняется правильно, можно не допустить появления такого сообщения. Однако сделать это можно лишь после тщательного тестирования, убедившись, что сценарий выполняется абсолютно корректно несмотря на возникающие ошибки. 418 Часть III. Объекты докуменп
IE запускает обработчик события onerror только для ошибок, появляющихся во время выполнения сценария. Это означает следующее: если сценарий содержит синтаксическую ошибку, которая возникает на этапе загрузки страницы, обработчик события onerror не запускается, и перехватить сообщение о ней нельзя. Более того, если в IE установлен отладчик сценариев, любой код, предназначенный для отключения вывода сообщений об ошибках, работать не будет. При запуске браузера свойство window. onerror имеет значение <undef ined>. В таком состоянии обо всех ошибках JavaScript браузер докладывает обычным образом — выводом окна или сообщения. Чтобы не допустить отображение сообщений об ошибках, свойству window. onerror необходимо присвоить функцию, которая не выполняет никаких действий. function doNothingO {return true;} window.onerror = doNothing; Для восстановления сообщений об ошибках потребуется заново загрузить страницу. Свойству window. onerror можно присвоить и более полезную функцию, которая управляет ошибками. Когда сообщения об ошибках отображаются (по умолчанию), ошибка сценария (а также Java-аплета или исключения класса) вызывает функцию, присвоенную свойству onerror, и передает ей три параметра: ■ сообщение об ошибке; ■ URL документа, вызвавшего ее; ■ номер строки с ошибкой. Важно, что все ошибки можно обработать созданными собственноручно средствами (или вообще не сообщать пользователю о них). Последним оператором функции должен быть return true — он обеспечивает вывод стандартного сообщения об ошибке JavaScript. Вы можете перехватывать все ошибки и управлять ими с помощью специально разработанного интерфейса (не требующего вывода предупреждающих сообщений пользователю). Последний оператор подобной функции должен содержать оператор return true, если вы не хотите, чтобы сообщения об ошибках отображались на экране. Если для вызова Java-аплетов или методов Java-класса напрямую из сценариев используется LiveConnect, то для обработки прерываний, генерируемых языком Java, поДойдет та же схема. Прерывание Java необязательно свидетельствует об ошибке в коде: в некоторых методах предполагается, что Java-код перехватывает определенные типы прерываний (например, действие в ответ на запрет доступа в диалоговом окне защищенного сценария). Пример перехвата прерываний Java приведен в главе 44. Кроме того, в главе 31 описана модель обработки прерываний JavaScript, которая представлена в браузерах, совместимых с W3C DOM. Пример В листинге 16.10 приведен сценарий, содержащий ошибку. В него добавлена функция обработки ошибки, которая отображает на экране отдельное окно, содержащее текстовую область (рис. 16.5). Кнопка Submit обеспечивает отправку сообщения об ошибке по указанному почтовому адресу — это один из вариантов сообщения о возникновении неполадок в готовых приложениях. <html> <head> <title>Error Dialog Control</title> <script type="text/javascript"> / \мЗШ8ф$ Глава 16. Объекты window и frame 419
// функция с неправильным значением переменной function goWrongO { var x = fred; } // отключение окон с ошибками function errOff() { window.onerror = doNothing; } // включение окон с ошибками function errOnO { window.onerror = handleError; } // назначение обработчика ошибок по умолчанию window.onerror = handleError; \ // обработчик при выключении ошибок предотвращает появление окон function doNothing() { return true; } function handleError(msg, URL, lineNum) { var errWind = window.open("","errors","height=270,width=400") ; var wintxt я "<htmlxbody bgcolor=red>" ; wintxt += "<b>An error has occurred on this page. Please report it to Tech Support.</b>"; wintxt += "<form method=POST enctype='text/plain' action=mailTo:support4@dannyg.com >"; wintxt += "<textarea name=*errMsg■ cols=45 rows=8 wrap=VIRTUAL>"; wintxt += "Error: " + msg + "\n"; wintxt += "URL: " + URL + "\n"; wintxt += "Line: " + lineNum + "\n"; wintxt += "Client: " + navigator.userAgent + "\n"; wintxt += " \n"; wintxt += "Please describe what you were doing when the error occurred:"; wintxt += "</textareaxbr />"; wintxt += "<input type=SUBMIT value='Send Error Report•>"; wintxt += "<input type=button value='Close■ onclick= •self.close()•>"; wintxt += "</form></body></html>"; errWind.document.write(wintxt); errWind.document.close(); return true; } </script> </head> <body> <form name="myform"> <input type="button" value="Cause an Error" one1i ck="goWrong()" /> <p><input type="button" value="Turn Off Error Dialogs" onclick="err0ff()" /> <input type="button" value="Turn On Error Dialogs" onclick="err0n()" /></p> </form> </body> с/html> 420 Часть ///. Объекты документа
Я добавил на страницу кнопку, выполняющую "принудительную" перезагрузку, в результате которой восстанавливается значение свойства window.onerror. Если отключить отображение сообщений об ошибках, то функция управления ошибками выполняться не будет. См. также: метод location.reload(); обработка прерываний JavaScript (глава31); отладка сценариев (глава 45). Рис. 16.5. Пример "автоматического" вывода сообщения об ошибке opener , Значение: ссылка на объект окна Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN3+, Mozl+, Safari 1+ Многие авторы сценариев ошибочно считают, что окно браузера, созданное методом window.open (), имеет с главным окном взаимоотношения типа "дочерний-родительский" (как это происходит в случае с фреймами). Но подобная связь не устанавливается! Вновь созданное окно браузера имеет очень слабую связь с породившим его окном: посредством свойства opener. Его цель — обеспечить сценариям в новом окне ссылку на исходное окно. Например, исходное окно может содержать значения переменных или функции общего назначения, которые используются в новом окне. Кроме того, исходное окно иногда содержит элементы форм, настройки которых или являются значениями нового окна, или устанавливаются при взаимодействии пользователя с ним. Поскольку значение свойства opener — это ссылка на объект window, начинать ссылки можно непосредственно с него. Можно также использовать и более полную ссылку вида window.opener или self .opener. Ссылка должна включать определенный объект или свойство исходного окна. Если новое окно открывает следующее новое окно, то цепочка остается в силе; она лишь становится на один шаг длиннее. Третье порожденное окно может запросить объекты в главном окне с помощью следующей ссылки. opener.opener.... Правильная методика построения сценариев для третьего окна заключается в том, чтобы сохранить значение opener. opener в глобальной переменной. Если пользователь закроет второе окно, переменной можно будет воспользоваться как ссылкой на главное окно. Если сценарий, генерирующий новое окно, находится во фрейме, свойство opener указывает на этот фрейм. Чтобы новое окно взаимодействовало с родительским или каким-либо другим фреймом исходного окна, следует с особой тщательностью создать ссылку на такой Глава 16. Объекты window и frame 421
объект. Например, если новому окну требуется установить свойство checked флажка во фрейме, сестринском по отношению к исходному окну, полная ссылка будет выглядеть так. opener.parent.sisterFrameName.document.formName.checkboxName.checked При создании ссылки будьте предельно внимательны, шаг за шагом отслеживая, как сценарий "проходит" из исходной точки в точку назначения. Пример Чтобы продемонстрировать важность свойства opener, рассмотрим, как новое окно создается в основном окне браузера (листинг 16.11). Функция doNewO генерирует небольшое подокно и загружает в него файл, представленный листингом 16.12. Обратите внимание на первый условный оператор этой функции, с помощью которого окно активизируется (используется метод f ocus ()), если оно уже существует. Лишит IJMt; Глаюое mho браузера, в котором генерируется подокно <html> <head> <title>Master of all Windows</title> <script type="text/javascript"> var myWind; function doNewO { if ('myWind || myWind.closed) { myWind = window.open("1st16-12.htm","subWindow", "height=200/width=350/resizable"); } else { // вывод на передний план существующего подокна myWind.focus(); } } </script> </head> <body> <form name="input"> Select a color for a new window: <input type="radio" name="color" value="red" checked^"checked" />Red <input type=Mradio" name="color" value="yellow" />Yellow <input type="radio" name="color" value="blue" />Blue <input type= "button" name="storage" value="Make a Window" onclick= "doNewO " /xhr /> This field will be filled from an entry in another window: <input type="text" name="entry" size="25" /> </form> </body> </html> Листинг 16.12. Ссылка на свойство opener <html> <head> <title>New Window on the Block</title> <script type="text/javascript"> function getColor() { 422 Насть III. Объекты документ»
// сокращение ссылки colorButtons = self.opener.document.forms[0].color; // проверка установленного переключателя for (var i = 0; i < colorButtons.length; i++) { if (colorButtons[i].checked) { return colorButtons[i].value; } } return "white"; } </script> <script type="text/javascript"> document.write("<body bgcolor='" + getColorO + "'>") </script> </head> <body> <hl>This is a new window.</hi> <form> <input type="button" value="Who's in the Main window?" onclick="alert(self.opener.document.title)" /> <p>Type text here for the main window: <input type="text" size="25" onchange="self.opener.document♦forms[0]. entry.value = this.value" /></p> </form> </body> </html> В функции get Co lor () многочисленные ссылки на массив переключателей могут выглядеть длинными. Чтобы упростить ссылки, в этой функции массив переключателей сохраняется в переменной с именем colorButtons. Данная переменная фигурирует во всех ссылках на объекты переключателей, включая операторы проверки их установки. Кнопка во втором окне выводит на экран сообщение о том, кто открыл это окно. Даже если в основном окне загружена другая страница, свойство opener второго окна будет указывать на первое. Но при этом свойство document основного окна изменится. Наконец, второе окно содержит объект ввода текстовых данных. Введите в него определенный текст, предварительно активизировав поле. Обработчик onchange обновляет текстовое поле в основном окне (предполагается, что в последнем открыт исходный документ). См. также: методы window. open (), window. focus (). outerHeight outerWidth Cm. innerHeight и innerWidth выше. pageXOffset pageYOffset Значение: целочисленное Только для чтения Совместимость: WinlE-, MacIE-, NN4+, Mozl+, Safari 1+ Левый верхний угол (внутренней) области содержимого окна браузера является точкой отсчета при прокрутке документов. Когда документ прокручен до самого верха и выровнен по левому краю (или же он достаточно мал, чтобы полностью поместиться в окне браузера), его расположение считается равным 0,0, т.е. документ находится на нулевом расстоянии от левого Глава 16. Объекты window и frame 423
верхнего угла. Если прокрутить документ, то его расположение будет задано другим значением. Это расстояние назьшается смещением страницы, а свойства pageXOf f set и pageYOf f set позволяют определить, соответственно, горизонтальное и вертикальное смещение в пикселях. Ml] Mastei of аИ Windows Microsoft Internet Exploier ' v^'-OI f lift ЫИ V'«:-A J :*Ъ'УЧИ*Ъ fooJS Hftij> ^ |; O** • -^ й [и ■?>• y:?s«* '&*»«» «fr**» в £> 4 и - 2 ^3 *? 1 Select a color for a new wmdow 0 Red О Yellow О Blue [ .M^aWindow [ This field will be filled from an entry m another wmdow: Hello from the subwindow Рис. 16.6. Основное окно и подокно, связанные свойством opener Область использования этих значений становится очевидной при разработке, например, кнопок навигации, тщательно управляющих содержимым страницы, отображаемым в окне. Например, страница может состоять из двух фреймов, в одном из которых находятся элементы навигации, а в другом — непосредственно содержимое. К элементам управления относятся полосы прокрутки, которые из эстетических соображений при отображении фрейма отключены. Сценарии, использующие созданные вручную кнопки прокрутки, определяют значение свойства pageYOf f set, а затем с помощью метода window.scrollToО прокручивают документ до следующего логического раздела. В IE4+ похожими свойствами обладает объект body: body. scroll Left и body. scroll Top (см. главу 18). Пример Сценарий листинга 16.13 представляет собой необычную программную конструкцию, создающую набор фреймов и добавляющую в каждый из двух фреймов одного документа определенную информацию. Цель данного примера (обычно открывается в Safari) — продемонстрировать возможности свойств pageXOf f set и pageYOf f set в прокручивающихся документах. В левом фрейме содержится два поля, в которых представлены значения свойств pageXOf f set и pageYOf f set правого фрейма. В правом фрейме вы увидите тридцатист- роковую таблицу фиксированной ширины (800 пикселей). События мыши захватываются на уровне документа (глава 18), что позволяет для запуска функции showOffsets О выполнить щелчок в любой части таблицы и за ее пределами. Эта функция выводит в соответствующих полях значения смещения страницы текущего фрейма. 424 Часть III. Объекты докумет
$.13. Свойства pmg#XCff0«t и pmg«YO£fe#t <html> <head> ^ <title>Master of all Windows</title> <script type="text/javascript"> function leftFrameO { var output = H<htmlxbody<h3>Page Offset Values<\/h3> <hr \/>\n"; output += "<form>PageXOffset:<input type='text' name=• xOffset• size='4' \/><br \/>\n"; output += "PageYOffset:<input type='text' name=ryOffset• size='4' \/><br \/>\n"; output += "<\/formx\/body><\/html>"; return output; } function rightFrameO { var output = u<html><headxscript type='text/javascript' >\n" ; output += "function showOffsets() {\nM; output += "parent.readout.document.forms[0].xOffset.value = self.pageXOffset;\n"; output += "parent.readout.document.forms[0].yOffset.value = self.pageYOffset;\n}\n"; output += "document.captureEvents(Event.CLICK);\n"; output += "document.onclick = showOffsets;\n"; output += "<\/scriptx\/headxbodyxh3>Content Page<\/h3>\n"; output += "Scroll this frame and click on a table border " + " to view page offset values. <br \/xhr \/>\n"; output += "<table border='5' width=»800■>"; var oneRow = "<td>Cell l<\/tdxtd>Cell 2<\/tdxtd>Cell 3 <\/tdxtd>Cell 4<\/td>" + "<td>Cell 5<\/td>"; for (var i = 1; i <= 30; i++) { output += "<trxtdxb>Row " + i + "<\/bx\/td>" + oneRow + "<\/tr>"; } output += "<\/tablex\/bodyx\/html>M; return output; } </script> </head> <frameset cols="30%/70%"> <frame name="readout" src="javascript:parent.leftFrame()" /> <frame name="display" src="javascript:parent.rightFrame()" /> </frameset> </html> Чтобы понять, как свойствам смещения задаются значения, прокрутите окно в горизонтальном направлении. Свойство pageXOf f set несколько увеличится. То же происходит и со свойством pageYOf f set при прокругке документа в вертикальном направлении. Помните, что эти свойства указывают координаты левого верхнего угла документа. В листинге 18.20 приведена версия этого документа для DE4+. См. также: свойства window. innerHeight, window. innerWidth, body. scrollLef t, body, scroll Top; методы window. scrollBy (), window. scrollTo (). Глава 16. Объекты window и frame 425
parent Значение: ссылка на объект окна Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safaril+ Свойство parent (а также свойство top, о котором рассказано далее в этом разделе) вступает в действие, как правило, тогда, когда отображаемый документ является частью многофреймового окна. HTML-документы, отображаемые во фреймах, отличаются от того документа, который содержит сам набор фреймов. Этот документ хранится в памяти браузера (причем именно его URL отображается в строке адреса) и не виден пользователю (кроме исходного вида при выборе опции Source View (Просмотр исходного кода)). Если сценариям в отображаемых документах необходимо сослаться на объекты или свойства окна, содержащего набор фреймов, используется свойство parent (в ссылке не следует указывать объект window, например window.parent .propertyName, поскольку это вызывает ошибки в ранних версиях браузеров). На первый взгляд, свойство parent нарушает иерархию объектов, поскольку в документе с одним фреймом оно указывает на уровень, находящийся выше. Если не указать свойство parent или вместо него использовать свойство self, то ссылка будет указывать на фрейм, а не на внешний объект window с набором фреймов. Нетрадиционный, но вполне приемлемый способ использования объекта parent заключается в хранении временных переменных или даже массивов данных. Эти значения доступны всем документам, загруженным во фреймы, включая ситуацию, когда документы изменяются. При сохранении данных в родительском фрейме "на ходу" (т.е. в ответ на действие пользователя) следует проявлять осторожность. В ранних версиях браузеров переменные возвращались к значениям по умолчанию (т.е. настраиваемым сценарием родительского окна) при изменении размеров окна. В дочернем окне можно вызвать функцию, определенную в родительском окне. Ссылка на функцию выглядит следующим образом. parent.functionName([parameters]) С первого взгляда, свойства parent и top могут показаться идентичными. В среде, которая состоит из одного окна, содержащего набор фреймов, и его непосредственных дочерних окон, так и есть. Но если одно из них само содержит набор фреймов, то общая иерархия объектов включает три поколения окон. С точки зрения самого "младшего" дочернего окна (например определенного во втором наборе фреймов), свойство parent указывает на его непосредственно родительское окно, тогда как top указывает на первое окно с основным набором фреймов в этой последовательности. С другой стороны, новое окно, созданное методом window. open (), не имеет взаимоотношений типа "родительский-дочерний" с исходным окном. Поэтому его свойства top и parent указывают на само новое окно (об этих взаимоотношениях см. ранее в настоящей главе). Пример Чтобы продемонстрировать, как различные свойства объекта windows задаются в многофреймовых документах, загрузите в браузере листинг 16.14. Отобразите в каждом фрейме один и тот же документ (листинги 16.15). Этот документ представляет несколько важных свойств окна, включая свойство document .title. ^ Лист»ет 16.14. МтаТО •; ^ Л ,'_,^Ш||| <html> <head> <title>The Parent Property Example</title> 426 Часть III. Объекты документа
<script type="text/javascript"> self.name = "Framesetter"; </script> </head> <frameset cols="50%,50%" onunload="self.name = »■"> <frame name="JustAKidl" src="lstl6-15.htm" /> <frame name="JustAKid2" src="lstl6-15.htm" /> </frameset> </html> 16.15. Отображение нес!солю!хс§ойств объекта window <html> <head> <title>Window Revealer II</title> <script type="text/javascript"> function gatherWindowData() { var msg = ""; msg = msg + "top name: " + top.name + "<br />"; msg = msg + "parent name: " + parent.name + "<br />"; msg = msg + "parent.document.title: " + parent.document.title + "<br />"; msg = msg + "window name: " + window.name + "<br />"; msg = msg + "self name: " + self.name + "<br />"; msg = msg + "self.document.title: " + self.document.title; return msg; } </script> </head> <body> <script type="text/javascript"> document.write(gatherWindowData()); </script> </body> </html> В двух кадрах этого примера (рис. 16.7) содержатся ссылки на объекты window и self. Они возвращают имя фрейма в наборе (JustAKlidl для левого фрейма и JustAKid2 для правого фрейма). Другими словами, для каждого фрейма объект window представлен по- разному. Ссылка self . document .title соответствует документу, загруженному только в текущий фрейм. При этом ссылки top и parent (в настоящем примере они одинаковые) определяют свойства, общие для обоих фреймов. Причина такого поведения очень проста. Стоит обратить внимание на несколько других моментов. Первое: имя окна с набором кадров назначается при загрузке кода листинга 16.14, а не по обработчику события onload дескриптора <frameset>. Причина такого поведения очень проста— имя должно назначаться фрейму до того, как в него будет вставлено содержимое. Если же ожидать возникновения события onload, то имя фрейму будет назначаться после его заполнения данными. Второе: я восстановил пустое имя родительского окна при выгрузке документов набора фреймов. В результате будут предотвращены возможные конфликты, возникающие при загрузке в основное окно последующих документов. См. также: свойства window. frames, window .self, window. top. Глава 16. Объекты window и frame 427
щгт*яшящр щттщтш11Ш!Шштш№тщ *ШЩ Ellt Edit Xltw Favorite» Ioeb tftlp * top name: Frame setter parent name: Framesetter parent.document.tide: The Parent Property Example window name. JustAKidl self name: JustAKidl self document.tide: Wmdow Revealer П top name: Framesetter parent name: Framesetter parent, document.tide: The Parent Property Example window name' JustAKid2 self name: JustAKid2 seK document tide: Window Revealer П №d ^$M&!&*.... Рис. 16.7. Свойства top и parent одинаковы для обоих кадров personalbar См. directories. returnValue Значение: любого типа Чтение/Запись Совместимость: WinIE4+, MacIE5+, NN-, Moz-, Safari- Сценарии используют свойство returnValue в документах, загружаемых в необычное для Ш модальное диалоговое окно. Последнее генерируется методом showModalDialog (), который возвращает те данные, которые были присвоены свойству returnValue диалогового окна до его закрытия. Такое поведение возможно по следующей причине: обработка сценариев в главном окне приостанавливается, пока открыто модальное диалоговое окно. Если его закрыть, сценарию в главном окне можно возвратить значение, причем выполнение продолжится с той точки, в которой было вызвано модальное окно. Пример Пример использования свойства returnValue приведен в листинге 16.39, в котором вы ознакомитесь также с методом showModalDialog () (в Ш4+). См. также: метод showModalDialog (). Только для чтения screen Значение: объект screen Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Несмотря на то, что объект screen является свойством объекта window только в последних версиях браузеров, сам этот объект появился еще в NN4 (см. главу 38), но как отдельный элемент. Поскольку ссылку на объект window можно опустить при доступе к его 428 Часть ///. Объекты документа
свойствам, для совместимости со всеми версиями браузеров (по крайней мере с теми, которые поддерживает объект screen) можно использовать старый вариант синтаксиса. В ссылках на объект screen рекомендуем поступать именно таким образом. Пример Примеры использования объекта screen для определения характеристик монитора компьютера, в котором запущен браузер, приведены в главе 38. См. также: объект screen. screenLeft screenTop Значение: целочисленное Только для чтения Совместимость: Winffi5+, МасГЕ-, NN-, Moz-, Safari- Браузеры ГЕ5+ поддерживают свойства screenLef t и screenTop объекта window, позволяющие получить положение в пикселях (относительно левого верхнего угла (0,0) монитора) элемента, который в терминологии Microsoft имеет название клиентской области окна браузера. Клиентская область исключает многие элементы управления окна (заголовок, адресную строку и панель изменения размеров окна). Поэтому, когда окно браузера ГЕ5+ открыто во весь экран (т.е. панели изменения размеров окна не отображаются), свойство screenLef t имеет значение 0, a screenTop зависит от панелей управления, отображенных пользователем. Для окон, открытых не во весь экран (причем размещенных так, что их левая и верхняя части выходят за пределы экрана), значения свойств могут быть отрицательными. Два этих свойства предназначены только для чтения. Изменить положение всего окна браузера (а не только клиентской области) позволяют методы window. moveTo () и window. moveBy (). Браузеры IE вплоть до версии 5.5 не поддерживают свойств, задающих положение всего окна браузера. Пример Приложение The Evaluator (глава 13) позволяет детально изучить свойства использования screenLef t и screenTop. Запустите браузер и максимально расширьте его окно (в Windows). Введите в первое текстовое поле следующее выражение. window.screenLeft Щелкните на кнопке Evaluate для просмотра текущих установок. Уменьшите размер окна браузера и перетащите его по экрану. При каждом перетаскивании щелкайте на кнопке Evaluate для ознакомления с изменениями. Эти же операции выполните и для свойства window.screenTop. См. также методы window. moveTo (), window. moveBy (). screenX screenY Значение: целочисленное Чтение/Запись Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ NN6+/Moz/Safari используют свойства screenX и screenY, чтобы расположить внешнюю границу окна относительно левой верхней координаты (0,0) монитора. Окно браузера включает панели изменения размеров окна шириной четыре пикселя, которые имеют все окна на платформе Win32. Поэтому, когда окно браузера NN6+ открыто во весь экран, значения свойств screenX и screenY равны -4. Netscape Navigator не поддерживает свойств, которые Глава 16. Объекты window и frame 429
эквивалентны свойствам screenLef t и screenTop, используемым в IE5 (они отвечают клиентской области окна). В NN можно только проверить, какие панели инструментов отображаются в окне браузера (см. window. directories). Оба свойства можно изменить средствами сценария, что приведет к перемещению окна, однако более удобными являются все же методы window. moveTo () и window. moveBy (), поскольку обе координаты в последнем случае можно указать в одном операторе. Пример Приложение The Evaluator позволяет экспериментировать со свойствами screenX и screenY. Разверните окно браузера во весь экран (в Windows) и введите в верхнее текстовое поле следующее выражение. window.screenY Щелкните на кнопке Evaluate для просмотра текущих установок. Уменьшите размер окна браузера и перетащите его по экрану. При каждом перетаскивании щелкайте на кнопке Evaluate для ознакомления с изменениями. Эти же операции выполните для свойства window.screenY. См. также: методы window. moveTo (), window. moveBy (). scrollbars См. directories. scrollMaxX scrollMaxY Значение: целочисленное Чтение/Запись Совместимость: Winffi-, Macffi-, NN7.1+, Mozl.4+, Safaril- B указанных браузерах эти свойства позволяют определить максимальные границы прокрутки документа в окне. Прокрутка выполняется только в случае добавления в окно полос прокрутки. Значения этих свойств указываются в пикселях. См. также: свойства scrollX, scrollY scrollX scrollY Значение: целочисленное Только для чтения Совместимость: Winffi-, Macffi-, NN7.1+, Mozl+, Safari 1+ Свойства scrollX и scrollY в NN6+/Moz/Safari позволяют определить положение горизонтальной и вертикальной полос прокрутки окна. Прокрутка возможна только тогда, когда окно отображает полосы прокрутки. Целочисленные значения задаются в пикселях. Объектная модель IE не поддерживает этих свойств окна, однако аналогичную информацию содержат свойства body. scrollLef t и body. scrollTop. Пример В приложении The Evaluator предусмотрено достаточно возможностей для детального изучения свойства scrollX и scrollY. Эведите в верхнее поле следующее выражение. window.scrollY Теперь вручную прокрутите страницу вниз и щелкните на кнопке Evaluate. Узнайте, насколько страница сместилась вниз при прокрутке. См. также: свойства body. scrollLef t, body. scrollTop. 430 Часть III. Объекты документа
self Значение: ссылка на объект окна Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Так же, как ссылка на объект window не является обязательной, свойство self можно опустить, если ссылка задается на объект в том же окне. Кажется необычным, что свойство self представляет тот же объект, что и window. Например, чтобы обратиться к заголовку окна с одним фреймом, можно использовать любую из трех следующих конструкций. window.document.title self.document.title document.title Несмотря на то, что self является свойством окна, не следует сочетать различные типы ссылок в сценарии страницы с одним фреймом (например, начинать ссылки с конструкции window, self — известно, что такой синтаксис вызывает многочисленные проблемы в сценариях). Однако указание свойства self, необязательное в окнах с одним фреймом, делает код понятным для чтения. В окнах с несколькими фреймами необходимо использовать это свойство очень внимательно. В JavaScript ссылки в пределах одного окна обрабатываются достаточно логично. Поэтому, обычно часть self в них можно опустить. Однако, когда документ находится в многофреймовом окне, полные ссылки (включая префикс self) делают чтение и отладку кода более простыми. Свойство self имеют все окна, поэтому оно содержит ссылку на объект window. Пример В листинге 16.16 выполняются те же операции, что и в листинге 16.5, но в первом в ссылках на объект окна применено свойство self. Подобные ссылки использовать совсем не обязательно, хотя в многофреймовых документах они играют важную роль при обращении одного фрейма к объектам в других фреймах. Свойство self позволяет быстро указать текущий фрейм, из которого вызываются элементы других фреймов. <html> <head> <title>self Property</title> <script type="text/javascript"> self.defaultStatus = "Welcome to my Web site."; </script> </head> <body> <a href=Mhttp://www.microsoft.com" onmouseover=" self . status = 'Visit Microsoft's Home page.'; return true;" onmouseout="self.status = '';return true;">Microsoft</a> <pxa href ="http: //mozilla.org" onmouseover="self.status = 'Visit Mozilla\'s Home page.'; return true;" onmouseout="self.status = self.defaultStatus; return true; ">Mozilla</ax/p> </body> </html> См. также: свойства window. frames, window. parent, window. top. Глава 16. Объекты window и frame 431
sidebar См. аррСоге. status Значение: строка Чтение/Запись Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safaril+ В нижней части окна браузера находится строка состояния. Часть строки занимает область, в которой обычно отображается состояние загрузки документа или URL ссылки, на которую наведен указатель мыши. Временное содержимое этой строки можно изменить, присвоив строку с текстом свбйству status объекта window. Корректировать свойство status необходимо лишь в ответ на события, дающие временный эффект (например, обработчик onmouseover объекта ссылки или карты изображения). Установка этого свойства отменяет другие его значения. Когда пользователь сводит указатель мыши с объекта, изменяющего содержимое строки состояния, последняя возвращается к значению по умолчанию (на некоторых страницах она может быть пустой). Safari 1.0 не всегда отображает в строке состояния новый текст. Это свойство окна используется как наиболее дружественный пользователю вариант отображения URL ссылки, когда пользователь перемещает указатель мыши по странице. Например, в строке состояния можно описать тему страницы, на которую указывает ссылка (текст размещается в ответ на возникновение события onmouseover). Следует также помнить, что опытные пользователи привыкли видеть в этой строке URL. Поэтому можно создавать, например, комбинированные сообщения (при этом строка состояния будет включать описание страницы, за которым в скобках следует URL). В средах с несколькими фреймами можно установить свойство window. status, не заботясь об указании адреса отдельного фрейма. Пример В листинге 16.17 свойство status устанавливается в обработчике onmouseover. Оно приравнивается к ссылкам, заданным в дескрипторах HTML-ссылки. Обратите внимание, что в последней строке обработчика должно возвращаться значение return true, или сообщение не будет отображаться в строке состояния всех указанных браузеров. , jMihp^ v ";| <html> <head> <title>window.status Property</title> </head> <body> <a href="http://www.dannyg.com" onmouseover="window.status = 'Go to my Home page. (www.dannyg.com)'; return true"> Home</a> <pxa href = "http://mozilla.org" onmouseover="window.status = 'Visit Mozilla Home page. (mozilla.org)'; return true"> Mozilla</ax/p> <:/body> </html> 432 Часть III. Объекты документа
Чтобы избежать непредвиденного поведения межплатформенных браузеров при обработке события onmouseover и свойства window, status, добавьте в код обработчик событий onmouseout для ссылок и клиентских карт изображений. Подобные обработчики onmouseout должны устанавливать свойство status равным пустой строке. Таким образом, при наведении указателя мыши на объект ссылки в строке состояние будет выводиться сообщение, заданное в свойстве def aultStatus. Если вы собираетесь написать общую функцию, которая управляет сообщениями в строке состояния, то используйте в ней обработчик onmouseover очень аккуратно, не забывая об операторе return true. В листинге 16.18 приведен альтернативный вариант. <html> <head> <title>Generalizable window.status Property</title> <script type="text/javascript"> function showStatus(msg) { window.status = msg; return true; } </script> </head> <body> <a href="http://home.netscape.com" onmouseover="return showStatus('Go to my Home page.')" onmouseout="return showStatus('')">Home</a> <pxa href ="http: //mozilla.org" onmouseover="return showStatus('Visit Mozilla Home page.1)" onmouseout ="return showStatus (• ') ">Mozilla</ax/p> </body> </html> Обратите внимание, как обработчики событий возвращают результат выполнения метода showStatus (). В последнем примере управления строкой состояния (листинг 16.19) показано, как в нижнюю часть окна браузера добавить бегущий текст. flwcripr 16.19. Стдм1йо б<гуцей строю -Г-i <html> <head> <title>Message Scroller</title> <script type="text/javascript"> var msg = "Welcome to my world..."; var delay = 150; var timerId; var maxCount = 0; var currCount = 1; function scrollMsgO { // Установка количества прокруток сообщения if (maxCount ==0) { maxCount = 3 * msg.length; } Глава 16. Объекты window и frame 433
window.status = msg; // отслеживание количества прокрученных символов CUrГCount++; // смещение первого символа сообщения в конец сообщения msg = msg.substring (1, msg.length) + msg.substring (0, 1); // проверка достижения последнего символа строки if (currCount >= maxCount) { timerlD =0; // zero out the timer window.status = ""; // clear the status bar return; // break out of function } else { // рекурсивный вызов функции timerld = setTimeout("scrollMsgОи, delay); } } </script> </head> <body onload="scrollMsg()"> </body> </html> Поскольку строка состояния управляется с помощью отдельной функции (а не обработчика события onmouseover), то вам нет необходимости добавлять в ее конец оператор return true, чтобы установить свойство status. Функция scrollMsgO использует сложные конструкции JavaScript (метод window. setTimeout ()) и методы управления строками (глава 27). Чтобы изменить скорость прокрутки текста в строке состояния, введите другое значение переменной delay. Установка свойства status в обработчике события onmouseover в NN выполняется несколько некорректно. Сценарий постоянно "конфликтует" с браузером за право заполнить данными строку состояния. Если ссылка, на которую наводится указатель мыши, находится на границе фрейма, то событие onmouseover вызвать практически невозможно. Таким образом запрограммированое сообщение в строке сообщения не отображается. Тестировать подобные документы Web-разработчикам довольно сложно. См. также: свойство window.defaultStatus; обработчики событий onmouseover, onmouseout; объект link. statusbar toolbar См. locationbar. top Значение: ссылка на объект окна Только для чтения Совместимость: Winffi3+, МасГ£3+, NN2+, Mozl+, Safari 1+ Свойство top объекта window указывает на самое верхнее окно в иерархии объектов документа. Для окна с одним фреймом оно указывает на тот же объект, что и window (а также его свойства self и parent), поэтому в ссылку нельзя включать префикс window. В многофреймовом окне самым верхним окном является то, в котором определен первый набор фреймов (в случае вложенных наборов). В такой среде пользователи никогда не видят самого верхнего окна, однако оно хранится в памяти браузера как объект. Причина заключается 434 Часть III. Объекты документа Сомт -й
втом, что это окно является "перевалочным пунктом" для других фреймов, которые могут обращаться к любым дочерним фреймам (если, например, в одном фрейме понадобится задать ссылку на дочерний объект другого). Ссылка выглядит так. top. имяФуикции( [параметры] ) Об отличиях между свойствами top и parent подробно рассказывалось в начале этой главы, когда описывалась общая методика разработки сценариев для фреймов. Кроме того, обратитесь к описанию свойства parent в примере, демонстрирующем назначение свойства top. См. также: свойства window, frames, window, self, window, parent. window Значение: объект окна Только для чтения Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Использование свойства window как отдельного элемента, скорее, запутывает работу, чем оказывается полезным. Значение свойства window совпадает с объектом window. Однако нет необходимости использовать ссылки вида window. window. Несмотря на то, что объект window подразумевается во многих ссылках, его можно использовать или не использовать в ссылках на объекты из одного и того же окна. Но его точно не допускается применять в ссылках на элементы, находящиеся выше данного окна в иерархической структуре (top или parent). Методы alert (" сообщение11) Возвращаемое значение: отсутствует Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Диалоговое окно предупреждения является модальным: в нем представлено сообщение и кнопка ОК, щелчок на которой закрывает окно. Пока на экране присутствует диалоговое окно предупреждения, другое приложение или окно нельзя сделать активным. Прежде чем продолжить работу, пользователю необходимо закрыть это окно. Единственный параметр метода alert () представляется значением любого типа данных, в том числе и некоторых необычных типов, редко применяемых в JavaScript (например отдельные объекты^. Это делает диалоговое окно предупреждения довольно удобным средством отладки сценариев JavaScript. Если необходимо проверить значение выражения, запустите метод alert (), подставив первое в качестве параметра. Сценарий будет выполнен до этой точки, а затем выведет значение. (Советы по отладке сценариев приведены в главе 45.) Разработчиков приложений часто беспокоит то, что все модальные диалоговые окна, созданные в JavaScript (методами alert (), confirm () и prompt ()), идентифицируют себя как генерированные JavaScript или браузером. В старых браузерах это выглядит не очень эстетично, поскольку ключевая фраза находится даже не в заголовке окна, а внутри окна. Это сделано преднамеренно, чтобы предотвратить действия тех разработчиков сценариев, которые пытаются имитировать диалоговые окна предупреждений системы или браузера, предлагая пользователю ввести пароль или другие важные данные. Идентифицирующую сообщение фразу нельзя исключить или заменить средствами сценария. Модальное диалоговое окно эмулируют независимо от версии браузера, но оно не является таким гибким, как настоящее модальное окно, создаваемое в браузерах IE4+ методом window. showModalDialog (). Поскольку метод alert () имеет глобальную природу (т.е. в многофреймовой среде не имеет значения, из какого фрейма он вызывается), ссылку на объект window обычно опускают. По возможности следует воздержаться от использования диалоговых окон предупреждений Глава 16. Объекты window и frame 435
в HTML-документах и при разработке Web-страниц. Модальность этих окон затрудняет пользовательскую навигацию по страницам. Взаимодействие с пользователем рекомендуется осуществлять с помощью форм или отдельных фреймов. Пример Параметр в примере листинга 16.20 представлен конкатенированной строкой. Он содержит две фиксированные строки, а также значение свойст$а navigator. appName. После загрузки этого окна на экране появляется окно с предупреждением (рис. 16.8). • ,* ..v -" * chtml> <head> <title>win,dow. alert () Method</title> </head> <body> <script type="text/javascript"> alert("You are running the " + navigator.appName + " browser.") </script> </body> ^/html> T\ You twtuonity INf MfciMtJI Iflltmft cxpkfttf Рис. 16.8. Результат выполнения метода al ert () в Internet Explorer u Netscape Navigator См. также: методы window. confirm (), window. prompt (). back() forward() Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN4+, Moz-, Safari- Цель методов window. back () и window. forward () в браузере NN4 состоит в том, чтобы добавить в сценарий унифицированную версию кнопок навигации Back (Назад) и Forward (Вперед) и позволить объекту history управлять навигацией в пределах определенного окна или фрейма— как и должно быть. Эти методы не поддерживаются в Ш (и не включены в объект window в W3C ЕЮМ 2), поэтому при навигации рекомендуется ограничиться 436 Честь ///. Объекты документа
методами объекта history. Более подробная информация о совместимости версий, а также навигации приведена в описании объекта history в главе 17. См. также: методы hi story, back (), history, forward (), history.goO . captureEvents (списокСобытий) Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN4, Moz-, Safari- B NN4 событие проходит через объект window и лишь затем достигает точки назначения. Например, по щелчку на кнопке событие достигает вначале объекта window, затем объекта document и лишь после этого — кнопки, в которой обработчик onclick выполняет заданные в нем операции. Механизм "перемещения" события в NN4 позволяет объектам окна, документа и слоя перехватить события и обработать их до того, как они достигнут своих целей (или полностью предотвратить последнее). Для того чтобы этот подход сработал, сценарий должен проинформировать внешний контейнер о том, какой тип событий следует перехватывать. Чтобы объект window перехватывал все события определенного типа, необходимо вызвать метод window.captureEvents (). I Браузеры NN6+ и W3C обеспечивают оба механизма: захват и всплывание события. /наймете Синтаксис для захвата событий в NN6 несколько отличается от принятого в NN4. Ме- * J^^0r тоды captureEvents(), releaseEvents(), handleEvent() и routeEvent() объектов window, document и layer рассматриваются только в среде браузера NN4. Если разрабатываемая вами DHTML-страница не требует поддержки в NN4, вы можете пропустить его. Метод window. captureEvents () в качестве параметров использует один или несколько типов событий. Типом события является константа, встроенная в NN4 в объект Event. Для каждого типа обработчика, допустимого в объектах документов в NN4, существует один тип события. Применяется следующий синтаксис: имя объекта события (Event) и имя события прописными буквами, разделенные точкой. Например, если окно должно перехватывать все события щелчка мышью, то задается следующий оператор. window.captureEvents(Event.CLICK); Несколько событий необходимо разделить символом вертикальной черты (|). window.captureEvents(Event.MOUSEDOWN | Event.KEYPRESS); После установка захвата события объектом window следует подготовить функцию, обрабатывающую событие. Предположим, что функция проверяет все события Event. MOUSEDOWN щелчка правой кнопкой, а также определяет, какому элементу формы предназначается событие. Целью может служить, например, отображение всплывающего меню (в отдельном слое). Если событие вызвано щелчком левой кнопкой мыши, то оно перенаправляется к другой цели. Чтобы определенному типу события, перехватываемому объектом window, поставить в соответствие функцию, ее необходимо присвоить событию. Например, для назначения функции doClickEvent (), перехватывающей события щелчков, применяется следующий оператор. window.onelick=doClickEvent; Обратите внимание на то, что имя функции задается как ссылка (без скобок и кавычек), — не так, как это определяется в обработчике события в дескрипторе. Данная функция считается функцией постольку, поскольку в качестве параметра она автоматически получает копию объекта Event. Отключить захват событий одного или нескольких типов позволяет метод window.releaseEvent(). Глава 16. Объекты window и frame 437
I Захват событий на уровне окна, документа или слоя в NN4 не всегда работает /назаметку так, как ожидается. Особенно это заметно в документах, содержащих таблицы. * .„*--" Например, перехват событий мыши в NN4 для Windows не работает, пока указатель не будет наведен на границу ячейки. Наиболее надежно захват событий выполняется в том случае, когда для объекта определен обработчик (даже если он равен пустой строке), а элемент является целью события (например при вводе текста в поле). Для всех остальных элементов захват событий на уровне документа или окна может быть просто невозможен. Пример Пример использования метода captureEvents () приведен в листинге 16.21. Как только объект window захватывает события щелчка, запускается функция flashO. В этой функции событие анализируется: только после нажатия клавиши <Ctrl> и щелчке кнопкой, имя которой начинается с button, фон страницы начинает мерцать красным цветом. Все остальные события щелчка (которые возникают в объектах страницы, имеющих обработчики onclick) обрабатываются методом routeEvent (). Листинг 1б^/За»атсо6ь1Гийщвлч1савокне ' \^,^ - ' "ГМ. <html> , <head> <title>Window Event Capture</title> <script type="text/javascript"> // вызывается при захвате окном события щелчка function flash(e) { if (е.modifiers «- Event.CONTROL_MASK && e.target.name.indexOf("button") ==0) { document.bgColor = "red"; setTimeout ("document .bgColor = 'white111, 500); } // продолжение перемещения события routeEvent(e); } // стандартный захват событий щелчка window.captureEvents(Event.CLICK); // назначение функции flash событиям щелчка, захваченным окном window.onclick = flash; </script> </head> <body bgcolor="white"> <form name="buttons"> <b>Turn window click event capture on or off (Default is "On")</b> <p><input name="captureOn" type="button" value="Capture On" onelick="window.captureEvents(Event.CLICK)" />&nbsp; <input name="captureOff" type="button" value="Capture Off" onclick="window.releaseEvents(Event.CLICK)" /></p> <hr /> <b>Ctrl+Click on a button to see if clicks are being captured by the window (background color will flash red):</b> <ul> <lixinput name="buttonl" type="button" value="Informix" onclick="alert('You clicked on Informix.')" /></li> 438 Часть III. Объекты документа
<lixinput name="button2" type= "button" value="Oracle" onclick="alert('You clicked on Oracle.1)" /></li> <lixinput name="button3" type="button" value="Sybase" onclick="alert('You clicked on Sybase.')" /></li> </ul> </form> </body> </html> При тестировании этой страницы отключите захват событий окна. Таким образом будут выполняться только обработчики onclick кнопок; страница начнет мерцать красным цветом. См. также: методы window. disableExternalCapture (), window. enableExternal - Capture (), window. handleEvent (), window. releaseEvents (), window. routeEvent (). clear Interval (интервал) , Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safari 1+ Метод window.clearlnterval () отключает выполнение действия в цикле через определенный интервал времени, установленный методом window, set Interval (). Параметром является идентификатор, возвращаемый методом set Interval (). Обычно методика задания интервалов в JavaScript используется в анимации объекта на странице. Если несколько действий выполняются таким образом, что для каждого из них задан интервал, то все они имеют отдельные идентификаторы в памяти браузера. Идентификатор позволяет отключить любое из них. Если цикл остановлен, сценарий не может продолжить его: цикл необходимо начинать сначала, при этом ему будет присвоен новый идентификатор. Пример В листингах 16.36 и 16.37 приведен пример использования методов clearlnterval () и setlnterval (). См. также: методы windpw.setlnterval (), window. setTimeout (), window, clear- Timeout (). clearTimeout (задержка) Возвращаемое значение: отсутствует Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Метод window. clearTimeout () обычно используется в сочетании с методом window. setTimeout (), описанным ниже в этой главе, когда необходимо отключить таймер, задающий запуск выражения. Параметром является идентификатор, возвращаемый методом window. setTimeout (). Метод clearTimeout () отменяет указанную ранее задержку. Правильная методика заключается в том, чтобы проанализировать ситуации, когда действия пользователя могут отменить запуск таймера. Пример Страница, представленная кодом листинга 16.22, содержит одно текстовое поле и две кнопки (рис. 16.9). Первая кнопка запускает посекундный обратный отсчет (отсчет начинается с одной минуты, но может использоваться и любое другое время), а вторая — прекращает его. По истечении минуты на экране появляется окно с сообщением. Глава 16. Объекты window и frame 439
ehtml> <head> <title>Count Down Timer</title> <script type="text/javascript"> var running = false; var endTime = null; var timerlD = null; function startTimerO { running = true; now = new Date(); now = now.getTime(); endTime = now + (1000 * 60 * 1); showCountDown(); } function showCountDown() { var now = new Date{); now = now.getTime(); if (endTime - now <= 0) { stopTimer() ; alert("Time is up. Put down your pencils."); } else { var delta = new Date(endTime - now); var theMin = delta.getMinutes(); var theSec = delta.getSeconds(); var theTime = theMin; theTime += ((theSec < 10) ? ":0" : ":") + theSec; document.forms[0].timerDisplay.value = theTime; if (running) { timerID = setTimeout("showCountDown()",1000); } } } function stopTimer() { clearTimeout(timerID); running = false; document.forms[0].timerDisplay.value = "0:00"; } </script> </head> <body> <form> <input type= "button" name*="startTime" value="Start 1 min. Timer" onclick="startTimer()" /> <input type="button" name="clearTime" value="Clear Timer" onclick="stopTimer()" /> <pxinput type="text" name= "timerDisplay" value="" /></p> </form> </body> с/html> 440 Часть III. Объекты документа
В сценарии используется три глобальных переменных: running, endTime и timerID. Они применяются во многих функциях сценария, поэтому объявлены вне последних. В функции st art Timer () устанавливается флаг запуска операции обратного отсчета. С помощью функций управления датами (глава 29) извлекается текущее время, выраженное в миллисекундах и к нему добавляется 1 минута (также выраженная в миллисекундах). Конечное время сохраняется в глобальной переменной, а потому функция может вызвать другую функцию, сравнивающую текущее и конечное время и выводящую их разницу в текстовом поле. Ранее в функции showCountDown () выполнялась проверка обнуления счетчика. Если этого не сделать, то сценарий продолжит рассчитывать разницу между двумя временами и форматировать полученное значение в виде mm: ss. Пока флаг операции обратного отсчета (running) установлен в значение true, функция перед повторным выполнением устанавливать таймер в значение 1 минута. Чтобы остановить таймер в произвольный момент (с помощью функции stopTimer ()), первым делом необходимо отменить в браузере одноминуг- ную задержку. Для этого используется метод clearTimeout () и глобальная переменная timerID. Впоследствии функция сбросит флаг running и обнулит содержимое поля. Filo EdK View Favorlteo Took Holp ф Start 1 mm. Timer Clear Timer 0:55 BjOone ■ <JMyCt*p*er Рис. 16.9. Страница с обратным счетчиком См. также: метод window. setTimeout (). close () Возвращаемое значение: отсутствует Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Метод window, close () закрывает окно браузера, на которое указывает объект window. Чаще всего он используется для закрытия вспомогательных окон, созданных из главного окна документа. Если вызов происходит не из вспомогательного окна, исходный объект window будет содержать запись о вложенном объекте. Для этого значение, возвращаемое методом window. open (), следует сохранить в глобальной переменной, которая будет доступна и другим объектам (например, в переменной, инициализированной не внутри функции). Если, с другой стороны, метод window. close () вызывает объект внутри вспомогательного окна, достаточно использовать ссылку window или self. Глава 16. Объекты window и frame 441
В ссылку необходимо обязательно ввести ключевое слово window. Иначе JavaScript будет трактовать это выражение как document. close (), которое имеет несколько другое применение (см. главу 18). Закрыть окно из сценария можно только методом window, close (). Закрытие окна, конечно же, запускает обработчик события onunload. Когда метод window.close () запущен, его уже нельзя остановить. Более того, обработчик события onunload, который запускает процессы, требующие некоторого времени на выполнение (например, отправка формы из закрываемого окна), может не завершиться, поскольку окно закроется до окончания процесса. Это поведение невозможно исправить (за исключением обработчика onbef oreunload в браузерах Ш4+). Особым является случай, когда вспомогательное окно пытается закрыть главное окно браузера (оператором self .opener, close О), в списке посещенных документов которого содержится более одной записи. Мерой предосторожности против сценариев, которые закрывают окна, созданные не ими, является следующее: в браузерах NN3+ и IE4+ у пользователя запрашивается подтверждение на закрытие главного окна (с помощью диалогового окна, генерируемого браузером). Это средство защиты можно отменить только с помощью защищенных сценариев в NN4+, когда пользователю предоставляются права на управление браузером (глава 46). Пример В листинге 16.4 (демонстрирующем применение свойства window.closed) приведен пример использования метода window. close (). См. также: методы window. open (), document. close (). confirm (" сообщение9*) Возвращаемое значение: булевого типа Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Диалоговое окно подтверждения представляет собой сообщение в модальном окне, содержащем также кнопки ОК и Отмена (Cancel). Такое окно запрашивает подтверждение у пользователя, как правило, на выполнение действий сценария, которые можно отменить. Запрос пользователя на продолжение обычной навигации после взаимодействия (например, с элементом формы) в большинстве случаев не приносит никакого результата. Однако для операций, которые могут выявить личность пользователя (например, при отправке данных формы на сервер), диалоговые окна подтверждения JavaScript могут оказаться нелишними. Пользователь может щелкнуть на кнопке случайно, поэтому разработчику стоит позаботиться о возможности прервать операцию до ее выполнения. Поскольку метод возвращает значение булевого типа (OK = true; Отмена (Cancel) = false), им можно пользоваться в операторе сравнения или присвоения. В этом случае метод находится внутри оператора, запрашивающего значения булевого типа. if (confirm("Are you sure?")) { alert("OK"); } else { alert("Not OK"); } В данном случае возвращаемое методом значение используется в конструкции if. . .else (глава31). Метод может быть задан также и в правой части оператора присвоения. var adult = confirm("Вам больше 18 лет?"); if (adult) { //для взрослых } else { 442 Часть III. Объекты документа
} //для детей В окнах такого типа в JavaScript заменить кнопки значками или изменить их заголовок нельзя. Вы не можете определить другие подписи и значки для двух кнопок в диалоговом окне подтверждения. Пример Пример в листинге 16.23 показывает, как можно использовать диалоговое окно подтверждения операции удаления набора данных. Текст в строке заголовка окна (рис. 16.10) в старых браузерах изменить нельзя. Листинг 10,28, Диадогоаое oicho гюдШржден^ <html> <head> <title>window.confirm() Methock/title> <script type="text/javascript"> function clearTableO { if (confirm("Are you sure you want to empty the table?")) { alert("Emptying the table..."); // для демонстрации // операторы очистки полей } } </script> </head> <body> <form> <!-- другие операторы отображения <input type="button" name="clear" onclick="clearTable()" /> </form> </body> </html> и заполнения таблицы value="Reset Table" \47/ Am yfcu год ytm ttftnft to empty the table? Рис. 16АО. Диалоговое окно подтверждения в WinlE См. также: методы window. alert (), window. prompt (), form. submit (). createPopup() Возвращаемое значение: ссылка на объект всплывающего окна Совместимость: WinIE5.5+, МасГЕ-, NN-, Moz-, Safari- Всплывающее окно в ЕЕ— это прямоугольная область без элементов управления, появляющаяся поверх текущего окна. В отличие от диалоговых окон, генерируемых методами Глава 16. Объекты window и frame 443
showModalDialog () и showModelessDialog (), содержимое такого окна должно полностью находиться под управлением сценария. Это относится также к размеру и расположению окна. Генерирование окна методом create Popup () лишь создает в памяти объект, не отображая его на экране. Ссылка, возвращаемая этим методом, может использоваться для позиционирования окна, заполнения его содержимым и последующего отображения (подробнее см. описание объекта popup далее в этой главе). Пример Пример использования метода create Popup () приведен в листинге 16.49. См, также: объект popup. execScript (" списокВиражений" [, язык]) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Метод window. execScript (), уникальный для BE, запускает один или несколько операторов, переданных как строковые выражения. Они указываются в первом аргументе (несколько операторов разделяются точкой с запятой). Второй (необязательный) аргумент задает интерпретатор языка, выполняющий выражения. Допустимы следующие значения: JavaScript, JScript, VBS и VBScript. По умолчанию он имеет значение JScript, поэтому его можно опустить, если применяются операторы JavaScript. В отличие от функции eval (), встроенной в ядро языка JavaScript (которая также выполняет оператор JavaScript, представленный строковым выражением), метод execScript () не возвращает значения. Метод работает с глобальной областью определения переменных окна, содержащего документ. Например, если в сценарии документа определена глобальная переменная var myVar; метод execScript () может получать и изменять ее значение. window.execScript("myVar = 10; myVar += 5"); После выполнения этого оператора значение my Var будет равно 15. Пример Используйте приложение The Evaluator для изучения метода execScript (). Это приложение содержит заранее объявленные глобальные переменные, представленные буквами от а до z. Введите следующее выражение в верхнее поле и ознакомьтесь с возвращаемым результатом. а При первой загрузке переменная объявляется, но она не содержит значения. window.execScript("а = 5") Метод не возвращает значения, поскольку оператор не определен. а Теперь переменная принимает значение 5. window.execScript("b = а * 50") b Глобальная переменная b имеет значение 250. Рассмотрите другие переменные приложения. Для одновременного ввода в поле нескольких операторов, разделите их запятыми. См. также: функция eval (). 444 Часть ///. Объекты документа
find(["строкаПоиска" [, чувствительностьКРегистру, направление] ]) Возвращаемое значение: булевого типа для недиалогового поиска Совместимость: Winffi-, МасЕЕ-, NN4+, Mozl+, Safari- Метод window, find (), уникальный для NN4, эмулирует действия диалогового окна Поиск (Find), вызываемого в результате щелчка на соответствующей кнопке на панели инструментов. Этот метод недоступен в NN7/Mozl. Если метод вызван без параметров, на экране появится обычное диалоговое окно (как при использовании кнопки Найти (Find)). В таком случае функция не возвратит никаких значений. Строку для поиска можно задать в аргументе функции. Поиск основан на простом сравнении строк и никак не связан с поиском на основе регулярных выражений (см. главу 42). Если при поиске найдено соответствие, браузер прокрутит страницу до найденного слова и выделит его — все происходит так же, как и при использовании диалогового окна. Кроме того, при нахождении соответствия функция возвращает значение true. Если соответствий в документе не найдено или они отсутствуют в направлении текущего поиска (по умолчанию поиск происходит от начала к концу документа), функция возвращает значение false. Два дополнительных параметра логического типа позволяют указать чувствительность к регистру и направление поиска. Они полностью идентичны опциям в диалоговом окне Поиск (Find) в NN4. По умолчанию поиск происходит без учета регистра в направлении сверху вниз. Если указывается один из параметров, необходимо указывать и второй. IE4+ имеет и другие средства поиска текста, реализованные, однако, совершенно другим способом (с помощью объекта TextRange, описанного в главе 35). Визуально их поведение также имеет отличия: в последнем случае слово не выделяется и страница не прокручивается до него. Пример В самом простом случае оператор f ind () вызывается следующим образом. var success = window.find("contract"); Если поиск производится с учетом регистра, то в операторе вызова используйте не менее двух параметров. success = window.find(matchString,caseSensitive,backward); Поскольку этот метод выполняется только в NN4, то детальное описание операции поиска в JavaScript вы найдете в главе 35. См. также: объекты TextRange, Range (глава 35). forward() См. window. blur (). handle Event (событие) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN4, Moz-, Safari- Когда в NN4 происходит перехват событий объектами window, document или layer (с помощью метода captureEvents (), заданного для них), сценарий управляет тем, куда события направляются после перехвата. Чтобы направить событие к своей исходной цели (например, пользователь щелкнул на кнопке), примените метод routeEvent (). Но если необходимо перенаправить событие (или класс событий) определенному обработчику в документе, обратитесь к другому методу — handleEvent (). Глава 16. Объекты window и frame 445
Каждый объект в NN4, имеющий связанные с ним обработчики событий, обладает методом handleEvent О . Поэтому если события щелчка перехватываются (например, окном), то их можно перенаправить определенной кнопке или ссылке на странице — эти объекты умеют управлять данными событиями. Рассмотрим следующий фрагмент кода. <script type="text/javaScript"> // запускается при захвате окном события щелчка function doClicks(evt) { // все щелчки передаются первой ссылке документа document.links[0].handleEvent(evt); } // указание захвата окном всех событий щелчков window.captureEvents(Event.CLICK); // назначение функции doClickO событиям щелчка, захваченным окном window.onclick = doClicks; </script> Все события щелчка перехватываются окном. Всякий раз, когда пользователь щелкает мышью на элементе, поддерживающем это событие, вызывается функция doClicks (). Она содержит один оператор, который перенаправляет событие щелчка в качестве параметра для обработки первой ссылки в документе. В дескрипторе ссылки необходимо определить обработчик события onclick, иначе этот код не будет выполняться. Поскольку объект event передается автоматически, обработчик имеет доступ к его свойствам (например, координатам указателя мыши в момент щелчка), которые он может при необходимости изменить до начала выполнения ссылкой своей задачи. Предыдущий пример демонстрирует использование метода handleEvent О, скорее, с объектом link, чем с объектом window. Для других объектов редко возникает необходимость перехватывать события, предназначенные для окна, но этот метод является частью любого объекта в NN4, поддерживающего события. В модели событий W3C аналогичный метод перехвата событий называется dispatchEvent (), а его эквивалент в Ш5+ — f ireEvent (). Пример Подробности и примеры управления объектами событий приведены в главе 25. См. также: методы window. captureEvents О , window, re 1 easeEvents (), window. routeEvent (); объект event. home () Возвращаемое значение: отсутствует Совместимость: WinlE-, Macffi-, NN4+, Moz-, Safari- Как и другие методы объекта window, новые для NN4, window. home () представляет собой специфический для этого браузера способ выполнения в сценарии действия, аналогичного задаваемому кнопкой на панели инструментов (речь идет о кнопке перехода к начальной странице (Ноте)). Щелчок на ней заставляет браузер перейти к URL, установленному в настройках браузера в качестве адреса начальной страницы. Выбранную в браузере пользователя начальную страницу по умолчанию изменить средствами сценария нельзя. См. также: методы window. back (), window. forward (); свойство window. toolbar. moveBy (del taX, del taY) moveTo(X/y) Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN4+, Mozl+, Safari 1+ 446 Часть III. Объекты документа
В браузерах DE4+ и NN4+ средства JavaScript позволяют управлять расположением окна на экране компьютера. Это относится и к главному окну, и к любому окну, созданному сценарием. Netscape Navigator рассматривает возможность перемещения окна за пределы экрана как потенциальную дыру в системе безопасности данных, поэтому в NN4+ для выполнения этого действия требуются защищенные сценарии. Расположение окна может быть задано абсолютно или в виде относительного смещения вдоль горизонтальной и/или вертикальной осей. Область определения горизонтальной (х) и вертикальной (у) координат представляет собой весь экран, где левому верхнему углу соответствует точка 0,0. Аргументами методов moveBy () и moveTo () служат координаты левого верхнего угла внешней части окна браузера. Поэтому перемещение окна в точку 0,0 выравнивает его по левой и верхней границам экрана. Это положение не соответствует окну, открытому во весь экран, для всех браузеров и операционных систем, поскольку координаты последнего являются, как правило, отрицательными. Если попытаться изменить расположение окна так, чтобы отдельная его часть "вышла" за экран, то оно автоматически будет смещено в пределы экрана. Иная ситуация в NN4 возможна лишь при использовании защищенных сценариев, получивших разрешение пользователя на частичное или полное смещение окна за пределы видимой области экрана. Перемещение единственного видимого окна браузера полностью за пределы экрана создает опасную ситуацию, так как для пользователя существует только один способ вернуть его — перезапустить браузер. Разница между методами moveTo () и moveBy () заключается в том, что первый использует абсолютные координаты, а второй задает смещение относительно текущей позиции окна. Другими словами, параметрами метода moveTo () являются точные координаты расположения левого верхнего угла окна по вертикали и по горизонтали в пикселях. Метод moveBy (), напротив, показывает, на какое расстояние следует переместить окно в каждом направлении. Если окно необходимо переместить на 25 пикселей вправо, все равно используйте два аргумента, но при этом второе значение обязательно будет равно нулю. window.moveBy(25,0); Для перемещения влево первый параметр должен быть отрицательным. Пример Несколько примеров использования методов moveTo () и moveBy () приведены в листинге 16.24. На показанной странице — 4 кнопки, каждая из которых перемещает окно браузера в своем направлении. <html> <head> <title>Window Gymnastics</title> <script type="text/javascript"> var isNav4 = ((navigator.appName == "Netscape") && (parselnt(navigator.appVersion) >= 4)); function init() { // заполнение отсутствующих свойств IE if (!window.outerWidth) { window.outerWidth = document.body.сlientWidth; window.outerHeight = document.body.clientHeight + 30; } // заполнение отсутствующих свойств 1Е4 if (!screen.availWidth) { Глава 16. Объекты window и frame 447
screen.availWidth = 640; screen.availHeight = 480; } } // запускается при захвате окном события щелчка function moveOffScreen() { // ветвление для системы защиты данных в NN if (isNav4) { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserWrite"); } var maxX = screen.width; var maxY = screen.height; window.moveTo(maxX+1, maxY+1); setTimeout("window.moveTo(0,0)",500); if (isNav4) { netscape.security.PrivilegeManager. disablePrivilege("UniversalBrowserWrite"); } } // устанавливает круговое движение окна function revolve() { var winX = (screen.availWidth - window.outerWidth) / 2; var winY = 50; window.resizeTo(400,300); window.moveTo(winX, winY); for (var i = 1; i < 36; i++) { winX += Math.cos(i * (Math.PI/18)) * 5; winY += Math.sin(i * (Math.PI/18)) * 5; window.moveTo(winX, winY); } } // устанавливает зигзагообразное движение окна function zigzag() { window.resizeTo(400, 300); window.moveTo(0,80); var incrementX = 2; var incrementY = 2; var floor = screen.availHeight - window.outerHeight; var rightEdge = screen.availWidth - window.outerWidth; for (var i = 0; i < rightEdge; i += 2) { window.moveBy(incrementX, incrementY); if (i%60 == 0) { incrementY - -incrementY; } } } // увеличивает окно на всю доступную область экрана function maximize() { window.moveTo(0,0); window.resizeTo(screen.availWidth, screen.availHeight); } </script> 448 Часть III. Объекты документ
</head> <body onload="init()"> <form name="buttons"> <b>Window Gymnastics</b> <ul> <li><input name="offscreen" type="button" value="Disappear a Second" onclick="moveOffScreen()" /></li> <lixinput name= "circles" type= "button" value="Circular Motion" onclick="revolve()" /></li> <lixinput name= "bouncer" type= "button" value="Zig Zag" onclick= " zigzag (') " /></li> <lixinput name="expander" type="button" value= "Maximize" onclick="maximize()" /></li> </ul> </form> </body> </html> Для успешного выполнения этого сценария в NN (до версии 7) вам необходимо установить доверителя (глава 46), иначе вы не получите доступ к подписанному сценарию. Функция moveOff Screen О мгновенно смещает окно браузера с экрана. Обратите внимание на то, что сценарий определяет размер окна перед его смещением. После смещения с экрана окно отображается в левом верхнем углу рабочего стола. Вторая функция, revolve (), располагает уменьшенное окно браузера в верхней части экрана и перемещает его вдоль окружности (36 раз смещает окно с шагом 10 градусов). Этот пример демонстрирует способ динамического перемещения окна, основанный на математических вычислениях. Чтобы продемонстрировать возможности метода moveBy (), используется третья функция— zigzag (). В ней в цикле for координаты окна изменяются таким образом, чтобы окно перемещалось на экране вдоль пилообразной траектории. Четвертая функция имеет широкое практическое применение. Она максимизирует окно таким образом, чтобы оно заняло всю площадь экрана. См. также: свойства window.outerHeight, window.outerWidth; методы window, resizeBy (), window, resizeToO . navigate ("URL") Возвращаемое значение: отсутствует Совместимость: WinIE3+, МасГЕЗ+, NN-, Moz-, Safari- Метод window.navigate (), поддерживаемый только в ЕЕ, позволяет загрузить новый документ в окно или фрейм. Его действие полностью аналогично присвоению URL свойству location. href, которое доступно во всех версиях браузеров NN и ГЕ, поддерживающих сценарии. Если ваша аудитория использует только браузер IE, применение этого метода является вполне безопасным. В противном случае рекомендуем применить свойство location. href. Пример В качестве аргумента метода navigate () чаще всего применяется корректный URL. window.navigate("http://www.dannyg.com"); См. также: объект location. Глава 16. Объекты window и frame 449
open (и URL " # " имяОкна" [, 11 средстваОкна" ] [, флаг1] ) Возвращаемое значение: объект window, представляющий новое окно; null, если выполнение завершилось неудачей Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Метод window. open () обеспечивает разработчику сценариев возможность вывода на экран нового окна Web-браузера, поддерживающего немало различных опций. Большая часть элементов управления окна отображается во всех браузерах, поддерживающих JavaScript, без необходимости применения защищенных сценариев. Поскольку элементы интерфейса представить себе легче всего, начнем с описания их параметров метода window. open (). Установка элементов нового окна Дополнительный параметр средстваОкна представляет собой одну строку, которая состоит из списка операторов присвоения, разделенных запятыми (наподобие атрибутов дескриптора HTML). Важно отметить следующее: для совместимости с разными браузерами после запятых не следует вводить пробелы. Если третий параметр опущен, то метод создает новое окно того же типа, который указан в опции New^Window (Создать1^Окно) меню File (Файл). Этот параметр управляет тем, какие элементы управления должны присутствовать в новом окне. Помните важное правило: если указать хотя бы одно из значений в третьем параметре, все остальные средства окна будут скрыты (кроме тех, которые указаны явно). В табл. 16.3 перечислены атрибуты нового окна во всех браузерах. Кроме указанных исключений, все значения булевого типа по умолчанию равны yes, если третий аргумент не указан. Т^иад 1^^ сценарием | Атрибут Браузеры Описание (Булевого типа). Всегда под другими окнами браузера (Булевого типа). Всегда над другими окнами браузера (Булевого типа). Режим с переключателем каналов (по умолчанию по) (Булевого типа). Копирует в новое окно содержимое меню Go исходного (Булевого типа). Новое окно закрывается при закрытии основного \ (Булевого типа). Панель папок с кнопками What's New и т.д. (Булевого типа). Без заголовка и меню (по умолчанию по) (Целочисленного типа). Высота области содержимого в пикселях (Булевого типа). Если true, то при скрытой строке меню запрещены комбинации клавиш (кроме Quit (Выход) и Security Info (Информация о защите)) (Целочисленного типа). Высота области содержимого в пикселях; совпадает со свойством height (Целочисленного типа). Ширина области содержимого в пикселях; совпадает со свойством width (Целочисленного типа). Горизонтальная координата левого верхнего угла экрана (Булевого типа). Поле, отображающее текущий URL alwaysLowered alwaysRaised3 channelmode copyhi story- dependent directories fullscreen height hotkeys innerHeight4 innerWidth4 left location NN4+ NN4+ IE4+ NN2+, IE3+ NN4+ NN2+, IE3+ IE4+ NN2+, IE3+ NN4+ NN4+ NN4+ IE4+ NN2+, IE3+ 450 Часть III. Объекты документа
Окончание табл. 16.3 Атрибут Браузеры menubar1 outerHeight4 outerWidth4 resizable2 screenX4 screenY4 scrollbars status titlebar3 toolbar top width z-lock3 NN2+, IE3+ NN4+ NN4+ NN2+, IE3+ NN4+ NN4+ NN2+, IE3+ NN2+, IE3+ NN4+ NN2+, IE3+ IE4+ NN2+, IE3+ NN4+ Описание (Булевого типа). Строка меню в верхней части окна (Целочисленного типа). Высота видимой части окна (Целочисленного типа). Ширина видимой части окна (Булевого типа). Элементы интерфейса, позволяющие изменять размеры окна в результате операций перетаскивания (Целочисленного типа). Горизонтальная координата левого верхнего угла экрана (Целочисленного типа). Вертикальная координата левого верхнего угла экрана (Булевого типа). Если документ не помещается в окне, отображаются полосы прокрутки (Булевого типа). Строка состояния в нижней части окна (Булевого типа). Заголовок и другие граничные элементы окна (Булевого типа). Панель с кнопками Back (Назад), Forward (Вперед) и т.д. (Целочисленного типа). Вертикальная координата левого верхнего угла экрана (Целочисленного типа). Ширина области содержимого в пикселях (Булевого типа). Слой окна, который расположен под окнами браузера 1 Не на платформе Macintosh, поскольку строка меню не является частью окна браузера; при отключении MacNN4 отображает сокращенный для Мае вариант строки меню. 2 На платформе Macintosh все окна позволяют изменять свои размеры, 3 Требует защищенного сценария. 4 Требует защищенного сценария для изменения размеров или положения окна за пределами видимой области. Значения булевого типа обрабатываются несколько неожиданным образом. Значение true может быть представлено как yes, 1 или именем самого свойства, значение false — по или 0. Все опущенные атрибуты булевого типа по умолчанию имеют значение false. Поэтому для создания, например, нового окна, имеющего только заголовок и строку состояния, а также элементы, позволяющие изменять размер окна, метод выглядит так. window.open("newURL",."NewWindow", "toolbar,status,resizable"); Новое окно, для которого не указаны высота и ширина, будет создано такого же размера, как и при использовании команды New^ Window (Создать^Окно) меню File (Файл). Другими словами, новое окно автоматически не приобретет размер окна, в котором вызван метод window. open (). Если не указаны атрибуты расположения, доступные в NN4+ и Ш4+, новое окно, создаваемое в сценарии, позиционируется произвольным образом. Обратите внимание, что атрибуты в разных браузерах называются по-разному (screenX и screenY в NN; left и top в Ш). Оба набора атрибутов можно включить в строку параметров, поскольку неизвестные атрибуты браузер просто игнорирует. Глава 16. Объекты window и frame 451
Защищенные сценарии (только для NN) Многие специфические для NN атрибуты считаются небезопасными и поэтому требуют применения защищенных сценариев и разрешения пользователя. Если пользователь не дает разрешения на использование, то защищенный параметр игнорируется. Некоторые такие атрибуты ведут себя по-разному в различных операционных системах (в зависимости от того, как их приложения управляют окнами). Например, на платформе Windows атрибуты alwaysLowered, alwaysRaised и z~ locked могут определяться для слоев, отличных от отведенных для окон браузера NN в Windows; в Мае слои окон в JavaScript рассматриваются только для NN. Разница заключается в том, что Windows позволяет окнам различных приложений находиться рядом с окнами браузера, тогда как в Мае окна каждого приложения располагаются только в смежных слоях. Чтобы защищенный сценарий создавал новое окно с особыми свойствами, необходимо разрешить права доступа UniversalBrowserWrite (см. главу 46). Фрагмент кода, создающий окно в стиле alwaysRaised, выглядит следующим образом. <script type="text/JavaScript" archive="myJar.jar" id="l"> function newRaisedWindow() { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserWrite"); var newWindow = window.open("","","height=100,width=300, alwaysRaised=yes"); netscape.security.PrivilegeManager. disablePrivilege("UniversalBrowserWrite"); var newContent = "<htmlxbodyxb> "On top of spaghetti! "</b>" ; newContent += "<formxcenterxinput type='button1 value='OK'"; newContent += "onclick= ' self .close () ' ></centerx/formx/bodyx/html>" ; newWindow.document.write(newContent); newWindow.document.close() ; } </script> С видом и поведением новых окон можно экспериментировать, подбирая любые комбинации атрибутов в листинге 16.25. На этой странице представлена таблица со сведениями о специфических для NN булевых атрибутах окон. На основе сделанного выбора создается новое окно размером 300x300 пикселей. На странице подразумевается, что при использовании NN4 во время управления защищенными сценариями вы обладаете правом изменения всех необходимых параметров (см. главу 46). С отключением заголовка и горячих клавиш нужно быть осторожным. При отключении заголовка содержимое окна как бы "витает в воздухе", поскольку границы окна не отображаются. Если горячие клавиши включены, комбинация <Ctrl+W> позволяет закрыть окно, не имеющее границ (на платформе Мае при отключении заголовка горячие клавиши всегда запрещены). Таким образом компьютер можно превратить в проектор: открыть окно, совпадающее по размерам с экраном, и установить его опции как "titlebar=no, hotkeys=no, alwaysRaised=yes". /tacrmr 16*2$. Сойвдиие мойте шеи <html> <head> <title>window.open() Options</title> <script type="text/javascript"> var isNav4 = (navigator.appName == "Netscape" && navigator.appVersion.charAt(0) >= 4) ? true : false; •1 452 Часть ///. Объекты документа
function makeNewWind(form) { if (isNav4) { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserWrite"); } var attr = "width=300,height=300"; for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].type == "checkbox") { attr += "," + form.elements[i].name + " = "; attr += (form.elements[i].checked) ? "yes" : "no"; } } var newWind = window.open("bofright.htm","subwindow",attr); if (isNav4) { netscape.security.PrivilegeManager. revertPrivilege("CanvasAccess"); } } </script> </head> <body> <b>Select new window options:</b> <form> <table border="2"> <tr> <td colspan="2" bgcolor="yellow" align="middle"> All Browsers Features:</td> </tr> <tr> <td><input type="checkbox" name="toolbar" /> toolbar</td> <td><input type="checkbox" name="location" /> location</td> </tr> <tr> <td><input type="checkbox" name="directories" /> directories</td> <tdxinput type="checkbox" name="status" />status</td> </tr> <tr> <td><input type="checkbox" name="menubar" /> menubar</td> <td><input type="checkbox" name="scrollbars" /> scrollbars</td> </tr> <tr> <tdxinput type="checkbox" name="resizable" /> resizable</td> <tdxinput type= "checkbox" name="copyhistory" /> copyhistory</td> </tr> <tr> <td colspan="2" bgcolor="yellow" align="middle"> Communicator Features:</td> </tr> <tr> <tdxinput type="checkbox" name="alwaysLowered" /> alwaysLowered</td> Глава 16. Объекты window и frame 453
<tdxinput type="checkbox" name=nalwaysRaisedM /> alwaysRaised</td> </tr> <tr> <tdxinput type ="checkbox" name ="dependent" /> dependent</td> <tdxinput type="checkbox" name = "hotkeys" checked="checked" />hotkeys</td> </tr> <tr> <tdxinput type = "checkbox" name="titlebar" checked^"checked" />titlebar</td> <tdxinput type="checkbox" name="z-lock" />z-lock</td> </tr> <tr> <td colspan="2" align="middle"><input type="button" name="forAll" value="Make New Window" onclick= "makeNewWind (this . form) " /x/td> </tr> </table> </form> <br /> </body> </html> Указание имени окна Вторым аргументом метода window. open () является имя нового окна (его не следует путать с заголовком документа, который устанавливается в HTML-коде страницы. Имя окна должно быть таким же идентификатором (из одного слова), как имя объекта или переменной. Кроме того, это имя представляет собой совершенно иную сущность, чем объект window, возвращаемый методом open (). Оно нигде более не используется в сценариях, за исключением атрибута target в ссылках и формах. Загрузка содержимого в новое окно Обычно сценарий заполняет окно информацией одного из двух типов. ■ Существующий документ HTML, URL которого известен заранее. ■ Страница HTML, создаваемая "на лету". Чтобы создать новое окно с существующим HTML-документом, в качестве первого аргумента метода window, open () необходимо указать его URL. Если загрузка новой страницы не выполняется (кроме случая, описанного в совете "Устранение ошибки в NN2"), то укажите полный URL-адрес документа (а не только имя файла). Если первым аргументом является пустая строка, новое окно открывается с пустым документом, который готов к заполнению содержимым средствами сценария (или загрузке отдельным оператором, в котором указан URL). Если вы планируете заносить данные в окно "на лету", создайте одну длинную строку, содержащую весь HTML-код, а затем воспользуйтесь методом document .write () для ее добавления в новое окно. Если запись данных происходит за один сеанс, в конце следует вызвать метод document. close О , который сообщит браузеру, что разметка страницы завершена (в результате чего в строке состояния, если она представлена в окне, появится сообщение Layout: Complete или Done). 454 Часть III. Объекты документа
Вызов метода window. open () возвращает ссылку на объект нового окна, если его создание прошло успешно. Это значение жизненно важно для сценария при обращении к элементам нового Окна (например, при записи в документ). Чтобы другие функции сценария имели доступ к новому окну, результат метода window. open () необходимо присвоить глобальной переменной. До первой записи в документ проверьте значение переменной — если оно равно null, значит, создание окна не было выполнено успешно (например, из-за недостатка свободной памяти). Если все в порядке, то этой переменной можно воспользоваться для задания ссылки на любое свойство или объект нового окна. var newWindow function createNewWindowO { newWindow = window.open("","и); if (newWindow != null) { newWindow.document .write ("<htmlxhead><title>Hi ! </title> </head>"); } } Глобальная переменная доступна всем функциям (например, для закрытия окна методом close О). Если сценарии вспомогательного окна будут взаимодействовать с объектами и сценариями главного окна, убедитесь, что новое окно имеет свойство opener. Обратитесь к описанию свойства window. opener ранее в этой главе. Выполнение нескольких методов window. open () с одним и тем же именем окна (во втором аргументе) не создает дополнительных копий окна в браузере Netscape Navigator (хотя в Internet Explorer это возможно). JavaScript не позволяет создать два окна с одним и тем же именем. Помните, что метод window. open () не выводит существующее окно с указанным именем на передний план: для этого используется метод window. focus (). Особенности Internet Explorer Создание новых окон в IE иногда затруднено нежелательным поведением браузера. Чаще всего проблема возникает при попытке воспользоваться методом document .write () для заполнения нового окна содержимым. Ш, особенно некоторые его последние версии, не успевает открыть окно до запуска метода document. write (). Это вызывает ошибку сценария, поскольку ссылка на окно еще не вступает в силу. Чтобы обойти эту ошибку, необходимо поместить операторы генерирования HTML-кода и метод document .write О в отдельную функцию, которая запускается методом set Timeout () после создания окна. Пример этого подхода приведен в листинге 16.26. Другая проблема, возникающая в Г£, — это нарушение прав доступа, а именно: отображение предупреждения (access denied — доступ запрещен) при попытке обращения к окну из сценария. Оно генерируется в том случае, когда страница, содержащая сценарий открытия и обращения к новому окну, находится на HTTP-сервере, а не на локальном жестком диске. Пример Страница, представленная кодом листинга 16.26, содержит одну кнопку, с помощью которой создается новое окно строго указанного размера, содержащее из дополнительных элементов только строку состояния. В сценарии описаны многие элементы окна браузера, которые отображаются при создании нового окна браузера в большинстве платформ. Ссылка на объект нового окна сохраняется в глобальной переменной newWind. Перед созданием нового окна выполняется проверка его существования (если окно еще не создано, то переменная Глава 16. Объекты window и frame 455
newWind имеет значение null). Если новое окно не найдено, то вызывается метод ореп(). В противном случае новое окно активизируется с помощью метода focus () (в ШЗ+ и NN4+). В связи с временной задержкой генерации новых объектов в Ш, HTML-код нового окна добавляется с помощью отдельной функции, вызываемой через 50 миллисекунд (остальные браузеры создают окно и его содержимое одновременно). Для создания строки, отображаемой в новом окне, я использовал оператор += (с его помощью значение справа от оператора добавляется к значению, расположенному слева от оператора). В нашем примере текст выводится с помощью дескриптора <hl>. <html> <head> <title>New Window</title> <script type="text/javascriptM> var newWindow; function makeNewWindow() { if (InewWindow || newWindow.closed) { newWindow = window.openC","", "status,height=200, width=300"); // небольшая задержка в IE setTimeout(nwriteToWindow()", 50); } else { // окно уже открыто; вывод его на передний план newWindow.focus(); , > function writeToWindowO { // генерация содержимого нового окна var newContent = "<htmlxhead><title>One Sub Window<\/title> <\/head>"; newContent + = "<bodyxhl>This window is brand new.<\/hl>"; newContent += n<\/body><\/html>"; // вывод документа нового окна newWindow.document.write(newContent); newWindow.document.close О; // закрытие потока записи } </script> </head> <body> <form> <input type="button" name="newOne" valuer"Create New Window" ' onclicks"makeNewWindow()" /> </form> </body> </html> См. также: методы window. close (), window. blur (), window. focus (); свойство window. closed. print () Возвращаемое значение: отсутствует Совместимость: WinIE5+, МасШ5+, NN4+, Mozl+, Safari- 456 Часть III. Объекты документа
Метод print () представляет собой способ печати окна или фрейма из сценария. В любом случае, на экране появляется диалоговое окно параметров печати, в котором пользователь имеет возможность указать принтер и выбрать другие настройки. Такой подход не разрешает некорректного использования команды print () без ведома пользователя. Точное поведение метода print () немного отличается в браузерах NN и IE (не говоря уже об операционных системах). В NN4+ (за исключением платформы Windows) все фреймы из набора можно распечатать с помощью одной команды print (), выполненной для родительского документа. NN4 для Windows не печатает весь набор фреймов целиком. Для этого необходимо использовать сценарий, который интерактивнсг просматривает все фреймы и с задержкой отправляет их содержимое в пул принтера. function printFrames(n) { parent.frames[n++].print(); if (n < parent.frames.length) { setTimeout("printFrames(" + n + ")",5000); } } Для распечатки всех фреймов вызывается функция printFrames (0). В Ш5 в диалоговом окне предоставлена возможность выборочно распечатать один или все фреймы окна. Поэтому убедитесь, что метод print () запускается для желаемого фрейма, если вы хотите распечатать только его. По умолчанию браузер распечатывает только один фрейм. Ш5 имеет несколько обработчиков событий, предназначенных для печати, которые запускаются и при печати из сценария, и при печати вручную. События происходят после того, как пользователь завершает работу в диалоговом окне настройки параметров печати. Обработчик onbeforeprint применяется, например, для вывода невидимого в данный момент содержимого, которое появится на бумаге. После отправки данных в пул принтера обработчик события onaf terprint восстанавливает исходный вид страницы. Пример Пример использования метода print () приведен в листингах 16.27 и 16.28. Первый представляет набор фреймов, а второй — документ, загружаемый в верхний фрейм и копирующий данные в нижний фрейм. <html> <head> <title>window.print() method</title> </head> <frameset rows="25%,75%"> <frame name="controls" src="lstl6-28.htm" /> <frame name="display" src="bofright.htm" /> </frameset> </html> Две кнопки на странице, представленной листингом 16.28, позволяют распечатать весь набор фреймов (в поддерживающих эту операцию браузерах) или только нижний фрейм. При печати набора фреймов на последний создается ссылка с участием ключевого слова parent. Если вам не понравился результат печати документа, то воспользуйтесь командами браузера, а не средствами JavaScript. Глава 16. Объекты window и frame 457
<html> <head> <title>Print()</title> </head> <body> <form> <input type="button" name="printWhole" value="Print Entire Frameset" onclick="parent.print()" /> <p><input type="button" name="printFrame" value="Print Bottom Frame Only" onclick="parent.display.print()" /></p> </form> </body> </html> См. также: методы window. back (), window. forward (), window. home {), window.find(). prompt (" сообщение", " поУмолчанию") Возвращаемое значение: строка текста, введенная пользователем, или null Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Третий тип диалогового окна, отображаемого JavaScript, содержит сообщение, которое задается автором сценария, и две кнопки (ОК и Cancel (Отмена) или Yes и No в NN2 и NN3 для платформы Мае). Автор сценария может задать предварительный вариант: если значение по умолчанию приемлемо, пользователю достаточно щелкнуть на кнопке ОК (или нажать клавишу <Enter>) без дополнительного введения данных. Важно указать оба аргумента метода window. prompt (). Даже если нет необходимости задавать ответ по умолчанию, в качестве второго параметра следует указать пустую строку. prompt("What is your postal code?",""); Если второй параметр опущен, то поле диалогового окна JavaScript выведет строку undefined. Эта надпись обескураживает большинство посетителей Web-страниц. Значение, возвращаемое этим методом, представляет собой строку, находящуюся в поле диалогового окна в тот момент, когда пользователь щелкает на кнопке ОК. Если планируется запрашивать у пользователя число, то помните, что значение, возвращаемое данным методом, является строкой. Преобразование типа данных для последующих вычислений можно выполнить с помощью функций parselnt () или parseFloat () (см. главу 34). Если в момент щелчка на кнопке ОК текст в поле отсутствует, то метод возвращает пустую строку (" ")• Щелчок на кнопке Cancel заставляет метод возвратить значение null. Поэтому при создании сценария необходимо обеспечить проверку возвращаемого значения, чтобы убедиться, что пользователь ввел какое-либо значение, которое будет обрабатываться далее в сценарии. var entry = prompt("Enter a number between 1 and 10:",""); if (entry != null) { // Операторы, выполняемые при вводе значения } В этом фрагменте сценария результат метода присваивается переменной, а вложенные операторы выполняются лишь в том случае, если его значение не равно null (т.е. пользователь 458 Часть III. Объекты документа
щелкнул на кнопке ОК). Затем в сценарии осуществляется проверка принадлежности числа заданному диапазону (см. главу 43). Может показаться, что диалоговое окно запроса является удобным средством ввода пользовательских данных. Тот факт (и это справедливо для других диалоговых окон JavaScript), что оно является модальным, нарушает обычную процедуру навигации и может привести к некорректной работе макросов, используемых для автоматического перемещения по Web-узлам. Для ввода текста предпочтительнее использовать поля HTML-форм. Наиболее безопасный способ — это отображение диалогового окна после щелчка на определенной кнопке или элементе лишь в том случае, когда одной строки достаточно для введения всей необходимой информации. Последовательность диалоговых окон запроса данных применять не рекомендуется. Пример Функция, принимающая значение из диалогового окна ввода данных (листинг 16.29 и рис. 16.11), выполняет проверку данных, однако она еще не так совершенна, чтобы использовать ее на коммерческих Web-узлах. Вначале функция проверяет равенство возвращаемого значения null (Отмена) или пустой строке (пользователь ничего не ввел и щелкнул на кнопке ОК). Детально о проверке данных речь пойдет в главе 43. 16.29. Диалоговое окно ввода данных f <html> <head> <title>window.prompt() Method</title> <script type=Mtext/javascriptM> function populateTable() { var howMany = prompt("Fill in table for how many factors?",""); if (howMany != null && howMany != "") { alert("Filling the table for " + howMany); //операторы проверки данных, //введенных в поля таблицы </script> </head> <body> <form> f <!-- другие операторы отображения таблицы --> <input type="button" name="fill" value="Fill Table..." onclick="populateTable()" /> </form> </body> </html> I Script ftompt Fi in tattt for how many facto»? In —EJSL-J | Рис. 16.11. Диалоговое окно запроса данных из листинга 16.29 См. также: методы window. alert (), window. confirm (). Глава 16. Объекты window и frame 459
releaseEvents {списохСобытий) Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN4, Moz-, Safari- Если в сценарии включен присущий только NN4 способ захвата событий объекта window (document или слоя), то его можно отключить с помощью метода releaseEvents (). Он не препятствует событиям достичь их конечной цели. После отключения захвата событий объектами, находящимися выше в иерархии, сами события не прекращают свое перемещение. Параметрами метода releaseEvents () являются события одного или нескольких типов. Каждый тип рассматривается отдельно; таким образом, если окно перехватывает все события, можно блокировать все или только некоторые типы событий. Например, если страница загружается и перехватывает три типа событий. window.captureEvents(Event.CLICK | Event.KEYPRESS | Event.CHANGE); Позднее можно отключить захват всех событий, кроме щелчка. window.releaseEvents(Event.KEYPRESS | Event.CHANGE); Окно продолжает перехватывать и обрабатывать события щелчка, а события keyPresa и change направляются напрямую к целевым объектам. Новый механизм (удаление получателя события) реализован в NN6 на основе модели событий W3C. Более подробно он описан в главах 14 и 25. См. также: методы window. captureEvents (), window. routeEvent {). resizeBy(deltaX,deltaY) resizeTo(внешняяШирина,внешняяВысота) Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacEE4+, NN4, Moz-, Safari 1 + Начиная с NN4 и ГЕ4, сценарии имеют возможность управлять размером текущего окна браузера "на ходу". Несмотря на то, что можно установить значения отдельных внутренних и (в NN) внешних свойств width и height, методы resizeBy () и resizeTo () позволяют выполнить эту задачу в одном операторе. В обоих случаях изменения относятся к правому нижнему углу окна: для перемещения левого верхнего угла применяются методы window. moveBy () или window. moveTo (). Каждый метод изменения размера требует различных параметров. Метод resizeBy () корректирует размер окна на определенное число пикселей вдоль одной или обеих осей. Например, для увеличения окна на 100 пикселей по горизонтали и 50 по вертикали используется оператор. window.resizeBy(100, 50); Оба параметра являются обязательными. Если необходимо изменить размер только в одном направлении, другой аргумент необходимо установить в значение нуль. Используя отрицательные значения, размер окна можно уменьшить. Метод resizeTo () применяется часто, особенно когда известно, что на определенной платформе окно требует корректировки ширины и высоты для улучшенного отображения элементов форм. Параметрами метода resizeTo () выступают реальные внешние ширина и высота окна в пикселях— они совпадают со свойствами window. outerWidth и window. outerHeight в NN. Изменить размер окна так, чтобы оно занимало всю доступную часть экрана (за исключением панели задач в Windows и строки меню в Macintosh), можно с помощью свойств объекта screen, указывающих размеры доступного пространства. window.resizeBy(screen.availWidth, screen.availHeight); 460 Часть III. Объекты докумет
Тем не менее, это действие не совпадает с открытием окна во весь экран в системе Windows. Для достижения такого эффекта окно необходимо поместить в точке (-4,-4) и добавить восемь к двум параметрам метода resizeBy (). window.moveTo(-4,-4); window.resizeTo(screen.availwidth + 8, screen.availHeight + 8); Этот фрагмент кода скрывает границы окна шириной четыре пикселя, что, собственно, и происходит при открытии окна во весь экран с помощью средств операционной системы (см. также описание объекта screen (глава 38), в котором подробно указаны специфические для операционной системы атрибуты). На практике в NN4 метод resizeTo () не возвращает однозначных результатов. На некоторых платформах задаются внутренние размеры, а не внешние. Если требуется гарантировано задать внешний размер, то предпочтительнее использовать свойства window. outerHeight и window. outerWidth. 1 Netscape Navigator накладывает определенные ограничения на максимальный и минимальный размер окна. Оба типа ограничений задаются видимой областью экрана и минимально различимым окном браузера. Ограничения не накладываются на защищенные сценарии (см. главу 46). С разрешения пользователя окно может принять размеры, большие видимой области экрана. Пример Вы можете смело экспериментировать с методами изменения размера окна, если воспользуетесь листингом 16.30. Два раздела формы позволят вывести значения отдельно для каждого метода. В первом разделе вы также можете указать количество повторных перемещений, чтобы лучше ознакомиться с эффектом метода. |fawr 16,30. Методы <html> <head> <title>Window Resize Methods</title> <script type="text/javascript"> function doResizeBy(form) { var x = parselnt(form.resizeByX.value); var у = parselnt(form.resizeByY.value); var count = parselnt(form.count.value); for (var i = 0; i < count; i++) { window.resizeBy(x, y); } } function doResizeTo(form) { var x = parselnt(form.resizeToX.value); var у = parselnt(form.resizeToY.value); window.resizeTo(x, y); } </script> </head> <body> <form> <b>Enter the x and у increment, plus how many times the window should be resized by these increments: </bxbr /> Horiz:<input type="text" name="resizeByX" size="4" /> Vert:<input type="text" name="resizeByY" size="4" /> How Many:<input type="text" name=Mcount" size="4" /> Глава 16. Объекты window и frame 461
<input type="button" name="ResizeBy" value="Show resizeByO" onclick="doResizeBy(this.form) " /xhr /> <b>Enter the desired width and height of the current window: </bxbr />Width:<input type="text" name="resizeToX" size="4" /> Height:<input type="text" name="resizeToY" size="4" /> <input type="button" name="ResizeTo" value="Show resizeTo()" onclick="doResizeTo(this.form)" /> </form> </body> </html> См. также: свойства window. outerHeight, window. outerWidth; методы window.moveToO , window, sizeToContent (). routeEvent (событие) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN4, Moz-, Safari- Если в сценарий включен присущий NN4 способ захвата событий объектов окна, документа или слоя (с помощью метода captureEvents ()), обработчики перехватят события и не допустят их отправки в целевые объекты. Такой подход используется при разработке определенных страниц, что позволяет объектам более высокого уровня обрабатывать все события определенного типа. Если же целью разработчика является предварительная обработка событий до отправки их в точку назначения, ему необходимо организовать способ их отправки по обычному маршруту. Этой цели и служит метод routeEvent (). Возможно, более общей причиной перехвата событий на уровне окна (или подобном ему) служит обработка особых действий, например нажатия клавиши <Ctrl> с одновременным щелчком на элементе. В этом случае, даже если обработчик получает все события щелчка, он производит последующую обработку лишь тогда, когда свойство event .modifiers oik ределяет, что клавиша <Ctrl> нажата, а свойство eventObj . target указывает на элемент ссылки, а не кнопки. Все другие варианты события щелчка направляются в свои пункты назначения. Объект event знает, куда отправляются события, поэтому в методе routeEvent () специально это указывать не нужно. Аргументом метода routeEvent () является объект события, который передается функции, обрабатывающей событие высокого уровня. function flashRed(evt) { [операторы, устанавливающие красный фон по определенному событию] routeEvent(evt); } Объект события evt используется для отправки объекту, на котором произошел щелчок, в неизмененном виде. В модели событий W3C DOM (реализованной в NN6) перехваченное событие продолжает путь к целевой точке после того, как завершается цепочка обработки в более высоком в иерархической структуре элементе. Пример Пример использования метода routeEvent О приведен в листинге 16.21 при рассмотрении метода window. captureEvents (). См. также: методы window. captureEvents О , window. releaseEvents О, window. handleEvent (); объект event (глава 25). 462 Часть III Объекты документ
scroll (горКоордин, вертКоордин) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ Метод window, scroll () появился впервые в браузере NN3 и затем был реализован во всех браузерах, поддерживающих языки написания сценариев. Однако вскоре он был заменен методом window. scroll То (), который синтаксически лучше сочетается с другими методами объекта окна. Если страница предназначена для пользователей NN3, применяется метод window, scroll (), в NN4+ и IE4+ лучше воспользоваться методом window. scrollTo (). Метод window, scroll () имеет два параметра: горизонтальная (х) и вертикальная (у) координаты документа, отвечающие левому верхнему углу документа в окне или фрейме. Йомните, что окно и документ имеют похожие, но независимые системы координат. С точки зрения окна, координаты левой верхней точки (области содержимого) равны (0,0). Координаты левой верхней точки всех документов также равны (0,0). Точка (0,0) окна неподвижна, а в документе она имеет возможность перемещаться — при прокрутке вручную или с помощью сценария. Несмотря на то, что метод scroll () принадлежит окну, он ведет себя как метод документа, перемещая последний в пределах окна. И наоборот, можно считать, что окно движется, чтобы переместить свою точку (0,0) в определенную часть документа. Аргументы могут принимать значения, большие размера документа или меньшие нуля, однако конечный результат зависит от используемой платформы. На текущий момент метод window.scroll () наиболее подходит для прокрутки в верхнюю часть документа (window. scrol 1 (0, 0)), чтобы переместить пользователя к началу. Для вертикальной прокрутки большого документа лучшей альтернативой может служить дескриптор ссылки на анкер (хотя он не позволяет задавать положение документа по горизонтали). Пример Чтобы продемонстрировать возможности метода scroll (), в листинге 16.31 был создан набор фреймов с документом в верхнем фрейме (листинг 16.32) и панелью управления в нижнем фрейме (листинг 16.33). В последнем представлено несколько кнопок и текстовых полей — с их помощью и прокручивается верхний документ. В качестве содержимого документа выбрано большое GIF-изображение. <html> <head> <title> window.scroll() Method </title> </head> <frameset rows="50%,50%"> <frame src="lstl6-32.htm" name="display" /> <frame src="lstl6-33.htm" name="control" /> </frameset> </html> 16.32. Прокручиваемое изображение .V,"'j "\ ;; * ^ \ <html> <head> Глава 16. Объекты window и frame 463
<title> Arch </title> </head> <body> <hl> A Picture is Worth... </hl> <hr /> <center> <table border="3"> <caption align*"bottom"> A Splendid Arch </caption> <tr> <td> <img alt="image" src="arch.gif" /> </td> </tr> </table> </center> </body> </html> chtml> <head> <title> Scroll Controller </title> <script type="text/javascript" > function scroll(x,y) { parent.frames[0].scroll(x, y); } function customScroll(form) { parent.frames[0].scroll(parselnt(form.x.value), parselnt(form.у.value)); } </script> </head> <body> <h2> Scroll Controller </h2> <hr /> <form name="fixed"> Click on a scroll coordinate for the upper frame: <p> <input type="button" value="0,0" onclick="scroll(0,0)" /> <input type="button" value^'^,100" onclick="scroll(0,100)" /> <input type="button" value="100/0" onclick="scroll(100,0)" /> </p> 464 Часть III Объекты документ*
<р> <input type="button" value="-10 0,10 0" oriclick="scroll(-100,100) ■■ /> <input type="button" value="20,200" onclick="scroll(20,200)" /> <input type="button" value="1000,3000" onclick="scroll(1000,3000)" /> </p> </form> <hr /> <form name="custom"> Enter a Horizontal <input type="text" name="x" value="0" size="4" /> and Vertical <input type="text" name="y" value="0" size="4" /> value. Then <input type="button" value="click to scroll" onclick="customScroll(this.form)" /> </form> </body> </html> Обратите особое внимание на функцию customScroll (). JavaScript должен конвергировать строковые значения, введенные в текстовых полях, в целые числа (с помощью метода parselnt ()). Нечисловые данные вызывают сбои. См. также: методы window. scrollBy (), window. scrollTo (). scrollBy(del taX, del taY) scrollTo (x#y) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ4+, NN4+, Mozl+, Safari 1+ Современные браузеры располагают связанными методами, предназначенными для прокрутки окна. Метод window. scrollTo () представляет собой новую версию метода window, scroll (). Оба они работают идентично, размещая определенную точку документа в левом верхнем углу окна. Нежелательная прокрутка Многие Windows-совместимые компьютеры оснащены мышью, которая имеет колесико прокрутки, активизируемое по нажатию. Помните, что даже та страница, которая загружена в окно или фрейм без полос прокрутки, будет прокручиваться при использовании этого элемента мыши (если документ или его фоновое изображение больше, чем видимая область окна). Пользователи могут даже не заметить, что прокрутили страницу (поскольку она не имеет соответствующих полос). Если это влияет на дизайн страницы, необходимо создать процедуру (с помощью метода setTimeout ()), которая будет периодически устанавливать координаты документа в значение 0,0. Метод window. scrollBy () позволяет указать относительное положение документа в окне. Аргументы указывают, на сколько пикселей необходимо прокрутить окно (по горизонтали или вертикали). Значения могут быть и отрицательными (прокрутка влево и/или вверх). Метод scrollBy () оказывается удобным, если вы отключили полосы прокрутки, он предлагает пользователям альтернативный способ навигации внутри окна. Например, для перемещения на один экран в длинном документе можно воспользоваться свойством window. innerHeight (в NN) или document .body. clientHeight (в IE) для определения смещения относительно текущей позиции. Глава 16. Объекты window и frame 465
if (document.body && document.body.clientHeight) { window.innerHeight = document.body.clientHeight; } window.scrollBy(0, window.innerHeight); При прокрутке вверх второй аргумент должен быть отрицательным. window.scrollBy(0, -window.innerHeight); Прокрутка документов на платформе Macintosh демонстрирует ошибки в работе браузера. Иногда кажется возможной прокрутка документа за его пределы. На самом деле документ прокручивается до своей границы, но окно или фрейм не обновляются должным образом. Для получения эффекта прокрутки позиционируемого элемента применяются не только эти методы. Такой тип действий достигается путем установки свойств объекта style (см. главу 39). Пример Чтобы детально изучить методы scrollBy () и scrollToO, изучите листинги 16.34 и 16.35. Замените метод scrol 1То () на scroll (). Полученный результат должен быть другим. В примере с методом scrollBy () начните с листинга 16.34. В нем загружается тот же документ, что и в листинге 16.32, но используется другая панель управления (листинг 16.35). Дивим* i&JMLifo&oo Дмлйшй nm MiiwrtitMM шптши ■ i <html> <head> <title> window.scrollBy() Method </title> </head> <frameset rows="50%/50%"> <frame src="lstl6-32.htm" name="display" /> <frame src="lstl6-35.htm" name="control" /> </frameset> </html> В листинге 16.35 все ссылки на свойства и методы окна относятся к фрейму display. Строковые значения, введенные в полях, преобразуются в числа с помощью глобальной функции parselnt (). <html> <head> <title> ScrollBy Controller </title> <script type="text/javascript"> function page(direction) { var pixFrame = parent.display; var deltaY = (pixFrame.innerHeight) ? pixFrame.innerHeight : pixFrame.document.body.scrollHeight; if (direction == "up") { deltaY = -deltaY; } 466 Часть III. Объекты документа
parent.display.scrollBy(0, deltaY); } function customScroll(form) { parent.display.scrollBy(parselnt(form.x.value), parselnt(form.у.value)); } </script> </head> <body> <b>ScrollBy Controller</b> <form name="custom"> Enter an Horizontal increment <input type="text" name="x" value="0" size="4" /> and Vertical <input type="text" name="y" value="0" size="4" /> value.<br /> Then <input type="button" value="click to scrollByO" ч onclick= "customScroll (this, form) " /xhr /> <input type="button" value="PageDown" onclick="page('down')" /> <input type="button" value="PageUp" onclick="page('up')" /> </form> </body> </html> См. также: свойства window.pageXOffset, window.pageYOffset; метод window.scroll(). set Interval (■' выражение11, задержка [, язык]) setlnterval (ссылкаНаФункцию, задержка [, дрг1, • •., аргп]) Возвращаемое значение: целочисленный идентификатор интервала Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safari 1+ Важно понимать отличие между методами setlnterval () и setTimeout (). До того как метод setlnterval () стал частью языка JavaScript, авторы сценариев имитировали его поведение с помощью setTimeout (), что часто требовало дополнительных усилий. Метод setlnterval () используется тогда, когда в сценарии необходимо запускать функцию или выполнять некоторое выражение постоянно через определенный интервал времени. Интервал отличается от состояния задержки, которое доступно в других языках: в JavaScript другие процессы не приостанавливаются на этот период времени. Типичные приложения, например, реализуют с его помощью анимацию, которая достигается перемещением объекта по странице с определенной скоростью (без использования интервала JavaScript перемещает объект со скоростью, зависящей только от производительности процессора). В приложении-презентации метод setlnterval () позволяет "прокручивать" слайды в отдельных фреймах или слоях, изменяя вид страницы каждые десять секунд. Данный метод вполне подходит для отображения часов или другого цифрового устройства (в этой книге приведены примеры, в которых для достижения таких целей используются устаревшие способы, применяющие метод setTimeout ()). Метод setTimeout () рекомендуется применять в тех случаях, когда необходимо запустить функцию или оператор через некоторое время в будущем (см. далее в этой главе). Исходная функциональность метода setlnterval () идентична в NN и Г£, однако каждый браузер предлагает дополнительные возможности в зависимости от указанных аргументов. Глава 16. Объекты window и frame 467
В простых случаях некоторые параметры подходят для всех браузеров, поддерживающих этот метод. Вначале мы рассмотрим именно такие аргументы. Первым параметром метода set Interval () является имя функции или выражения, которое необходимо запустить через заданный интервал времени. Значение представляет строку в кавычках. Если параметр является функцией, то в скобках запрещено использовать ее аргументы, кроме случая, когда они являются строками (см. раздел "Передача параметров функции"). Вторым аргументом метода является число в миллисекундах (тысячных долях секунды), которые задает интервал времени. Несмотря на то, что значение задается с высокой точностью, не стоит доверять ему на все 100%. Различные задержки внутренних процессов могут повлиять на длину указанного интервала времени. Как и setTimeout (), метод set Interval () возвращает целочисленный идентификатор процесса. Он позволяет завершить процесс методом clear Interval (). Единственным аргументом последнего является именно этот идентификатор. Такой механизм позволяет запустить несколько интервальных процессов, что позволит сценарию остановить любой из них, не прерывая при этом другие. IE4+ имеет дополнительный третий параметр, задающий язык сценариев для выражения или функции, указанной в первом аргументе. Поскольку вы используете JavaScript (он же JScript), в его установке нет необходимости. Передача параметров функции NN4+ обеспечивает простой механизм передачи параметров функции, запускаемой методом setInterval (). Для его применения первым аргументом^ должна быть не строка, а указатель на функцию (т.е. имя без скобок). Второй аргумент, как и ранее., — задержка в миллисекундах. Далее, начиная с третьего аргумента, указывается список параметров функции, разделенный запятой. intervallD = setlnterval(cycleAnimation, 500, "figurel"); Функция получает аргументы так же, как и любая другая функция. function cycleAnimation(elemlD) {...} Для применения метода setlnterval () в более широком диапазоне браузеров можно воспользоваться конкатенацией строк, поскольку функция передается методу как строковое выражение. Например, если функция обрабатывает события для поиска элемента, на котором щелкнул пользователь (чтобы начать выполнение анимационного движения), идентификатор этого элемента, содержащийся в переменной, можно передать функции следующим образом. function findAndCycleО { var elemID; // Выражения в этом блоке проверяют события и // извлекают, идентификатор элемента, // присваивая его переменной elemID intervallD = setlnterval("cycleAnimation(" + elemID + ")", 500); } Если при каждом запуске функции в методе setlnterval () ей требуется передать раз-, личные параметры, то советуем воспользоваться методом setTimeout () как последним оператором функции, вызывающим ее снова. Пример Пример использования метода setlnterval О можно рассмотреть в двухфреймовой среде (листинг 16.36). 468 Часть III. Объекты документа
16.36. Набор фреймов дж* призера метода в в t in t e rval о <html> <head> <title>setlnterval() Method</title> </head> <frameset rows="50%,50%"> <frame src="lstl6-37.htm" name="control" /> <frame src="bofright.htm" name="display" /> </frameset> </html> В верхнем фрейме представлена панель управления, содержащая несколько кнопок, которые предназначены для автоматической прокрутки документа нижнего фрейма. Листинг 16.37 включает код документа панели управления. Многие операции, выполняемые с ее помощью, реализуются благодаря методу set Interval (). В начале сценария объявляется несколько глобальных переменных. Три из них представляют параметры, с помощью которых выполняется прокрутка документа. Последний — это идентификатор, возвращаемый методом setlnterval (). Глобальной эта переменная сделана затем, чтобы остальные функции могли отменить прокрутку, воспользовавшись методом clearlnterval (). Прокрутка документа выполняется с помощью функции autoScroll (). Для простоты все ее параметры также имеют глобальную область действия. Более того, этот прием позволяет выполнить автоматическую прокрутку документа с последними используемыми параметрами. Листинг 16.37. Йодяьдааш^ •etinte*v**?C> <html> <head> <title>ScrollBy Controller</title> <script type="text/javascript"> var scrollSpeec^ = 500; var scrollJump = 1; var scrollDirection = "down"; var intervalID; function autoScroll() { if (scrollDirection == "down") { scrollJump * Math.abs(scrollJump); } else if (scrollDirection == "up" && scrollJump > 0) { scrollJump = -scrollJump; } parent.display.scrollBy(0, scrollJump); if (parent.display.pageYOffset <= 0) { clearlnterval(intervallD); } } function reducelnterval() { stopScroll(); scrollSpeed -= 200; startScroll(); } function increaselnterval() { Глава 16. Объекты window и frame 469
stopScroll () ; scrollSpeed += 200; startScroll (); } function reduceJumpO { scrollJump -= 2; } function increaseJump() { scrollJump += 2; } function swapDirection() { scrollDirection = (scrollDirection == "down") ? "up" : "down"; } function startScroll() { parent.display.scrollBy(0/ scrollJump); if (intervallD) { clearlnterval(intervallD); } intervallD = setlnterval("autoScroll() ",scrollSpeed); } function stopScroll() { clearlnterval(intervallD); } </script> </head> <body onload="startScroll() "> <b>AutoScroll by setlnterval() Controller</b> <form name="custom"> <input type="button" value="Start Scrolling" onclick="startScroll()" /> <input type="button" value="Stop Scrolling" onclick^"stopScroll() " /> <pxinput type="button" value="Shorter Time Interval" onclick="reduceInterval()" /> <input type="button" value="Longer Time Interval" onclick="increaseInterval()" /></p> <pxinput type =" but ton" value= "Bigger Scroll Jumps" onclick="increaseJump()" /> <input type="button" value="Smaller Scroll Jumps" onclick="reduceJump()" /></p> <pxinput type= "button" value= "Change Direction" onclick="swapDirection()" /></p> </form> </body> </html> Метод setlnterval () вызывается в функции startScrollO. Эта функция исходно прокручивает страницу на один интервал scrollJump. Данная операция выполняется для определения возможности прокрутки страницы вверх с помощью функции autoScroll (), выполняемой перед основной частью сценария. В функции проверяется существование переменной intervallD. Если такая существует, то она очищается перед установкой нового значения. Это очень важная операция, поскольку повторный щелчок на кнопке Start Scrolling приведет к установке нескольких интервалов. Тем не менее, в переменной intervallD сохраняется только последний интервал. Упомянутая проверка выполняется с той целью, чтобы удостовериться в установке только одного интервала. Одна из глобальных переменных, scrollSpeed, используется для сохранения задержки, подставляемой в качестве аргумента 470 Часть ///. Объекты документа
метода set Interval (). Чтобы динамически изменить это значение, сценарий должен прервать текущий процесс, изменить переменную s с го 11 Speed и запустить новый процесс. См. также: методы window. clear Interval (), window. setTimeout (). ееtTimeout ("выражение", задержка [, язых]) setTimeout (ссылкаНаФункцию, задержка [, aprl, . •., аргп]) Возвращаемое значение: идентификатор для использования в методе window, clear- Timeout() Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Этот метод имеет непривычное имя, особенно для тех, кто уже работал с задержками в других языках программирования. В JavaScript задержка представляет собой интервал времени (в миллисекундах) перед выполнением выражения. Данный метод устанавливает задержку не в выполнении сценария, а в запуске выражения или функции. Операторы, следующие после вызова setTimeout (), выполняются немедленно. Пусть, например, Web-страница позволяет пользователям взаимодействовать с различными кнопками или полями в пределах указанного интервала времени (страница с презентацией). Можно установить задержку, скажем, в две минуты (120 тысяч миллисекунд), после которой (если пользователь не взаимодействовал со страницей ) страница будет прокручиваться вверх или выводить подсказку. При отключении задержки, когда пользователь осуществляет навигацию, необходимо, чтобы одна из кнопок вызывала метод clearTimeout () (см. ранее в этой главе). Несколько таймеров могут запускаться одновременно. При этом они совершенно независимы друг от друга. Несмотря на то, что исходная функциональность метода setTimeout () идентична в NN и Ш, каждый браузер предлагает дополнительные возможности в зависимости от указанных аргументов. В простых случаях некоторые параметры подходят для всех браузеров, поддерживающих этот метод. Вначале мы рассмотрим именно такие аргументы. Первым аргументом метода window. setTimeout () является строка в кавычках, содержащая вызов функции, метода или просто оператора JavaScript. По истечении временной задержки выражение выполняется. Важно понимать, что установленная задержка не прерывает выполнения сценария. При использовании метода setTimeout () в сценарии немедленно выполняются следующие после него операторы, и лишь после указанного интервала времени запускается выражение в скобках. Поэтому рекомендуется устанавливать задержку в последнем выражении функции: пусть сначала будут выполнены все остальные операторы, а затем метод setTimeout () прервет последующее выполнение сценария на определенный интервал времени. В действительности если этот метод запущен, пользователь может совершенно однозначно выполнять действия. После того, как задержка будет задана, время корректировке не поддается. Для выполнения такой задачи необходимо сначала отменить задержку и установить новую. Если метод setTimeout () используется внутри функции, ее следует разбить на две части, применив метод как разделитель. Пример такого подхода приведен в листинге 16.26, где IE требуется небольшая задержка для открытия окна до того, как в него будут записываться данные. Если бы задержки не требовалось, то обе части действия можно было бы выполнить в одной функции. Зачастую метод setTimeout () запускается из функции, которая указана в его аргументе. Например, если применяется Java-аплет, взаимодействие с которым осуществляется с помощью LiveConnect, сценарию нужно подождать некоторое время до его полной загрузки и инициализации. Несмотря на то, что обработчик события onload показывает, что объект аплета доступен сценарию, он ничего не сообщает о его состоянии. Для этого создается Глава 16. Объекты window и frame 471
функция JavaScript, которая каждые 500 миллисекунд проверяет внутреннее значение аплета, указывающее на степень его готовности. var t function autoReport() { if (!document.myApplet.done) { t = setTimeout ("autoReport ()•', 500) ; } else { clearTimeout(t); // операторы, использующие данные аплета // .> JavaScript не имеет встроенного эквивалента команды wait. Наихудшей ее реализацией может служить цикл, приостанавливающий дальнейшее выполнение сценария на определенное время. К сожалению, этот подход прекращает выполнение других процессов, поэтому предпочтительнее пользоваться методом setTimeout (). NN4+ имеет механизм передачи параметров функции, заданной в первом аргументе метода setTimeout () (см. раздел "Передача параметров функции", в котором описывался метод window. set Interval ()). Замечание для программистов: ни set Interval (), ни setTimeout () не порождают новых процессов для выполнения своих операций. Когда интервал истекает и вызывается функция, этот процесс размещается в конце очереди на преобразование интерпретатором JavaScript. Пример При загрузке HTML-страницы из листинга 16.38 запускается функция updateTime{), которая отображает в строке состояния текущее время (в формате hh:mm am/pm). Вместо того, чтобы выводить в строке состояния секунды (многих это обескураживает), эта функция в качестве последнего символа значения времени использует звездочку (*), которая появляется и исчезает через секунду. Листинг 16.3& Отображен <html> <head> <title>Status Bar Clock</title> <script type="text/javascript"> var flasher = false; function updateTime() { var now = new Date(); var theHour = now.getHours() ; var theMin = now.getMinutes0; var theTime = »" + ((theHour > 12) ? theHour - 12 : theHour); theTime += ((theMin < 10) ? ":0" : ":") + theMin; theTime += (theHour >= 12) ? " pmM : " am"; theTime += ((flasher) ? " " : "*"); flasher = ! flashes- window, status = theTime; timerlD = setTimeout("updateTime()",1000) ; } </script> </head> <body onload="updateTime()"> </body> </html> 472 Часть III. Объекты документа
В такой функции метод setTimeout () используется следующим образом. Как только текущее время (включая мерцающую звездочку) появятся в строке состояния, выполнение сценария приостанавливается на 1 секунду (1000 миллисекунд), спустя которую функция вызывается повторно. Вам не нужно очищать значение timerID, поскольку JavaScript это делает автоматически каждые 1000 миллисекунд. Возникает логический вопрос: почему не использовать метод set Interval () ? В данном случае большой разницы нет. Оба метода прекрасно справятся со своей задачей. В последнем случае вам необходимо установить интервал вне функции updateTime () .При этом сценарий не будет выполняться в браузерах версии, ниже IE4 и NN4, а код из листинга 16.38 выполняется. Чтобы продемонстрировать, как в функцию updateTime () подставляются параметры, представьте время, отображаемое в строке состояния, с помощью переменных. Таким образом, в функции будет использоваться параметрическая переменная, изменяющаяся каждый раз при вызове метода setTimeout (). Для всех браузеров функция будет выглядеть следующим образом. function updateTime(i) { window.status = theTime + " (" + i + ")"; // подстановка обновленного значения счетчика timerlD = setTimeout("updateTime(" + i+1 + ")",1000); } При выполнении этой функции в NN4+ можете использовать более удобную запись последнего оператора. timerlD = setTimeout(updateTime,1000, i + 1); В любом случае обработчик onload также необходимо изменить. onload = "updateTime(0)"; См. также: методы window.clearTimeoutО , window.setInterval(), window.clearlnterval(). showModalDialogCURL" [/ аргументы] [, средства]) showModelessDialog(" URL"[, аргументы] [, средства]) Возвращаемое значение: returnValue (модальные) или объект window (безрежимные) окна Совместимость: WinDE4+, МасГ£4+, NN-, Moz-, Safari- IE4+ поддерживает методы открытия модальных диалоговых окон, отображение которых делает главное окно браузера недоступным пользователю. В IE5 разработчики Microsoft добавили безрежимный тип диалогового окна, которое также отображается поверх основного окна, но разрешает доступ к последнему. В диалоговое окно можно загрузить любую HTML-страницу или изображение, указав URL в аргументе метода. Дополнительные параметры позволяют передать окну данные, управляющие его видом. К сожалению, такие типы окон не поддерживаются в NN. В лучшем случае их поведение можно эмулировать, но эта задача не под силу начинающим. Окна, генерируемые обоими методами, представляют (почти) полноценные объекты window с некоторыми полезными дополнительными свойствами. Вероятно, наиболее важным из них является window.dialogArgument. Это свойство позволяет сценарию читать данные, передаваемые окну во втором аргументе showModalDialog () или showModelessDialog (). Они могут иметь любой из поддерживаемых в JavaScript типов, включая объекты и массивы. Глава 16. Объекты window и frame 473
Вывод модального диалогового окна, как правило, приводит к ветвлению сценария. В частности, его выполнение приостанавливается на операторе, вызывающем метод showModalDialog (), до тех пор, пока окно остается отображенным на экране. В это время выполняются сценарии документа из этого диалогового окна. После его закрытия продолжается выполнение сценария в главном окне. Вызов безрежимного диалогового окна не приводит к остановке выполнения сценария в главном окне, так как сценарии из разных окон могут взаимодействовать друг с другом в режиме реального времени. Данные диалогового окна Чтобы передать данные из модального диалогового окна главному, сценарий должен установить свойство window.returnValue равным необходимому значению. Именно его и возвращает метод setModalDialog (), как показано ниже. var specifications = window.showModalDialog("preferences.html"); Данные находятся под полным управлением сценария. Автоматически метод не возвращает никаких значений. Поскольку безрежимное диалоговое окно доступно одновременно с главным, возврат данных из него не так прямолинеен, как для модального окна. Второй аргумент метода showModelessDialogO выполняет специальную задачу: в нем указывается ссылка на глобальную переменную или функцию. Сценарий безрежимного окна использует ее как способ передачи данных главному окну (когда пользователь закрывает безрежимное окно или, например, щелкает на кнопке Apply). Этот механизм даже позволяет передать данные функции в главном окне. Например, пусть в нем определена функция. function receivePrefsDialogData(a, b, с) { // операторы обработки входных значений // } При открытии безрежимного окна следует передать ссылку на эту функцию. dlog = showModelessDialogP'prefs.html", receivePrefsDialogData); В новом окне этой ссылкой можно воспользоваться, например, в функции обработчика события onclick для кнопки Apply. var returnFunc - window.dialogArguments; function apply(form) { returnFunc(form.color.value, form.style.value, form.size.value); } Данный подход блокирует способы получения параметров диалоговым окном при открытии, однако им всегда можно пользоваться для непосредственной установки значений полей форм или переменных в главном окне. dlog = showModelessDialogC'prefs.html", receivePrefsDialogData); dlog.document.forms[0].userName.value = GetCookie("userName"); Помните, что диалоговое окно, открытое каким-либо из двух методов, не поддерживает связь с главным окном с помощью свойства opener. Его значение не определено. Свойства диалогового окна Оба метода имеют дополнительный, третий аргумент, указывающий состояние дополнительных элементов окна. Если он опущен, все элементы отображаются по умолчанию. Все параметры задаются в одной строке, и каждый из них представлен парой имя-значение с син-; таксисом attribute rvalue, подобным используемому в CSS-стилях. Все возможные для двух типов окна свойства перечислены в табл. 16.4. Если вам необходима совмести- 474 Часть III. Объекты документ* i
мость с IE4, то ваши возможности ограничены только модальным окном и набором свойств, отмеченных в таблице. Все значения (кроме принадлежащих булевому типу) принимают одно из четырех значений: yes, no, 1, 0. Р*д«^16Л Свойствадиа^ ^ */ •• ^ Свойство Тип ° Описание center Булев dialogHeight Длина dialogLeft dialogTop dialogWidth edge help resizable status Целочисленный умолчанию yes Разное Разное Целочисленный Разное Длина Строка Булев Булев Булев Разное raised| sunken yes no Разное Центрирование диалогового окна (отменяется свойствами dialogLef t И/ИЛИ dialogTop)' Внешняя высота окна. В IE4 длина по умолчанию указывается в em; в IE5 - в рх Смещение диалогового окна от левого края экрана в пикселях Смещение диалогового окна от верхнего края экрана в пикселях Внешняя ширина окна. В IE4 длина по умолчанию указывается в em; в IE5 — в рх Стиль границы Отображение значка Help (Справка) в заголовке. Возможность изменения размеров окна (только в IE5+) Отображение строки состояния внизу окна (только в IE5+). Для непроверенных диалоговых окон значение по умолчанию yes; для проверенных — по. Синтаксис CSS позволяет разместить в одной строке любое количество свойств, разделенных точкой с запятой. var dlogData = showModalDialogC'prefs.html", defaultData, "dialogHeight:300px; dialogWidth:46Opx; help:no"); Хотя это не указано явно в свойствах диалогового окна, если содержимое выходит за его пределы, в окне отображаются полосы прокрутки. Если это нежелательно, при открытии страницы следует установить свойство document .body. scroll в значение false. Предупреждения, касающиеся использования диалоговых окон Потенциальная проблема (с точки зрения пользователя) заключается в том, что обычно диалоговое окно не отображается до тех пор, пока в него полностью не загружен HTML- файл. Поэтому, когда происходит загрузка сложного документа, возникает пауза, при которой пользователь не видит каких-либо признаков активности. В данном случае можно поэкспериментировать со стилевым свойством cursor, временно изменив его, а затем восстановив по окончании загрузки документа. Одной из причин, по которым я назвал диалоговое окно почти объектом window, является то, что в IE4 недоступны некоторые обычные свойства этого объекта. Например, если в диалоговое окно загрузить набор фреймов, внутренние сценарии не смогут получить доступ к переменным или методам родительского окна. Поэтому кнопка в модальном диалоговом окне Ш4 не сможет запустить метод parent. close () для его закрытия. Такой недочет устранен в Ш5. Глава 16. Объекты window и frame 475
Пример Чтобы продемонстрировать два типа диалоговых окон, мы наделили модальное и немодельное окна одинаковыми функциональными возможностями. Впоследствии вы сможете научиться правильно передавать данные из основного окна в оба типа диалоговых окон и наоборот. Первый пример касается использования модального окна. В данном случае данные подставляются в диалоговое окно, а в сценарий возвращаются значения. Листинг 16.39 представ^ ляет HTML-код и код сценария основной страницы. Обработчик onclick запускает функцию, отображающую диалоговое окно на экране. Документ диалогового окна (листинг 16.40) содержит несколько элементов управления, с помощью которых вводится имя пользователя и задаются отдельные цвета основного документа. Данные, получаемые из диалогового окна, заносятся в массив и передаются в основное окно. Массив после закрытия диалогового окна сохраняется в локальной переменной pref s. Как только пользователь отменяет введенные в диалоговом окне данные (кнопка Отмена), возвращается пустая строка, поэтому в формуле get Pref sData () данные не обрабатываются. При щелчке на кнопке ОК массив заполняется данными. Каждый элемент массива считывается и приравнивается к значению свойства или элемента управления. Все эти данные также сохраняются в глобальном массиве currPref s. Это позволяет отправить данные в диалоговое окно (в качестве второго аргумента метода showModalDialog ()) при последующем отображении его на экране. /Щш/Ш 1&39* Основной документ прщмдо для метода <html> <head> <title>window.setModalDialog() Method</title> <script type="text/javascript"> var currPrefs = new Array(); function getPrefsDataO { var prefs = showModalDialog("lstl6-40.htm", currPrefs, "dialogWidth:400px; dialogHeight:ЗООрх"); if (prefs) { if (prefs["name"] ) { document.all.firstName.innerText = prefs["name"]; currPrefs["name"] = prefs["name"]; } if (prefs["bgcolor"]) { document.body.style.backgroundColor = prefs ["bgColor"] ; currPrefs["bgColor"] = prefs["bgColor"]; } if (prefs["textColor"]) { document.body.style.color = prefs["textColor"]; currPrefs["textColor"] = prefs["textColor"]; } if (prefs["hlSize"]) { document.all.welcomeHeader.style.fontSize = prefs["hlSize"]; currPrefs["hlSize"] = prefs["hlSize"]; } ' } } function initO { document.all.firstName.innerText = "friend"; 474» Часть III. Объекты документа
</script> </head> <body bgcolor="#EEEEEE" style="margin:20px" onload="init()"> <hl>window.setModalDialog() Method</hl> <hr /> <h2 id="welcomeHeader">Welcome, <span id="firstName">&nbsp; </span>!</h2> <hr /> <p>Use this button to set style preferences for this page: <button id="prefsButton" onclick="getPrefsData()"> Pref erences</buttonx/p> </body> </html> Документ диалогового окна, представленный листингом 16.40, запрашивает данные у пользователя (для этого используются специальные элементы управления) и передает полученную информацию в основное окно. Обратите внимание на то, что при выполнении сценария в заголовке диалогового окна отображается элемент title этого окна. После загрузки документа в диалоговое окно вызывается функция init (), анализирующая свойство window, di a logArguments. Если это свойство содержит данные, то они представляют текущие настройки основного окна. Функция setSelectedO назначает заданные в диалоговом окне настройки в качестве настроек основного окна. Кнопки в нижней части страницы располагаются так, чтобы отображаться в нижнем правом углу экрана. Каждая кнопка вызывает функцию, выполняющую необходимые действия и закрывающую диалоговое окно. В случае использования кнопки ОК функция handleOKO устанавливает в качестве значения свойства window. returnValue данные, полученные из функции getFormData (). Последняя функция считывает значение элемента управления и сохраняет его в массиве. Впоследствии эти данные можно легко использовать в сценарии основного окна, поскольку порядок следования элементов управления уже не будет играть особой роли. f &40. Документ модального <нша <html> <head> <title>User Preferences</title> <script type="text/javascript"> // Закрытие диалогового окна function closemeO { window.close(); } // Обработка щелчка на кнопке ОК function handleOKO { window.returnValue = getFormData(); closeme(); } // Обработка щелчка на кнопке Cancel function handleCancelО { window.returnValue = ""; closeme(); } Глава 16. Объекты window и frame 477
// Общая функция преобразования пар имя-значение элементов // формы в массив function getFormData() { var form = document.prefs; var returnedData = new Array(); // Получение данных для каждого типа элементов формы for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].type == "text") { returnedData[form.elements[i].name] = form.elements[i].value; } else if (form.elements[i].type.indexOf("select") != -1) { returnedData[form.elements[i].name] = form.elements[i].options[form.elements[i]. selectedlndex].value; } else if (form.elements[i].type == "radio") { returnedData[form.elements[i].name] = form.elements[i].value; } else if (form.elements[i].type == "checkbox") { returnedData[form.elements[i].name] = form.elements[i].value; } else continue; } return returnedData; } // Инициализация - настройка элементов формы // соответственно введенным данным function init() { if (window.dialogArguments) { var args = window.dialogArguments; var form = document.prefs; if (args["name"]) { form.name.value = args["name"];. if (args["bgcolor"]) { setSelected(form.bgColor, args["bgColor"]); if (args["textColor"]) { setSelected(form.textColor, args["textColor"]); } if (args["hlSize"]) { setSelected(form.hlSize, args["hlSize"]); // Функция установки элемента select в одно значение function setSelected(select, value) { for (var i = 0; i < select.options.length; i++) { if (select.options[i].value == value) { select.selectedlndex = i; break; return; } // Функция обработки нажатия клавиши 478 Часть III. Объекты документ!,
// <Enter> вместо щелчка на кнопке ОК function checkEnterO { if (window.event.keyCode ==13) { handleOKO ; } } </script> </head> <body bgcolor="#EEEEEE" onload="init()"> <h2>Web Site Preferences</h2> <hr /> <form name="prefs" onsubmit="return false"> <table> <tr> <td>Enter your first name:<input name="name" type="text" value="" size="20" onkeydown="checkEnterO" /></td> </tr> <tr> <td>Select a background color: <select name=MbgColor"> <option value="beige">Beige</option> <option value="antiquewhite">Antique White</option> <option value="goldenrod">Goldenrod</option> <option value="lime">Lime</option> <option value="powderblue">Powder Blue</option> <option value="slategray">Slate Gray</option> </selectx/td> </tr> <tr> <td>Select a text color: <select name="textColor"> <option value="blackn>Black</option> <option value="white">White</option> <option value="navy">Navy Blue</option> <option value="darkorange">Dark Orange</option> <option value="seagreen">Sea Green</option> <option value="teal">Teal</option> </selectx/td> </tr> <tr> <td>Select "Welcome" heading font point size: <select name="hlSize"> <option value="12">12</option> <option value="14n>14</option> <option value="18">18</option> <option value="24">24</option> <option value="32">32</option> <option value=n48">48</option> </selectx/td> </tr> </table> </form> <div style="position:absolute; left:200px; top:220px"> <button style="width:80px" one lick= "handleOKO">OK</button>&nbsp;&nbsp; <button style="width:80px" onclick="handleCancel()">Cancel</button> </div> </body> </html> Глава 16. Объекты window и frame 479
Последним важным элементом модального окна, с которым следовало бы вас ознакомить, является обработчик onkeypress текстового поля. Он вызывается при нажатии клавиши <Enter>. Если при нажатии этой клавиши текстовое поле неактивное, то вызывается все та же функция handleOK (). Такой подход позволяет сделать кнопку ОК используемой по умолчанию. При переходе от модального окна к немодальному структура приложения несколько изменяется (листинг 16.41). В этом листинге показан документ, загружаемый в основном окне. В данном случае в сценарии инициализируется переменная Pref sDlog, которая возвращается методом showModelessWindow () и сохраняет ссылку на немодальное диалоговое окно. Эта переменная используется для вызова функции init () в немодальном диалоговом окне, но при этом принимает участие в условии конструкции if, анализирующей необходимость создания диалогового окна. Такая конструкция необходима, чтобы не допустить одновременного создания нескольких немодальных диалоговых окон. Новое диалоговое окно не создается до тех пор, пока переменная pref sDlog содержит значение и пока текущее диалоговое окно не будет закрыто (проверяется по свойству window .closed диалогового окна). Второй параметр метода showModelessDialog () представляет собой ссылку на функцию в основном документе, которая обновляет последний. Как вы сможете убедиться далее, эта функция вызывается из диалогового окна по щелчку пользователя на кнопке ОК или Apply диалогового окна. Я*спетМ41»0с1Ю§^ /< ■ **ъ< * ►* ■ »fao**o4*lDi*log() ЧЧ <html> <head> <title>window.setModelessDialog() Method</title> <script type="text/javascript"> var currPrefs = new Array(); var prefsDlog; function getPrefsData() { if (IprefsDlog || prefsDlog.closed) { prefsDlog = showModelessDialog("lstl6-42.htm", setPrefs, "dialogWidth:400px; dialogHeight:ЗООрх"); prefsDlog.init(currPrefs); } } function setPrefs(prefs) { if (prefs["bgcolor"]) { document.body.style.backgrourtdColor = prefs["bgColor"]; currPrefs["bgColor"] = prefs["bgColor"]; } if (prefs["textColor"]) { document.body.style.color = prefs["textColor"]; currPrefs["textColor"] = prefs["textColor"]; } if (prefs["hlSize"]) { document.all.welcomeHeader.style.fontSize = prefs["hlSize"]; currPrefs["hlSize"] = prefs["hlSize"]; } if (prefs["name"]) { document.all.firstName.innerText = prefs["name"]; currPrefs["name"] = prefs["name"]; 480 Часть ///. Объекты докумеип
} function init() { document.all.firstName.innerText = "friend"; } </script> / </head> <body bgcolor="#EEEEEE" style="margin:20px" onload="init()"> <hl>window.setModelessDialog() Method</hl> <hr /> <h2 id="welcomeHeader">Welcome, <span id="firstName">&nbsp; </span>i </h2> <hr /> <p>Use this button to set style preferences for this page: <button id="prefsButton" onclick="getPrefsData()"> Preferences</buttonx/p> </body> </html> Изменения в документе немодального диалогового окна (листинг 16.42) весьма ограничены. В нижнюю часть окна добавлена новая кнопка Apply. С ее помощью текущие настройки диалогового окна применяются к основному документу без закрытия первого. Кнопка Apply вызывает функцию handleApply (), которая выполняет все те же действия, что и функция handleOK (), но не закрывает диалогового окна. Однако эти функции взаимодействуют с данными основного окна несколько иначе чем в случае использования модального окна. Ссылка на функцию обработки данных основного окна подставляется в качестве второго аргумента метода showModelessDialog (); она представлена свойством window. dialogArgument s объекта диалогового окна. <html> <head> <title>User Preferences</title> <script type="text/javascript"> // Закрытие диалогового окна function closemeO { window.close(); } // Обработка щелчков на кнопке OK function handleOK() { var returnFunc = window.dialogArguments; returnFunc(getFormData()); closeme 0; }. // Обработка щелчков на кнопке Apply function handleApply() { var returnFunc = window.dialogArguments; returnFunc(getFormData()); } // Обработка щелчков на кнопке Cancel function handleCancel() { Глава 16. Объекты window и frame 481
} window.returnValue closeme(); // Общая функция преобразования пар имя-значение элементов // формы в массив function getFormData() { var form = document.prefs; var returnedData = new Array(); // Получение данных о каждом типе элементов формы for (var i = 0; i < form.elements.length; i++) { if (form.elements[i].type == "text") { returnedData[form.elements[i].name] = form.elements[i].value; } else if (form.elements[i].type.indexOf("select") != -1) { returnedData[form.elements[i].name] = form.elements[i].options[form.elements[i]. selectedlndex].value; } else if (form.elements[i].type == "radio") { returnedData[form.elements[i].name] - form.elements[i].value; } else if (form.elements[i].type == "checkbox") { returnedData[form.elements[i].name] = form.elements[i].value; } else continue; } return returnedData; } // Инициализация - настройка элементов формы // соответственно подставленным данным function init(currPrefs) { if (currPrefs) { var form = document.prefs; if (currPrefs["name"]) { form.name.value = currPrefs["name"]; } if (currPrefs["bgColor"]) { setSelected(form.bgColor/ currPrefs["bgColor"]); } if (currPrefs["textColor"]) { setSelected(form.textColor, currPrefs["textColor"]); } if (currPrefs["hlSize"]) { setSelected(form.hlSize, currPrefs["hlSize"]); } } } // Устанавливает элемент select в одно значение function setSelected(select, value) { for (var i = 0; i < select.options.length; i++) { if (select.options[i].value == value) { select.selectedlndex = i; break; } } 482 Часть III. Объекты документ*
return; // Функция обработки события нажатия клавиши // <Enter> вместо щелчка на кнопке ОК function checkEnterO { if (window.event.keyCode ==13) { handleOKO ; } } </script> </head> <body bgcolor="#EEEEEE" onload="init()"> <h2>Web Site Preferences</h2> <hr /> <form name="prefs" onsubmit="return false"> <table> <tr> <td>Enter your first name:<input name="name" type="text" valuer"" size="20" onkeydown="checkEnter()" /></td> </tr> <tr> <td>Select a background color: oelect name="bgColor"> <option value="beige">Beige</option> * <opt ion value="antiquewhite">Antique White</option> <option value="goldenrod">Goldenrod</option> <option value="lime">Lime</option> <option value="powderblue">Powder Blue</option> <option value="slategray">Slate Gray</option> </selectx/td> </tr> <tr> <td>Select a text color: <select name="textColor"> <option value="black">Black</option> <option value="white">White</option> <option value="navy">Navy Blue</option> <option value="darkorange">Dark Orange</option> <option value="seagreen">Sea Green</option> <option value="teal">Teal</option> </selectx/td> </tr> <tr> <td>Select "Welcome" heading font point size: <select name="hlSize"> <option value="12">12</option> <option value="14">14</option> <option value="18">18</option> <option value="24">24</option> <option value="32">32</option> <option value="48">48</option> </selectx/td> </tr> </table> </form> <div styles "position .-absolute; left:120px; top:220px"> <button style="width:80px" onclicks"handleOK()">OK</button>&nbsp;fcnbsp; Глава 16. Объекты window и frame 483
<button style="width:80px" onclick="handleCancel()"> Cancel</button>&nbsp;&nbsp; <button style="width:80px" onclick="handleApply()">Apply</button> </div> </body> </html> Вам придется самостоятельно решить, какой тип диалогового окна лучше использовать. Каждый из них есть имеет преимущества и недостатки. Решать только вам и пользователям создаваемых вами страниц. См. также: метод window. open (). sizeToContent() Возвращаемое значение: отсутствует Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari- Метод window. sizeToContent () в NN6+ применяется при проверке размера окна (особенно нового) на оптимальное отображение в нем содержимого. Однако при его использовании следует проявлять осторожность, иначе от него будет больше вреда, чем пользы. Выполнение метода sizeToContent () приводит к изменению размера окна таким образом, чтобы все его содержимое было максимально видимым на экране. Заботы о разных типах представления данных в различных операционных системах уже ушли в прошлое. Естественно, такое действие следует производить в окне, содержимое которого занимает меньшее пространство, чем предоставляет наименьший режим разрешения монитора (обычно 640x480 пикселей, однако в будущих версиях браузеров для портативных компьютеров будут применяться намного меньшие режимы). Если дважды запустить метод для окна, содержащего сценарий, могут возникнуть проблемы. Такое действие заставит окно принять больший размер, чем видимая область экрана Последующие вызовы метода могут и не придать окну нужного размера. Тем не менее, несколько вызовов вполне безопасно использовать для новых окон, если операторы сценария находятся в главном окне. Пример Приложение The Evaluator, загруженное в NN6, позволяет детально ознакомиться с методом sizeToContent (). Предполагается, что вы запускаете это приложение из папки примеров для главы 13. Вы можете открыть подокно для других примеров из этой главы и изменить его размер. Введите в верхнее поле приложения следующее выражение. а = window.ореп("1st13-02.htm","") а.sizeToContent() Теперь ширина окна браузера минимальна, а высота такова, что в окне отображается всего незначительная часть документа. См. также: метод window. resizeTo (). stop () Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN4+, Moz-, Safari- Поддерживаемый только в NN метод stopO снабжает сценарий кнопкой, аналогичной кнопке Stop (Стоп) на панели инструментов. Наличие этого метода позволяет создать на странице собственную панель инструментов и скрыть исходную (в новом окне или с помощью 484 Часть ///. Объекты документ*
защищенных сценариев в главном). Например, если на странице расположено изображение, имитирующее кнопку Stop, его можно сделать ссылкой, прекращающей загрузку страницы. <а href="javascript: void stop()"><img src="myStop.gif" border=0x/a> Сценарий не может прекратить загрузку своего документа — это возможно сделать только в другом фрейме или окне. Кроме того, если текущий документ динамически загружает новое изображение или элемент мультимедийного типа MIME, то метод stop () подходит только для остановки такого процесса. Несмотря на то, что метод stop () принадлежит объекту window, он не привязан к определенному окну или фрейму. См. также: методы window.back(), window.find(), window.forward(), window. home (), window. print (). Обработчики событий onafterprint onbeforeprint Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Bee эти обработчики (не поддерживаемые в Macffi5) запускаются по щелчку на кнопке ОК в диалоговом окне печати браузера Ш. Так происходит при печати вручную (с помощью меню или кнопок браузера) и при вызове метода window. print (). Печать обычно организована по принципу WYSIWYG, однако вполне возможно, что бумажная версия будет содержать больше или меньше информации, чем отображается на экране. Например, при выводе каждой страницы на бумагу к ней можно добавить сообщение об авторских правах. Тем не менее, свойство display таблиц стилей соответствующего элемента с таким содержимым при загрузке страницы может иметь значение попе. До начала печати документа, свойство необходимо изменить, чтобы элемент отображался как блоковый; по окончании процесса печати следует опять вернуться к исходному значению. Обработчик события onbeforeprint запускается сразу же после щелчка на кнопке ОК в диалоговом окне Print. После отправки страниц(ы) на принтер или в пул печати запускается обработчик onafterprint. Пример Следующий фрагмент кода взят из сценария страницы, содержащей элемент div, настройки стиля которой включают оператор display: none. При этом в заголовке страницы обработчики событий печати назначены свойствам. function showPrintCopyright() { document.all.printCopyright.style.display = "block"; function hidePrintCopyright() { document.all.printCopyright.style.display = "none"; } window.onbeforeprint = showPrintCopyright; window.onafterprint = hidePrintCopyright; onbeforeunload Совместимость: WinIE4+, МасШ5+, NN-, Moz-, Safari- Любое действие (пользователя или сценария), выгружающее текущую страницу или заменяющее ее новой, запускает обработчик события onbeforeunload. В отличие от обработчика Глава 16. Объекты window и frame 485
события onunload, onbef oreunload более эффективен в ситуации, когда сложному сценарию необходимо завершить работу до реальной выгрузки страницы. Кроме того, обработчик возвращает строковое значение, присвоенное свойству event. returnValue. Эта строка является частью сообщения в окне предупреждения, выводимом на рассмотрение пользователю. Если пользователь предпочитает остаться на странице, она не выгружается, и никаких действий не выполняется. Пример Пример использования обработчика onbef oreunload приведен в листинге 16.43. В нем показано, как отменить выгрузку документа из браузера. <html> <head> <title>onbeforeunload Event Handler</title> <script type="text/javascript"> function verifyCloseO { event.returnValue = "We really like you and hope you will stay longer."; } window.onbeforeunload - verifyClose; </script> </head> <body> <hl>onbeforeunload Event Handler</hl> <hr /> <p>Use this button to navigate to the previous page: <button id="go" onclick="history.back()"> Go Back</buttonx/p> </body> </html> См. также: обработчик события onunload. ondragdrop Совместимость: Winffi-, MacIE-, NN4, Moz-, Safari- При расширяющейся интеграции рабочего стола и браузеров можно разместить ярлыки (ссылки) на URL на рабочем столе или в других документах. NN4 позволяет запрограммировать операцию перетаскивания таких элементов в окно браузера. Событие dragdrop окна запускается тогда, когда пользователь перетаскивает в него файл или другой объект, имеющий собственный URL. Пример Обработчик события ondragdrop можно включить в дескриптор <body> и вместе с объектом события передать в него дополнительные сведения, определяющие, на каком элементе завершилась операция перетаскивания, а также URL перетаскиваемого элемента. Такую информацию получает и обрабатывает функция, вызываемая обработчиком события. Поскольку событие принадлежит окну, включать захват событий методом window. captureEvents() необходимости нет. 486 Часть III. Объекты документе
Основную характеристику события — URL перетаскиваемого элемента — можно получить только с помощью защищенного сценария с разрешения пользователя (см. главу 46). В листинге 16.44 приведен простой документ. Он отображает URL и позицию на экране, которые были получены с помощью объекта события, передаваемого вместе с событием dragdrop. Данный листинг лучше работает на платформе Windows. <html> <head> <title>DragDrop Event</title> ocript type="text/javascript"> function reportDrag(e) { var msg = "You dropped the file:\n"; netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserRead"); msg += e.data; netscape.security.PrivilegeManager. disablePrivilege("UniversalBrowserRead"); msg += "\nonto the window object at screen location ("; msg += e.screenX + ", " + e.screenY + ")."; alert(msg); return false; } </script> </head> <body ondragdrop="return reportDrag(event)"> <b>Drag and Drop a file onto this window</b> </body> </html> dragdrop является единственным событием, использующим свойство data объекта события в NN4. Это свойство содержит URL. Свойство target указывает на объект window. Чтобы получить координаты точки, в которой была отпущена кнопка мыши, следует обратиться к свойствам screenX и screenY объекта события. См. также: объект event (глава 25). onerror Совместимость: WinIE4+, МасГ£4+, NN3+, Mozl+, Safari 1+ См. описание свойства window. onerror ранее в этой главе. onhelp Совместимость: WinIE4+, MacEE4+, NN-, Moz-, Safari- Общий обработчик события onhelp рассматривался в главе 15, однако он запускается и тогда, когда пользователь активизирует контекстную справку внутри модального или безрежимного диалогового окна. В последнем случае пользователь может щелкнуть мышью на значке Help (Справка) в заголовке окна, после чего указатель примет форму вопросительного знака. После этого пользователь может щелкнуть на любом элементе окна. По второму щелчку запускается обработчик события onhelp, при этом объект события содержит информацию об элементе (ссылка на определенный элемент находится в свойстве event. srcElement), что позволяет сценарию вывести справочную информацию о нем. Глава 16. Объекты window и frame 487
Чтобы отключить появление встроенного справочного окна, обработчик события должен или заканчиваться оператором return false (IE4+), или устанавливать свойство event. re turn Value равным false (Ш5+). Пример Следующий фрагмент сценария можно реализовать в безрежимном диалоговом окне (только в Г£5), добавив его к листингу 16.44. В примере показано, как отображаются справочные сведения для двух полей формы. function showHelpO { switch (event.srcElement.name) { case "bgColor" : alert("Choose a color for the main window\■s background."); break; case "name" : alert("Enter your first name for a friendly greeting."); break; default : alert("Make preference settings for the main page styles."); } event.returnValue = false; } window.onhelp = showHelp Справка выводится для элементов формы; для этого в операторе switch используется их свойство name. Для других типов страниц более подходящим может оказаться свойство id. См. также: объект event (глава 25); оператор switch (глава 31) onload Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Обработчик события onload запускается в текущем окне по окончании загрузки документа (после пересылки всех текстовых и графических элементов с исходного сервера в браузер, а также загрузки всех модулей и Java-аплетов). К этому моменту память браузера содержит все необходимые объекты и компоненты сценария. Обработчик события onload является атрибутом дескриптора <body> для документа с одним фреймом или же дескриптора < frameset> для набора фреймов. В последнем случае событие происходит лишь после полной загрузки документов во всех указанных фреймах. Для вставки обработчика события onload используется один из двух следующих сценариев. <html> <head> </head> <body [другие атрибуты] onLoad=" операторИлиФункция" > [ содержимое] </body> </html> <html> <head> </head> <frameset [другие атрибуты] onLoad= " операторИлиФункция" > <f rame > спецификации фрейма</f rame > </frameset> </html> 488 Часть III. Объекты документа
Этот обработчик, являющийся частью определения набора фреймов, обладает специальным свойством: он не запускается до тех пор, пока не запустятся обработчики onload всех дочерних фреймов набора. Поэтому, если сценарии инициализации зависят от компонент, находящихся в других фреймах, их следует запускать в обработчике onload набора фреймов. Из всего этого следует одно из основных правил программирования на JavaScript: сценарии, запускаемые во время загрузки документа, должны участвовать в процессе генерирования документа и его объектов. Обработчик события onload может содержать дополнительные функции управления объектами документа. Обычно в обработчик события onload включают те операции, которые выполняются быстро и без вмешательства пользователя. Пользователи не должны ожидать окончания действий после загрузки страницы, они имеют право сразу взаимодействовать с ней. Ни в коем случае в обработчике onload не следует открывать модальное диалоговое окно. Если пользователи применяют макросы для автоматической навигации, нежелательно, чтобы процесс останавливался при выводе диалогового окна предупреждения, подтверждения или запроса. С другой стороны, такую операцию, как установка свойства window.defaultStatus, можно смело включить в обработчик события onload. To же самое относится к инициализации обработчиков событий как свойств объектов элементов страницы. См. также: обработчик события onunload; свойство window. defaultStatus. onmove Совместимость: Winffi-, MacIE-, NN4, Moz-, Safari- Когда пользователь перетаскивает окно браузера NN4, это действие вызывает событие move для объекта window. Когда обработчику события присваивается функция (например window. onmove = handleMoves), ей передается объект события; его свойства screenX и screenY содержат координаты точки (по отношению ко всему экрану), в которой находится левый верхний угол окна. См. также: объект event (глава 25). onresize Совместимость: WinIE4+, MacDE4+, NN4+, Mozl+, Safari- Если пользователь изменяет размеры окна, для объекта window запускается обработчик события onresize. Когда событию присваивается функция (например, window. onresize = handleResizes), объект события в NN имеет свойства width и height, содержащие ширину и высоту внешней части окна. Изменение размеров окна не должно приводить к перезагрузке документа, как это происходит при запуске обработчика onload (хотя некоторые ранние версии NN вызывают это событие). Изменение размеров окна браузера NN4, особенно если в нем содержатся позиционируемые элементы (div или layer), вызывает серьезные проблемы с отображением содержимого и с выполнением сценариев страницы. Содержимое накладывается, а сценарии могут совсем исчезнуть. Единственная надежда — в использовании обработчика события onresize для перезагрузки страницы. Некоторые идеи по поводу того, как обойти эту проблему, приведены в статье по адресу http://developer.netscape.com/viewsource/goodman_resize/ goodman_resize.html. В статье не рассказано о том, что версия NN4 для Windows запускает событие resize, когда в окне появляются полосы прокрутки. Это событие в определенной ситуации может привести к бесконечному циклу. Для его предотвращения следует проверить свойства window.innerwidth и window. innerHeight, показывающие, действительно ли изменилось окно (эти свойства сохраняют свои значения и при появлении полос прокрутки). Ниже /- Нязямвтеу Глава 16. Объекты window и frame 489
приведен пример кода, который размещается в дескрипторе заголовка страницы. Он предназначен для предотвращения этой проблемы в NN4. var Nav4 = (navigator.appName == "Netscape" && parselnt(navigator.appVersion) == 4); if (Nav4) { var loadWidth = window.innerWidth; var loadHeight = window.innerHeight; } function restore() { if (loadWidth != window.innerWidth || loadHeight != window.innerHeight) { history.go(0); } } if (Nav4) window.onresize = restore; См. также: объект event (глава 25). onunload Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Событие unload происходит в текущем окне непосредственно перед выгрузкой документа. Чаще всего выгрузка документа вызывается загрузкой нового HTML-документа или его созданием "на лету" средствами сценария. Желательно ограничить обработчик события onunload быстрыми операциями, которые не препятствуют переходу от одного документа к другому. Не используйте методов, открывающих диалоговые окна! Обработчики события onunload размещаются в тех же частях документа, что и обработчики onload: в атрибуте дескриптора <body> для однофреймового окна или в атрибуте дескриптора < frameset > для набора фреймов. Оба обработчика могут находиться водном дескрипторе (<body> или <frameset>, не вызывая проблем). Обработчик события onunload хранится в памяти браузера до тех пор, пока не произойдет событие unload. Следует высказать одно предостережение по поводу обработчика события onunload Несмотря на то, что событие происходит перед очисткой документа, не стоит связывать с ним такие долго выполняемые задачи, как генерирование новых объектов или отправка данных форм. Скорее всего, документ исчезнет до того, как функция завершится, в результате чего она будет обращаться к уже несуществующим значениям или объектам. Предпочтительно ограничить обработчик события onunload минимальным количеством действий. См. также: обработчик события onload. Элемент frame Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий allowTransparency borderColor contentDocument contentWindow 490 Часть III. Объекты документа:
Окончание таблицы Свойства Методы Обработчики событий frameBorder height longDesc marginHeight marginWidth name noResize scrolling src width Синтаксис Доступ к свойствам и методам объекта frame из элемента frameset. (IE4+) document .all. идентификаторФрейма. свойство \ метод ( [параметры] ) (IE5+/W3C) document. getElementByld ("идентификаторФрейма") . свойство | метод ( [параметры] ) Доступ к свойствам и методам объекта frame из документа фрейма. (IE4+) parent. document .all. идентифика торФрейма. свойство \ метод {[параметры] ) (IE5+/W3C) parent. document. getElementByld ( "идентификаторФрейма") . свойство | метод( [параметры] ) Описание объекта Как отмечалось во вступлении к данной главе, элемент frame отличается от объекта фрейма, который представлен как объект window в иерархии документа. Элемент frame доступен сценариям только там, где все элементы HTML включены в объектную модель, т.е. в браузерах DB4+ и NN6+, Mozilla и Safari. Так как элемент frame является элементом HTML, он имеет те же свойства, методы и обработчики событий, что и другие элементы HTML, о которых рассказано в главе 15. Элемент frame используется для установки или изменения значений атрибутов в дескрипторе <f rame>. Для упрощения этой задачи следует присвоить уникальный идентификатор атрибуту id этого дескриптора. Если сценарии обращаются к фрейму в рамках стандарта исходной объектной модели (по ссылке parent. f rameName), дескриптору требуется атрибут name. Несмотря на то, что допускается использовать один и тот же идентификатор в атрибутах name и id, желательно присваивать разные слова, чтобы избежать конфликтов в браузерах, поддерживающих оба способа. Для изменения размеров фрейма следует обратиться к элементу frameset, в котором определены атрибуты cols и rows. Эти свойства можно изменить "на ходу** только в браузерах Ш4+ и W3C. Глава 16. Объекты window и frame 491
Свойства allowTransparency Значение: булево Чтение/Запись Совместимость: Winffi6+, MacIE-, NN-, Moz-, Safari- Это свойство указывает на прозрачность фона фрейма. Как правило оно характеризует элемент if rame, поскольку обычные фреймы не требуют использования прозрачных фонов. borderColor Значение: три шестнадцатеричных значения или строковое Чтение/Запись имя цвета Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Если фрейм имеет границу (которая определяется атрибутом f rameborder элемента frame или атрибутом border элемента frameset), она может окрашиваться в цвет, отличный от цвета других фреймов. Исходный цвет (если он отличается от цвета набора фреймов), как правило, устанавливается в атрибуте bordercolor дескриптора <f rame>. В сценарии при необходимости можно изменить эту установку. Изменение цвета границы одного фрейма иногда оказывается рискованным делом (это зависит от используемых цветовых комбинаций). На практике разные браузеры следуют различным правилам в тех ситуациях, когда возникают конфликты или требуется определить, насколько граница одного фрейма "уходит" в пространство страницы. Более того, в WinIE5 при изменении цвета границы одного фрейма возникает странный эффект. Изменения цвета границы отдельного фрейма не всегда отображается на экране. Поэтому комбинации цветов следует проверять во всех возможных браузерах на разных платформах. Пример Вы можете столкнуться с проблемой изменения цвета границы отдельного фрейма, несмотря на это, использование синтаксиса W3C DOM и свойства borderColor является оправданным. document.getElementByld("contentsFrame").borderColor = "red"; В IE также можно использовать следующее выражение. document.all["contentsFrame"].borderColor = "red"; Эти примеры предполагают, что имя фрейма подставляется в функции сценария в текстовом виде. Если сценарий выполняется только в одном фрейме набора, то в выражение необходимо добавить ссылку parent. См. также: свойства frame. f rameBorder, frameset. f rameBorder. contentDocument Значение: ссылка на объект document Только для чтенш Совместимость: WinlE-, MacIE-, NN6+, Moz-, Safari- Свойство contentDocument элемента frame представляет собой не более, чем ссылку на документ, содержащийся во фрейме. Это свойство компенсирует разницу между элементом frame и объектом frame. Оба этих объекта содержат один и тот же объект document, но в ссылках сценария, чаще всего объект frame используется для доступа к документу внутри фрейма, а элемент frame — к свойствам, содержащимся в атрибутах этого дескриптора. Если сценарий имеет ссылку на элемент frame, свойством contentDocument можно воспользоваться как ссылкой на документ, а значит, и на любое содержимое фрейма. 492 Часть III. Объекты документ»
Пример В многофреймовом документе для обращения к отдельному фрейму с целью получения его свойств весьма удобно использовать идентификатор элемента frame. Но начинать всегда нужно со ссылки на объект document. var doc = document.getElementByld("Frame3").contentDocument; Далее в сценарии объявленную ранее переменную можно использовать самым произвольным образом. var val = doc.mainForm.entry.value; См. также: объект document. contentWindow Значение: объект document Только для чтения Совместимость: WinIE5.5+, МасГЕ-, NN7+, Mozl+, Safari- Это свойство элемента frame представляет собой ссылку на окно фрейма. С помощью этой ссылки удобно обращаться к документу в окне фрейма. Пример Вы можете создать ссылку на объект window фрейма, воспользовавшись следующим выражением. var win = document.getElementByld("Frame3").contentWindow; См. также: объект window. frameBorder Значение: yes | no 111 0 как строковые значения Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari- Свойство frameBorder обеспечивает доступ к атрибуту f rameborder элемента frame сценария. Браузеры IE4+ не всегда реагируют корректно на изменение этого свойства после загрузки страницы. Значения свойства frameBorder являются строками, замещающими значения булевого типа. Значение yes или 1 означает (предположительно) отображение границы, а по или 0 — ее отсутствие. Пример По умолчанию свойство frameBorder имеет значение yes. Вы можете создать в сценарии функцию отображения и скрытия границы фрейма (которая в DE может и не выполняться). \¥ЗС-совместимая версия этой функции приведена ниже. function toggleFrameScroll(framelD) { var theFrame = document.getElementByld(framelD); if (theFrame.frameBorder == "yes") { theFrame.frameBorder = "no"; } else { theFrame.frameBorder = "yes"; } } См. также: свойство frameset. frameBorder. Глава 16. Объекты window и frame 493
height width Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Браузеры ГЕ4+ позволяют узнать высоту и ширину элемента frame. Эти значения не всегда совпадают с document.body.clientHeight и document.body.clientWidth, поскольку фреймы часто содержат собственные элементы управления, например полосы прокрутки. Эти значения предназначены только для чтения. Изменение размеров фрейма можно произвести с помощью свойств rows и cols объекта элемента frameset. Читать целочисленные значения высоты и ширины фрейма значительно удобнее, чем анализировать строковые свойства rows и cols. Пример Следующий фрагмент кода предполагает, что основной документ состоит из двух вертикальных фреймов. Приведенные ниже выражения содержатся в сценарии основного документа. С их помощью ширина левого фрейма извлекается и увеличивается на 10%. Здесь используется >¥ЗС-синтаксис, хотя его можно легко адаптировать под поддерживаемый в Г£ синтаксис. var frameWidth = document.getElementById("leftFrame").width; document.getElementById("mainFrameset").cols = (Math, round (frameWidth * 1.1)) + « ,*■'; Обратите внимание, что исходная ширина фрейма увеличивается на 10%, а полученное значение конкатенируется с текстовой частью свойства cols набора фреймов. Звездочка после запятой указывает на необходимость автоматического определения ширины левого фрейма. См. также: объект frameset. longDesc Значение: строка URL Чтение/Запись Совместимость: Winffi6+, МасШ5+, NN6+, Mozl+-, Safari 1+ Свойство longDesc является эквивалентом (для сценария) атрибута longdesc дескриптора <f rame>. Этот атрибут стандарта HTML 4.0 предназначен для передачи браузерам URL документа, содержащего длинное описание элемента. Будущие версии браузеров, возможно, будут использовать это свойство при выведении информации о фрейме для пользователей с плохим зрением. marginHeight marginWidth Значение: целочисленное Чтение/Запись Совместимость: WinIE6+, MacIE5+, NN6+, Mozl+, Safari 1+ Браузеры автоматически вставляют содержимое во фрейм, добавляя поля вблизи его границ. Значения полей представлены свойствами marginHeight (верхняя и нижняя граница) и marginWidth (левая и правая граница). Эти свойства предназначены не только для чтения, однако их изменение после загрузки набора фреймов не влияет на отображение документа во фрейме. Если требуется изменить поля документа, следует воспользоваться свойствами стиля document. body .style. 494 Часть ///. Объекты документа
Несмотря на то, что по умолчанию эти значения являются пустыми (т.е. атрибуты marginheight и marginwidth дескриптора <f rame> не установлены), поля встроены в саму страницу. Их точное значение в пикселях зависит от операционной системы. См. также: объект style (глава 26). name Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Это свойство идентифицирует фрейм в наборе фреймов основного документа. Вы можете его свободно использовать в ссылках на фрейм (например, top. frames [ "my Frame" ]). noResize Значение: булевого типа Чтение/Запись Совместимость: Winffi6+, MacIE5+, NN6+, Mozl+, Safari 1+ В большинстве случаев Web-дизайнеры фиксируют размеры фреймов, не позволяя пользователям изменять их (в результате перетаскивания границы). Свойство noResize позволяет получить и откорректировать поведение фрейма после того, как страница загрузилась. Например, во врем? взаимодействия с пользователем ему можно разрешить вручную изменить размер фрейма (в определенном режиме) или же предоставить однократную возможность этой операции. Когда запускается обработчик события onresize, сценарий устанавливает свойство noresize элемента frame в значение false. Если отключить возможность изменения размеров, все границы фрейма станут неподвижными, независимо от значения свойства noresize соседних фреймов. Отключение возможности изменения размеров фрейма пользователем не оказывает никакого влияния на способность сценариев выполнять эту операцию с помощью свойств cols и rows элемента frameset. Пример Следующее выражение отключает возможность изменения размера фрейма. parent.document.getElementByldC'myFramel").noResize = true; Поскольку имя свойства уже указывает на отрицание, то установка его в значение true предполагает отключение возможности изменения размера фрейма. Внимательно следите за этим в своих сценариях. См. также: свойства frameset .cols, frameset. rows. scrolling Значение: yes | no 111 0 как строковые значения Чтение/Запись Совместимость: Winffi6+, Macffi5+, NN6+, Mozl+, Safari 1+ Свойство scrolling позволяет сценариям включать или отключать полосы прокрутки внутри одного фрейма или целого набора. По умолчанию они отображаются, если только их не отменяет атрибут scroll дескриптора <f rame>. Свойство scrolling содержит строку, заменяющую значения булевого типа. Значение yes или 1 означает, что полосы прокрутки отображаются (при условии, что часть содержимого находится за пределами видимой области), а по или 0 скрывает их. Браузеры Ш4+ также поддерживают (и устанавливают по умолчанию) автоматическое (auto) значение этого свойства. Глава 16. Объекты window и frame 495
/ Это свойство в WinlE5.5+ поддерживается только частично. Изменение значения /на замету свойства никак не отражается на фрейме. NN6 имеет эту и другие проблемы ' а^00^' (например, свойство не возвращает никакого значения, если атрибут scrolling не указан в дескрипторе элемента frame явно). Пример Листинг 16.45 демонстрирует пример создания восьми фреймов. Содержимое фреймов создается сценарием (функция f illFrame ()). Обработчики onclick каждого фрейма вызывают функцию toggle Frames его 11 (). В данном листинге приведено оба способа обращения к фреймам (версия для Ш закомментирована). В функции toggleFrameScroll () с помощью оператора if выполняется проверка равенства свойства значению, отличному от по. Обратите внимание, что полосы прокрутки в Ш5.5, NN6, Moz и Safari из окна не исчезают. <html> <head> <title>frame.scrolling Property</title> <script type="text/javascript"> function toggleFrameScroll(framelD) { // IE5+/W3C var theFrame = document.getElementById(framelD); // IE4+ // var theFrame = document.all[framelD]; if (theFrame.scrolling 1= "no") { theFrame.scrolling = "no"; } else { theFrame.scrolling = "yes"; } } // генерирование содержимого для каждого фрейма function fillFrame(framelD) { var page = "<htmlxbody onclick= 'parent.toggleFrameScroll(\"" + framelD + "\")'> <span style='font-size:24pt'>"; page += "<p>This frame has the ID of:<\/p><p>" + framelD + ".<\/p>"; page += "<\/spanx\/bodyx\/html>"; return page; } </script> </head> <frameset id="outerFrameset" cols="50%/50%"> <frameset id="innerFramesetl" rows="25%,25%,25%,25%"> <frame id=nmyFramel" src="javascript:parent.fillFrame('myFramel')" /> <frame id="myFrame2" src="javascript:parent.fillFrame('myFrame2')" /> <frame id="myFrame3" src="javascript:parent.fillFrame('myFrame3')" /> <frame id="myFrame4" src="javascript:parent.fillFrame('myFrame4')" /> 496 Часть III. Объекты документа
</frameset> <frameset id="innerFrameset2" rows=M25%/25%,25%,25%"> <frame id="myFrame5" src="javascript:parent.fillFrame('myFrameS')" /> <frame id="myFrame6" src="javascript:parent.fillFrame('myFrame6')" /> <frame id="myFrame7" src=" javascript .-parent. f illFrame ( 'myFrame7 ' ) " /> < f rame i d="myFrame 8 " src="javascript:parent.fillFrame('myFrame8')" /> </frameset> </frameset> </html> src Значение: строка URL Чтение/Запись Совместимость: Winffi6+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Свойство src элемента frame представляет собой дополнительный способ перехода к другой странице в пределах фрейма (кроме присвоения нового URL свойству location. href объекта frame). Для совместимости с предыдущими версиями браузеров рекомендуется продолжать использовать свойство location.href. Помните, что свойство src принадлежит элементу frame, а не объекту window, который оно представляет. Поэтому ссылаться на свойство src следует с помощью идентификатора элемента или иерархической структуры узлов. Пример Рекомендуется использовать в свойстве src полные URL-адреса. parent.document.getElementByld("mainFrame").src = "http://www.dannyg.com"; Относительные URL-адреса и выражения javascript :псевдо_URL также находят широкое применение в этом свойстве. См. также: свойство location. href. Элемент frameset Свойства, методы и обработчики событий этого Элемента HTML описаны в главе 15. Свойства Методы Обработчики событий border borderColor cols frameBorder frameSpacing rows Глава 16. Объекты window и frame 497
Синтаксис Доступ к свойствам и методам элемента frameset из элемента frameset. (IE4+) document. all. идентификаторНабораФреймов. свойство \ метод([па- раметры] ) (IE5+/W3C) document. get Element By Id ("идентификаторНабораФреймов") . свойст- во\ метод ( [параметры] ) Доступ к свойствам и методам элемента frameset из документа внутри фрейма. (IE4+) parent. document .all. идеитифика торНа бора Фреймов. ев ойство \ метод ( [параметры] ) (IE5+/W3C) parent. document. getElementByld ("идентификаторНабораФреймов") . свойство]метод( [параметры] ) Описание объекта Элемент frameset представляет собой эквивалент дескриптора <frameset> для сценариев. Он отличается от родительского объекта (окна) исходной объектной модели. Объект frameset имеет свойства и методы элемента HTML; в отличие от него объект window, на который с помощью ключевых слов parent или top ссылаются документы внутри фрейма, содержит документ со всем его содержимым. Во вложенных наборах фреймов существует родительско-дочерняя взаимосвязь между узлами. Например, рассмотрим следующую вложенную структуру фреймов. <frameset id="outerFrameset" cols="30%, 70%"> <frame id="frameIм> <frameset id="innerFrameset" rows="50%,50%"> <frame id="frame2"> <frame id=,,frame3"> </Frameset> </frameset> Сценарии, обращающиеся к фреймам в этой структуре, используют ссылки в менее расширенной иерархической структуре, чем предоставляет HTML. Сценарий из любого фрейма ссылается на окно с набором фреймов с помощью указателя parent, а на другой фрейм — parent. f rameName. Другими словами, объекты window из фреймов, определенных в документе, являются сестринскими узлами с одним родителем. Дело обстоит иначе, если на эту структуру взглянуть с точки зрения терминологии узлов W3C. Взаимоотношения узлов основываются на принципе вложенности элементов HTML, независимо от того, какие окна создает браузер. Поэтому фрейм frame2 имеет только один сестринский узел — f гатеЗ. Оба они имеют одного родителя — innerFrameset. В свою очередь, innerFrameset и f ramel являются дочерними по отношению к outerFrameset. Если сценарий находится во фрейме f rame2, то для изменения свойства cols набора outerFrameset необходимо пройти по двум поколениям узлов. frame2Ref.parentNode.parentNode.cols = "40%,60%"; На практике применение этого объекта зачастую выглядит еще запутаннее: сценарий, принадлежащий одному из фреймов, должен использовать терминологию объекта окна для перехода от текущего объекта window к набору фреймов. Другими словами, нет прямого способа перейти от документа к элементу frame, в котором он находится. Сценарий документа обращается к иерархии узлов набора фреймов с помощью ссылки parent. document. Последняя является ссылкой на объект document, содержащий всю структуру фреймов. 498 Часть ///. Объекты документа
К счастью, в W3C DOM существует метод getElementByldO, предназначенный для получения ссылки на любой узел, вложенный в документе. Таким образом, документ внутри одного из фреймов получает доступ к элементу frame так же, как к любому другому своему объекту. parent.document.getElementByld("frame2") В данном случае нет необходимости ссылаться на элемент frameset. Например, чтобы изменить ширину столбца в сценарии, находящемся в одном из фреймов, используется выражение. parent.document.getElementByld("outerFrame").cols = "40%,60%"; Для доступа к внутреннему набору фреймов применим этот же синтаксис. Свойства border Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari 1+ Свойство border элемента frameset позволяет получить толщину (в пикселях) границ фреймов в наборе. Если атрибут border дескриптора, задающего набор фреймов, не установлен, то это свойство является пустым (оно не отражает толщину границ, использующуюся по умолчанию). Пример Несмотря на то, что это свойство имеет атрибут чтение/запись, редактирование его значения не вызывает изменения толщины отображаемой в браузере границы. Если вам необходимо задать толщину границы, то используйте ссылку, подобную приведенной ниже. var thickness = parent.document.all.outerFrameset.border; См. также: свойство frameset. frameBorder. borderColor Значение: три шесГнадцатеричных значения или имя цвета Чтение/Запись Совместимость: WinD54+, MacIE4+, NN-, Moz-, Safari- Свойство borderColor позволяет получить значение цвета, которое устанавливается в атрибуте bordercolor дескриптора, определяющего набор фреймов. Данное свойство предназначено для чтения и записи, однако изменение цвета в сценарии не влияет на вид фрейма. Значения, установленные как имена цветов в строковом виде, при чтении воспринимаются как корректные шестнадцатеричные числа. Пример Чтобы получить текущий цвет набора фреймов, используйте ссылку следующего формата. var borderColor = parent.document.all.outerFrameset.borderColor; См. также: свойства frame .borderColor, frameset. f rameBorder. cols rows Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Глава 16. Объекты window и frame 499
Свойства cols и rows элемента frameset позволяют получить и изменить размеры фреймов после их загрузки. Оба этих свойства определены в W3C DOM. Значения обоих свойств являются строками, которые могут включать символы процента или звездочки. Поэтому при попытке увеличить или уменьшить размер столбца или строки фрейма вначале следует обработать строку и извлечь из нее значения, используемые в математических вычислениях (в браузерах IE4+ воспользуйтесь свойствами height и width элемента frame, содержащими текущие размеры фрейма в пикселях). Ш4+ позволяет полностью изменить набор фреймов путем корректировки этих свойств (добавляются и удаляются строки или столбцы в наборе фреймов). Поскольку модификация структуры набора влияет на сценарии, изменяя массив фреймов, привязанный к родительскому окну, или выгружая документы, содержащие нужные данные, тестируйте сценарии в обоих состояниях набора фреймов. Если требуется удалить фрейм, просто укажите нулевой размер строки или столбца в наборе. Конечно же, нулевой размер сохраняет на экране однопиксельный фрейм, однако он невидим, если имеет тот же цвет фона, а границы скрыты. Второй аргумент в пользу использования такой методики заключается в том, что восстановить фрейм можно без изменения структуры документа. Если в одном документе определены вложенные наборы фреймов, убедитесь, что ссылки указывают на требуемый объект элемента frameset. В одном объекте могут быть определены столбцы, а в другом (вложенном) — строки. Каждому элементу frameset необходимо присвоить уникальный идентификатор. Пример В листингах 16.46-16.48 приведен код документа, который размещается в наборе из нескольких фреймов. Этот документ содержит в отдельном фрейме список разделов основной статьи. В листинге 16.46 приведен код настройки трехфреймового документа. Левый фрейм содержит оглавление, представленное листингом 16.47. Правая часть страницы разделена на два горизонтальных фрейма. В верхнем фрейме содержится простой элемент управления (листинг 16.48), скрывающий и отображающий оглавление (левый фрейм). Как только пользователь щелкнет на подчеркнутом тексте этого элемента управления (вставлен в элемент span), его обработчик onclick вызовет функцию toggleTOC (). Приведенный в листингах синтаксис полностью А^ЗС-совместимый. Чтобы исправить его для выполнения в Ш, замените ссылку document .getElementById ("outerFrameset") на document .all .outer Frameset, a elem. first Chi Id. node Value — на elem. innerText. Листинг 16.46. Набор фрейм» и сценарий отображения/скрьпгия фрейма " <html> <head> <title>Hide/Show Frame Example</title> <script type="text/javascript"> var origCols; function toggleTOC(elem, frm) { if (origCols) { showTOC(elem) ; } else { hideTOC(elem/ frm); } } function hideTOC(elem/ frm) { var frameset = document.getElementByld("outerFrameset"); origCols = frameset.cols; 500 Часть III. Объекты документа
frameset.cols = "0,*"; } function showTOC(elem) { if (origCols) { document.getElementByldC'outerFrameset").cols = origCols; origCols = null; } } </script> </head> <frameset id="outerFrameset" frameborder="no" cols="150/*"> <frame id="T0C" name="TOCFrame" src="lstl6-47.htm" /> <frameset id="innerFramesetl" rows="80/*"> <frame id="controls" name="controlsFrame" src="lstl6-48.htm" /> <frame id="content" name="contentFrame" src="bofright.htm" /> </frameset> </frameset> </html> Перед скрытием фрейма свойство cols сохраняется в глобальной переменной. Впоследствии она будет использоваться в функции showTOC () для восстановления "исходной структуры фреймов. ^ ^ ^$Нф'ЬЛЪ' chtml> <head> <title>Table of Contents</title> </head> <body bgcolor="#EEEEEE"> <h3> Table of Contents </h3> <hr /> <ul style="font-size:10pt"> <lixa href="bof right .htm#articlel" target="contentFrame">Article I</ax/li> <lixa href ="bofright.htm#article2" target="contentFrame">Article II</ax/li> <lixa href ="bofright.htm#article3" target="contentFrame">Article III</ax/li> <lixa href ="bof right .htm#article4" target =" content Frame ">Article IV</ax/li> <lixa href= "bof right .htm#article5" target="contentFrame">Article V< /ax /1 i > <lixa href="bofright.htm#article6" target="contentFrame">Article VI</ax/li> <lixa href = "bof right.htm#article7" target="contentFrame">Article VII</ax/li> <lixa href="bofright.htm#article8" targets"contentFrame">Article VIII</ax/li> <lixa href="bofright.htm#article9" target= "contentFrame">Article IX</ax/li> <lixa href="bofright.htm#articlelO" target ="contentFrame">Article X</ax/li> Глава 16. Объекты window и frame 501
</ul> </body> </html> <html> <head> <title>Control Panel</title> </head> <body> <pxspan id="tocToggle" style=" text-decoration: under line; cursor:pointer" onclick="parent.toggleTOCO">&lt; &lt;Hide/Show&gt;&gt;</span> Table of Contents</p> </body> </html> См. также: объект frame. frameBorder Значение: yes | no 111 0 как строковые значения Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство frameBorder обеспечивает сценариям доступ к атрибуту frameborder элемента frameset. Браузеры IE4+ некорректно реагируют на изменение этого свойства после загрузки страницы. Свойство frameBorder содержит строку, заменяющую значения булевого типа. Значение yes или 1 означает, что границы отображается, а по или 0 скрывает их. Пример По умолчанию свойство frameBorder принимает значение yes. Вы можете создать специальную функцию, которая его изменяет (хотя в Ш она выполняется не всегда). function toggleFrameScroll(framesetID) { var theFrameset = document.all(framesetID); if (theFrameset.frameBorder == "yes") { theFrameset.frameBorder = "no"; } else { theFrameset.frameBorder = "yes"; См. также: свойство frame. frameBorder. frameSpacing Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство frame Spacing элемента frameset позволяет получить расстояние (в пикселях) между фреймами. Если атрибут f ramespacing дескриптора, задающего набор фреймов, не установлен, то это свойство является пустым (оно не отражает толщину границ, использующихся по умолчанию, обычно равную 2 пикселям). 502 Часть III. Объекты документа
Пример Это свойство имеет атрибут чтение/запись, однако его настройка в ГЕ4+ не изменяет расстояния между фреймами в окне браузера. Если вы хотите определить расстояние, заданное атрибутом дескриптора, то используйте ссылку следующего вида. var spacing = parent.document.all.outerFrameset.frameSpacing; См. также: свойство frameset. border. Элемент iframe Свойства, методы и обработчики событий этого элемента HTML описаны в главе 15. Свойства Методы Обработчики событии align allowTransparency contentDocument contentWindow height hspace longDesc marginHeight marginWidth scrolling src vspace width Синтаксис Доступ к свойствам и методам элемента iframe из документа внутри него. (IE4+) document .all. идентификатор. свойство \ метод( [параметры] ) (IE4+/W3C) window. frames ["имяФрейма" ] . свойство \ метод ( [параметры] ) (IE5+/W3C) document. getElementByld (" идентификатор") . свойство \ метод {[параметры] ) Доступ к свойствам и методам элемента iframe из документа внутри элемента iframe. (IE4+) parent. document. all. идентификатор. свойство \ метод( [параметры] ) (IE5+/W3C) parent. document. getElementByld ("идентификатор") . свойство | метод ( [параметры] ) Глава 16. Объекты window и frame 503
Описание объекта Элемент iframe (Ш4+ и NN6) позволяет загрузить HTML-содержимое из источника в тело другого документа. В некотором смысле элемент layer в NN4 является предшественником концепции if rame, но, в отличие от layer, он не является наследственно позиционируемым. Его можно позиционировать как и любой другой элемент HTML, присвоив соответствующие атрибуты в таблицах стилей, заданных для элемента iframe. Если его положение не указано явно, элемент if rame размещается в теле документа в месте, заданном исходным кодом страницы. В отличие от фрейма или набора фреймов, if rame можно разместить в любом месте документа. Если размеры элемента if rame изменяются с помощью сценария, прилежащие к нему элементы смещаются соответствующим образом. Что действительно отличает if rame от других элементов HTML, так это возможность загружать и отображать содержимое внешних HTML-файлов, причем, различные страницы могут загружаться, не влияя на содержимое основного документа. Страницы, загружаемые в if rame, могут содержать сценарии и любые другие средства любого HTML-документа (включая, например, XML-данные). Элемент if rame имеет большой набор атрибутов, позволяющих автору страницы управлять видом, размером (height и width) и, в некоторой степени, поведением фрейма. Многие атрибуты доступны сценарию как свойства элемента if rame. Важно помнить, что во многом элемент if rame ведет себя как обычный объект frame, особенно, если речь идет о взаимосвязях с окнами. Если включить элемент if rame в документ главного окна, он будет представлен в объектной модели как фрейм. window.frames[i] window.frames[имяФрейма] Внутри объекта if rame находится документ со всем его содержимым. Все ссылки на объекты документа внутри if rame должны использовать "портал" if rame. И наоборот, сценарии документа внутри элемента if rame могут взаимодействовать с главным окном с помощью ключевого слова parent. Конечно же, заменить содержимое главного окна другим HTML-документом (с помощью, например, location.href), не уничтожая if rame, нельзя. Свойства align Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Свойство align управляет выравниванием элемента if rame по отношению к окружающему его содержимому страницы. Два возможных значения (left и right) управляют положением if rame по отношению к левому и правому краю (соответственно) элемента, содержащего - if rame (обычно BODY). Содержимое документа обтекает элемент if rame так же, как это происходит для изображения. Все возможные значения и их описание приведены в табл. 16.5. Когда сценарий изменяет значение свойства align, страница отображается повторно. Пример По умолчанию это свойство принимает значение baseline. Чтобы изменить выравнивание, например, по правому краю, воспользуйтесь в сценарии следующим выражением. document.getElementById("iframel").align = "right"; См. также: свойства if rame .hspace, if rame. vspace. 504 Часть III. Объекты документа
16.5. Значения свойства align Зн ачение Описание absbottom Выравнивает нижнюю границу if rame no подстрочной линии символов окружающего текста absmiddie Выравнивает середину if rame по центральной линии между top окружающего текста И absbottom baseline Выравнивает нижнюю границу if rame по базовой линии окружающего текста bottom Совпадает со свойством baseline в IE left Выравнивает if rame по левому краю элемента-контейнера middle Выравнивает воображаемую центральную линию окружающего текста с воображаемой линией элемента if rame right Выравнивает if rame no правому краю элемента-контейнера texttop Выравнивает верхнюю границу элемента if rame по надстрочной линии символов окружающего текста top Выравнивает верхнюю границу элемента if rame по верхней границе окружающего текста allowTransparency Значение: ссылка на объект document Только для чтения Совместимость: Winffi6+, MacIE-, NN-, Moz-, Safari- Это свойство определяет прозрачность фона фрейма. Чтобы сделать фоновое изображение или цвет прозрачным, установите свойство allowTransparency в значение true. contentDocument Значение: ссылка на объект document Только для чтения Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Свойство contentDocument элемента if rame является простой ссылкой на документ, который содержится во фрейме. Если сценарий имеет ссылку на элемент if rame, свойством contentDocument можно воспользоваться как указателем на документ, а значит, и на любое содержимое фрейма. Пример В сценариях документов часто используются идентификаторы элементов if rame. С их помощью можно не только изменить свойства фрейма, но и обратиться к объекту document, var doc = document.getElementById("Frame3").contentDocument; Далее вы можете обратиться к форме документа, var val = doc.mainForm.entry.value; См. также: объект document. contentWindow Значение: объект document Только для чтения Совместимость: WinIE5.5, МасШ-, NN7+, Mozl+, Safari- Глава 16. Объекты window и frame 505
Свойство contentWindow элемента if rame служит ссылкой на объект window, сгенерированный фреймом. Вы можете использовать ее для получения доступа к объекту document и любых его объектам. См. также свойство content Document; объект window. height width Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Эти свойства задают высоту и ширину объекта if rame, а потому используются для установки размеров фрейма. Оба свойства задаются в пикселях. hspace vspace Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Эти свойства, поддерживаемые в ffi, позволяют устанавливать отступы для элемента if rame. Свойства hspace и vspace (и соответствующие им атрибуты HTML) были заменены параметрами CSS. Они не поддерживаются ни в одном из стандартов W3C (включая HTML 4.0). Значения этих свойств являются целочисленными и задают отступ в пикселях между элементом и окружающим его содержимым документа. Значение hspace задает отступ слева и справа, a vspace — сверху и снизу. Изменение этих свойств в сценарии не оказывает никакого влияния на вид страницы в Winffi5+. См. также: свойство style .padding. longDesc Значение: строка URL Чтение/Запись Совместимость: WinIE6+, MacIE5+, NN6+, Mozl+, Safaril+ Свойство longDesc является эквивалентом (для сценария) атрибута longdesc дескриптора <if rame>. Этот атрибут стандарта HTML 4.0 предназначен для передачи браузерам URL документа, содержащего длинное описание элемента. Будущие версии браузеров, возможно, будут использовать это свойство при выведении информации о фрейме для пользователей с плохим зрением. marginHeight marginWidth Значение: целочисленное Чтение/Запись Совместимость: WinEE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Браузеры автоматически вставляют содержимое во фрейм, добавляя поля вблизи его границ. Значения полей представлены свойствами marginHeight (верхняя и нижняя границы) и marginWidth (левая и правая границы). Эти свойства предназначены не только для чтения, однако их изменение после загрузки набора фреймов не влияет на вид документа во фрейме. Если требуется изменить поля документа, воспользуйтесь свойствами стиля document.body.style. 506 Часть III. Объекты документ
Помните: хотя по умолчанию эти значения являются пустыми (при задании атрибутов marginheight и marginwidth дескриптора <iframe>), поля отдельно задаются для самой страницы. Их точное значение в пикселях зависит от операционной системы. См. также: объект style (глава 26). name Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Представляет идентификатор фрейма, используемый при обращении к последнему. Обычно имя фрейма задается с помощью атрибута name. scrolling Значение: yes | no 111 0 как строковые значения Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Свойство scrolling позволяет сценариям включать или отключать полосы прокрутки внутри одного фрейма или целого набора. По умолчанию они отображаются, если только их не отменяет атрибут scroll дескриптора <if rame>. Свойство scrolling содержит строку, заменяющую значения булевого типа. Значение yes или 1 означает, что полосы прокрутки отображаются (при условии, что часть содержимого находится за пределами видимой области), а по или 0 скрывает их. Браузеры Ш4+ также поддерживают (и устанавливают по умолчанию) автоматическое значение. Пример Следующая функция togglelFrameScroll О принимает в качестве аргумента идентификатор элемента iframe (представленный строкой) и изменяет свойство scrolling. Оператор if проверяет, установлено ли свойство в значение, отличное от по. function toggleFrameScroll(frameID) { // IE5 & NN6 var theFrame = document.getElementByld(framelD); // IE4+ // var theFrame = document.all[frameID] if (theFrame.scrolling 1= "no") { theFrame.scrolling = "no"; } else { theFrame.scrolling = "yes"; } } См. также: свойство frame. scrolling. src Значение: строка URL Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safaril+ Свойство src элемента if rame представляет собой дополнительный способ перехода к другой странице в пределах фрейма (кроме присвоения нового URL свойству location.href объекта фрейма). Помните, что свойство src принадлежит элементу if rame, а не объекту window, который оно представляет. Поэтому ссылаться на свойство src следует с помощью идентификатора элемента и/или иерархии узлов. Глава 16. Объекты window и frame 507
Пример Рекомендуется использовать в качестве значения этого свойства полные URL-адреса. document.getElementById("mylframe"). src = "http://www.dannyg.com"; Относительные адреса и операторы javascript:псевдо__ЦЯЬ также допускается применять, но иногда они вызывают сбои. См. также: свойство location.href. Объект popup Свойства Методы Обработчики событий document hide() isOpen show() Синтаксис Создание объекта popup. var popupObj = window.createPopup() Доступ к свойствам и методам объекта popup из документа, создавшего всплывающее окно. popupObj . свойство\метод( [параметры] ) Совместимость: WinIE5.5+, Macffi-, NN-, Moz-, Safari- Описание объекта Объект popup представляет собой всплывающее окно без элементов управления. Оно располагается поверх документа, который его генерирует. Это окно отображается поверх диалоговых окон. В отличие от последних, генерируемых в IE методами showModalDialogO и showModelessDialog (), сценарии должны не просто создавать окно, а также заполнять его содержимым и указывать его положение на экране. Поскольку всплывающее окно не имеет элементов управления (заголовка, элементов изменения размера и т.д.), оно должно иметь рамку и/или другой цвет фона, чтобы выделяться на странице. Ниже представлена типичная последовательность операторов, применяемая для создания, заполнения содержимым и отображения объекта popup. var popup = window.createPopup(); var popupBody = popup.document.body; popupBody.style.border = "solid 2px black"; popupBody.style.padding = "5px"; popupBody.innerHTML = "<p>Here is some text in a popup window</p>"; popup.show(200,100, 200, 50, document.body); Всплывающее окно, создаваемое в Ш, является окном лишь с точки зрения документа. Таким образом, хотя набор свойств и методов объекта popup невелик, свойство parent Window документа внутри него указывает на исходное свойство window. Помните, что всплывающее окно не отображается отдельно среди окон на панели задач Windows. Если пользователь щелкает мышью за пределами всплывающего окна или активизирует другое приложение, окно исчезает; для его восстановления необходимо заново вызвать метод show () (с указанием параметров размера и положения). При заполнении окна содержимым следует удостовериться, что оно помещается в пределах окна. Если это не так, полосы прокрутки все равно не отображаются. 508 Часть III. Объекты документа
Свойства document Значение: ссылка на объект document Только для чтения Совместимость: WinIE5.5+, МасШ-, NN-, Moz-, Safari- Свойство document используется как своеобразный шлюз для содержимого всплывающего окна. Это единственная точка доступа сценария, создавшего всплывающее окно, к документу в нем. Например, для создания границы всплывающего окна (поскольку само по себе оно не имеет элементов управления), сценарий присваивает значения свойству style документа. myPopup.document.body.style.border = "solid 3px gray"; Помните, что объект document всплывающего окна поддерживает не все возможные свойства. Например, свойству document. url во всплывающем окне нельзя присвоить новый URL. Пример Приложение The Evaluator (глава 13) используется для изучения объекта popup и его свойств. Введите в верхнее текстовое поле следующие выражения. Первый оператор создает вспльшающее окно; ссылка на него задается глобальной переменной а. Следующий оператор представляет собой ссылку на тело документа всплывающего окна; эта ссылка сохраняется в глобальной переменной Ь. Остальные операторы управляют указанными двумя глобальными переменными. а = window.createPopup() b = а.document.body b.style.border = "solid 2px black" b.style.padding = "5px" b.innerHTML = "<p>Here is some text in a popup window</p>" a.show(200,100, 200, 50, document.body) См. описание метода show (). См. также: объект document. isOpen Значение: булево Только для чтения Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Пока всплывающее окно является отображаемым, свойство isOpen возвращает значение true; в ином случае оно равно false. Поскольку любое действие пользователя в браузере приводит к удалению окна с экрана, это свойство применяется только в тех операторах сценария, которые выполняются после отображения окна. Пример Свойство isOpen также можно легко изучить, воспользовавшись приложением The Evaluator. Введите в верхнее текстовое поле следующие выражения. Указанная последовательность операторов начинается с создания всплывающего окна, ссылка на которое сохраняется в глобальной переменной а. Обратите внимание, что последняя строка состоит из двух операторов; второй оператор выполняет только тогда, когда всплывающее окно все еще открыто. а = window.createPopup(); a.document.body.innerHTML = "<p>Here is a popup window</p>"; a.show(200,100, 200, 50, document.body); alertC'Popup is open:" + a.isOpen); Глава 16. Объекты window и frame 509
Если вы щелкнете в основном окне для скрытия всплывающего окна, то получите результат, который зависит от того, будет ли введен в верхнее поле следующий оператор. alert("Popup is open:" + a.isOpen); См. также: метод popup. show (). Методы hide () show (слева, справа, ширина, высота [, позиционирование]) Возвращаемое значение: отсутствует Совместимость: Winffi5.5+, MacIE-, NN-, Moz-, Safari- Созданный с помощью метода window. createPopup () объект popup необходимо явным образом отобразить на экране — для этого и предназначен метод show (). Если окно не отображается на экране по причине того, что пользователь щелкнул мышью где-либо в браузере, метод show () (со всеми параметрами) необходимо запустить заново. Чтобы скрыть окно, для объекта popup используется метод hide О. Четыре первых аргумента метода show () задают расположение и размер всплывающего окна в пикселях. По умолчанию координатным пространством для left и top служит экран. Поэтому значения left и top, равные нулю, размещают окно в левом верхнем углу экрана. Указав пятый, дополнительный аргумент, можно определить другое координатное пространство. Этот параметр является ссылкой на элемент страницы. Чтобы ограничить координатное пространство окном браузера, необходимо указать объект document. body. Пример В листинге 16.49 приведен пример использования методов hide () и show (). Щелчок на кнопке страницы приводит к вызову функции self Timer (), которая выполняет большинство операций этого примера. Наша цель— создание всплывающего окна, которое "самоуничтожается" спустя пять секунд после открытия. При всем этом во всплывающем окне отображается секундомер. Ссылка на всплывающее окно сохраняется в глобальной переменной popup. После создания объекта popup функция initContent () форматирует содержимое всплывающего окна с помощью свойств style и innerHTML. Содержимое окна генерируется автоматически в процессе его создания. В документ всплывающего окна также включен элемент span, чтобы в дальнейшем еще одна функция могла изменить только фрагмент данных документа. Обратите внимание, что добавление содержимого во всплывающее окно выполняется на этапе инициализации последнего (переменная popup принимает значение), хотя само окно при этом не отображается. Объект popup отображается с помощью функции self Timer О. Установка правильного размера окна требует проведения определенных подготовительных операций; все необходимые настройки задаются в функции initContent (). После отображения всплывающего окна на экране вызывается функция countDown (). Перед выполнением остальных действий эта функция проверяет, инициализировано и отображено окно на экране или нет. Если пользователь щелкнет при обратном отсчете в основном окне, то свойство isOpen примет значение false, и ни один оператор внутри конструкции if выполняться не будет. Функция countDown () извлекает текст элемента span и использует метод parselnt () для извлечения целого числа. 510 Часть ///. Объекты документа
<html> <head> <title>popup Object</title> <script type»"text/javascript"> var popup; function initContent() { if (popup && !popup.isOpen) { var popBody = popup.document.body; popBody.style.border = "solid 3px red"; popBody.style.padding = "1Opx"; popBody.style.fontSize = "24pt"; popBody.style.textAlign = "center"; var bodyText - "<P>This popup will self-destruct in "; bodyText += "<span id='counter'>05<\/span>"; bodyText += " seconds...<\/P>"; popBody.innerHTML « bodyText; } function countDownO { if (popup && popup.isOpen) { var currCount * parselnt(popup.document.all.counter.innerText, 10); if (--currCount ==0) { popup.hide(); popup = null; } else { popup.document.all.counter.innerText = "0" + currCount; setTimeout("countDown() ", 1000); } } function selfTimerO { popup « window.createPopupO ; initContent(); popup.show(200,200,400,100,document.body); setTimeout("countDown()", 1000); } </script> </head> <body> <form> <input type="button" value»"Impossible Mission" onclick="selfTimer()" /> </form> </body> </html> Метод hide () запускается в сценарии при отображенном всплывающем окне. Поскольку окно скрывается автоматически по истечении короткого промежутка времени, то вызывать этот метод при щелчке пользователем в основном окне нет смысла. Для умышленного закрытия всплывающего окна используется метод parentWindow. close (). См, также: свойство popup. isOpen; метод window. createPopup (). Глава 16. Объекты window и frame 511
Объекты history и location l^ll e все объекты в модели документа можно просмот- II И реть в области окна браузера. Каждое окно или фрейм имеет ссылки на дополнительную информацию по теме страницы, отображаемой пользователем в текущий момент. URL страницы, отображенной в окне браузера, называется адресом; браузеры сохраняют эту информацию в объекте location. Во время пребывания пользователя в сети URL-адреса страниц, посещенных им в прошлом, сохраняются браузером в объекте history. Вручную можно просматривать содержимое этого объекта в меню браузера, таким образом переходя на предыдущие страницы. В данной главе описаны объекты history и location, которые не используются на Web-странице явно, однако играют немаловажную роль при написании сценария. Данные объекты могут использоваться не только для простого управления браузерами. С их помощью можно получить URL-адреса страниц, загруженных пользователем в другие окна браузера или посещенных им узлов. Эту задачу легко осуществить при написании даже самого простого сценария. В конечном счете, разработчики снабдили браузеры средствами защиты, ограничивающими доступ к некоторым свойствам данных объектов (это ограничение не относится к NN4+). В последующих версиях браузеров эти свойства стали просто недоступны.
Объект location Свойства Методы Обработчик событий hash host hostname href pathname port protocol search assign() reload () replace () Синтаксис Загрузка нового документа в текущее окно. [window.]location.href="URL" Доступ к свойствам или методам объекта location. [window. 3 location. свойство\метод( [параметры] ) Описание объекта В иерархической структуре объектов документа объект location расположен на один уровень ниже объектов window. Таким образом, он представляет информацию об URL-адресе любого открытого в настоящее время окна или определенного фрейма. В многофреймовых окнах в поле адреса браузера отображены URL родительских окон. Каждому фрейму также соответствует ссылка, хотя она и не всегда отображена в окне браузера. Чтобы получить информацию об URL документа, расположенного в другом фрейме,.в объекте location должна содержаться ссылка на фрейм данного окна. Пусть у вас есть окно, состоящее из двух фреймов. В табл. 17.1 приведены возможные ссылки на объекты location для существующих в сети фреймов. С помощью сценариев нельзя изменить URL, отображенный в поле адреса брау- Назаметку зера. Чтобы обеспечить защиту данных, в этом поле не отображается ничего, ■*" кроме URL-адреса текущей либо загружаемой страницы. /- мл. Ссылки | oto*mЩ Ссылка Описание location (или window, location) parent.location parent.frames[0].location URL фрейма, содержащего документ, из которого запускается сценарий с данной ссылкой URL родительского окна, для представления которого использована структура дескриптора <f rameset> URL первого вложенного фрейма Глава 17. Объекты history и location 513
Окончание табл. 17А Ссылка Описание parent. frames [ 1 ] . location URL второго вложенного фрейма parent. именаДругихФреймов. location URL остальных фреймов того же дескриптора Большинство свойств объекта location используется для работы в сети. Это касается данных о физическом расположении документа в сети, включая хост-сервер, используемые протоколы и другие компоненты URL. При создании полного URL обычной Web-страницы каждой части URL-адреса с помощью объекта window. location назначается индивидуальное значение. http://www.giantco.com:80/pronios/newproducts.html#giantGiznio Свойство protocol hostname port host pathname hash href Значение "http:" "www.giantco.com" "80" "giantco.com:80" "/promos newproduct s.html" "#giantGizmo" "http://www.giantco.com:80.promos newproducts.html#giantGizmo" Если при написании сценария требуется дополнительная информация об URL, удобно использовать объект window, location. Можно также получить основную ссылку, на которой и базируются URL-адреса документов, выбранные пользователем для дальнейшей работы. Данный объект часто используется при разработке узла на одном компьютере и при последующей его отправке на сервер (возможно, через узел Intemet-провайдера), на которое в свою очередь, существует собственная структура папок. При написании сценария необходимо создать основные ссылки на текущий документ, расположенный в той или иной папке. Таким образом можно формировать полные URL для загрузки любых документов. Совсем необязательно вручную изменять основные ссылки в документах при перемещении файлов с одного компьютера на другой или из одной папки в другую. Для того чтобы извлечь часть URL адреса и затем изменить его для соответствующей папки, используют следующее выражение. var baseRef=location.href.substring(0,location.href. lastlndexOf ("/") + H; Безопасность: для обеспечения безопасной работы в Internet и защиты от всевозможных посягательств в браузерах, поддерживающих сценарии, доступ к свойствам объекта location заблокирован из фреймов, которые расположены на сервере и в домене (кроме того, в котором расположен соответствующий сценарий). Однав это не относится к использованию защищенных сценариев в NN4+ и ситуации, код в IE установлены доверительные отношения с узлом. Таким образом, в проекты многих разработчиков помещается специальная функция, обеспечивающая защиту до кументов от Web-посетителей, имеющих "виды" на ваш сценарий. Если вы поп* таетесь предоставить такой доступ к свойствам объекта location, то на экран! появится предупреждающее сообщение, извещающее о "запрещении доступа". Установив значения некоторых свойств location, можно контролировать документы» загружаемые в окно или фрейм. Если необходимо загрузить в окно браузера новую страницу или узел, введите в поле адреса соответствующий URL, предварительно задав его в свойстве 514 Часть 111. Объекты локумет
window, location.href (некоторые, наверное, считают, что в JavaScript существует метод с ключевыми словами Go или Open — как аналог кнопок панели управления браузера). window.location.href="http://www.dannyg.com/"; Наиболее "верный" способ для установки новой ссылки в объекте — использование оператора (=). При установке в объекте location.href URL другого МГМЕ-типа (это могут быть различные мультимедийные форматы) браузер вынужден загрузить эти файлы в допол- шггельных приложениях, указанных в настройках браузера. Первоначально метод location. assign () был предназначен для внутреннего использования браузером, однако на самом деле, программисты также имеют к нему доступ (хотя и не рекомендуется использовать данный метод для "путешествия" по сети). В объектной модели Internet Explorer существует еще один метод для загрузки документа в окно — window. navigate (), однако его нельзя использовать в приложениях, предназначенных для запуска в браузере. Два других метода дополняют в объекте location средства навигации по Web. Один из чметодов представляет собой сценарий, выполнение которого аналогично результату, полученному при щелчке на кнопке Reload (Обновить); другой метод обеспечивает возможность перемещения содержимого текущего документа в соответствии со следующим выбранным URL-адресом. I Свойства hash Возвращаемое значение: строковое Чтение/Запись Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Символ "решетки" (#), или hash-символ, является стандартным символом в ШИ^адресе, с помощью которого в браузере происходит перемещение к указанному в документе анкеру. Любое имя, назначенное анкеру (в дескрипторе <а name=". . .">. . .</а>)с использованием этого значка, становится частью URL. Свойство hash объекта location является именем "анкерной части" текущего URL (которая состоит из символа # и собственно имени анкера). Если пользователь перемещается по документу с помощью анкеров и соответствующих им ссылок, то можно заметить следующее: хотя в ссылке документа анкер и представлен как часть URL (например в поле Location), значение анкера не изменяется, если пользователь просматривает документ, прокручивая его вручную. В URL-адресе анкер изменятся только тогда, когда переход в текущую точку документа осуществлялся с помощью анкерной ссылки либо в соответствии со сценарием, в котором задан новый URL. К другим анкерам, расположенным в том же документе, можно перемещаться с помощью любого URL, заданного свойством window. 1 осаtion.href. В данном случае необходимо изменить только свойство hash, при этом не используя самого символа (как показано в следующем примере) в имени анкера. Такое перемещение даже в пределах документа иногда влечет за собой перезагрузку текущего документа в Ш, чего не происходит в NN3+. Пример В листинге 17.1 продемонстрирован пример использования hash для доступа к анкерной части URL. При загрузке кода этого листинга измените размер окна браузера так, чтобы в нем отображался только один раздел. По щелчку на кнопке сценарий переместит вас к следующему логическому разделу или в верхнюю часть документа. Глава 17. Объекты history и location 515
<html> <head> <title>location.hash Property</title> <script type="text/javascript"> function goNextAnchor(where) { window.location.hash = where; } </script> </head> <body> <hlxa id="start" name= "start">Top</ax/hl> <form> <input type="button" name="next" value="NEXT" onclick="goNextAnchor('seel')" /> </form> <hr /> <hlxa id="secl" name="secln>Section l</ax/hl> <form> <input type="button" name="next" value="NEXT" onelick="goNextAnchor(•sec2•)" /> </form> <hr /> <hlxa id="sec2" name="sec2">Section 2</ax/hl> <form> <input type="button" name="next" value=MNEXT" onelick="goNextAnchor('sec3')" /> </form> <hr /> <hlxa id="sec3" name="sec3">Section 3</ax/hl> <form> <input type="button" name="next" value="BACK TO TOP" onclick="goNextAnchor('start')" /> </form> </body> </html> Имена анкеров подставляются в качестве аргументов обработчиков событий onclick кнопок. Вместо использования в функции значения window, location и добавления символа диеза, а также анкерной части адреса, я изменил свойство hash объекта location текущего окна. Если вы попытаетесь заново считать в сценарии свойство window, location.hash, то не всегда получите корректную информацию, извлекаемую из настроек браузера. Чтобы не допустить возвращения неправдоподобной информации, составьте URL из тех же выражений, что использовались ранее для изменения свойства hash. He стоит полностью полагаться на браузер при получении информации об адресе. См также: свойство location. href. host Возвращаемое значение: строковое Чтение/Запись Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ В свойстве location.host описывается имя хоста и порт URL-адреса. Значение порта в этом свойстве сохраняется только тогда, когда оно явно указано в полном URL. Если в поле 516 Часть III. Объекты документ*
Location браузера отображен URL, не содержащий номера порта, то свойства location. host и location. hostname возвращают одинаковые значения. Для получения части URL, называемой hostname: port, используйте свойство location.host. Такая возможность применяется для формирования URL-адреса определенного документа, к которому в процессе его загрузки происходит обращение из сценария. Пример Используйте листинги 17.2-17.4 для изучения свойства host. Это свойство принимает значение только в случае включения имени порта в URL-адрес. Если в поле адреса браузера введен URL, который не содержит имени порта, то свойство location.host содержит такое же значение, как и location. hostname. Используйте свойство location.host для извлечения из URL-адреса документа, отображенного в окне браузера, части location: port. Эта возможность часто используется при создании URL-адреса документа, доступ к которому необходимо получить в процессе выполнения сценария. В приведенных ниже листингах используется намного больше значений, чем возвращает свойство window, location. Откройте в браузере файл листинга 17.2. Эта страница содержит два фрейма. Слева располагается временный заполнитель (листинг 17.4), а справа — документ (листинг 17.3), позволяющий указать URL-адреса загружаемых страниц и отобразить составляющие свойства location (фрейм для загрузки страницы можно указать отдельно). ^Листинг 17.2» Набор фреймов для приложения изун^ <html> <head> <title>window.location Properties</title> </head> <frameset cols="50%,50%" border="l" bordercolor="black"> <frame name="Framel" src=Mlstl7-04.htmM /> <frame name="Frame2M src="lstl7-03.htm" /> </frameset> </html> <html> <head> <title>Property Picker</title> <script type="text/javascript"> var isNav = (typeof netscape != "undefined") ? true : false; function fillLeftFrame() { newURL = prompt("Enter the URL of a document to show in the left frame:",""); if (newURL != null && newURL != "") { parent.frames[0].location = newURL; function showLocationData(form) { for (var i = 0; i <3; i++) { Глава 17. Объекты history и location 517
if (form.whichFrame[i].checked) { var windName = form.whichFrame [i] .value,- break; } } var theWind = "" + windName + ".location"; if (isNav) { netscape.security.PrivilegeManager. enablePrivilege("UniversalBrowserRead"); } var theObj = eval(theWind); form.windName.value = windName; form.windHash.value = theObj.hash; form.windHost.value = theObj.host; form.windHostname.value = theObj.hostname; form.windHref.value = theObj.href; form.windPath.value = theObj.pathname; form.windPort.value = theObj.port; form.windProtocol.value = theObj.protocol; form.windSearch.value = theObj.search; if (isNav) { netscape.security.PrivilegeManager. disablePrivilege("UniversalBrowserRead"); } } </script> </head> <body> Click the "Open URL" button to enter the location of an H3ML document to display in the left frame of this window. <form> <input type="button" name="opener" value="Open URL..." onclick="fillLeftFrame()" /> <hr /> <center> Select a window/frame. Then click the "Show Location Properties" button to view each window, location property value for the desired window. <p><input type="radio" name="whichFrame" value="parent" checked="checked" />Parent window <input type="radio" name="whichFrame" value="parent.frames[0] " />Left frame <input type=" radio" name="whichFrame" value= "parent. frames [ 1 ]" / >This frame</p> <p><input type="button" name="getProperties" value="Show Location Properties" onclick="showLocationData(this.form)" /> <input type="reset" value="Clear" /></p> <table border="2"> <tr> <td align="right">Window:</td> <tdxinput type="text" name="windName" size="30" /></td> </tr> <tr> <td align="right">hash:</td> <tdxinput type="text" name="windHash" size="30" /></td> </tr> <tr> <td align="right">host:</td> 518 Часть III. Объекты документа
<tdxinput type="text" name="windHost" size="30" /></td> </tr> <tr> <td align="right">hostname:</td> <tdxinput type="text" naпe=,Iwil^dHostname,, size="30" /></td> </tr> <tr> <td align="rightn>href:</td> <tdxtextarea name="windHref" rows="3" cols="30" wrap="soft"> </textareax/td> </tr> <tr> <td align="right">pathname:</td> <tdxtextarea naire="windPathn rows="3" cols="30" wrap="soft"> </textareax/td> </tr> <tr> <td align="right">port:</td> <td><input type="text" name="windPort" size="30" /></td> </tr> <tr> <td align="right">protocol:</td> <tdxinput type="text" name=HwindProtocol" size="30" /></td> </tr> <tr> <td align="right">search:</td> <tdxtextarea name="windSearch1' rows="3" cols="30" wrap="soft"> </textareax/td> </tr> </table> </center> </form> </body> </html> <html> <head> <title>Opening Placeholder</title> </head> <body> Initial placeholder. Experiment with other URLs for this frame (see right). </body> </html> Для получения наилучших результатов отобразите Web-документ, расположенный в сети, в том же домене и на том же сервере, что и документы, которые представлены листингами 17.2-17.4 (возможно, это локальный жесткий диск). Если возможно, загрузите документ, который содержит анкеры, позволяющие перемещать страницы по разделам. Покажите в левом фрейме исходную страницу, а в правом — составляющие свойства location. См. также: свойства location .port, location, hostname. Глава 17. Объекты history и location 519
hostname Возвращаемое значение: строковое Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Имя хоста в типичном URL — это сетевое имя сервера, на котором располагается про-. сматриваемый в браузере документ. Для большинства Web-узлов имя сервера включает в себя не только имя домена, но также и префикс www. Однако в имени хоста номер порта не содержится, даже если он и определяется в URL. Пример Пример использования свойства hostname приведен в листингах 17.2-17.4. См. также: свойства location. hostname, location.port. href Возвращаемое значение: строковое Чтение/Запись Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Из всех свойств объекта location, href (гипертекстовая ссылка), вероятно, одно из наиболее часто встречающихся в сценарии свойств. Свойство location.href напрямую связано со строкой полного URL, указанного в объекте window. Для того чтобы открыть в окне документ, находящийся по определенному URL-адресу, в JavaScript используют именно это свойство, располагая его в левой части выражения. Ниже приведены способы, с помощью которых можно загрузить страницу данного Web-узла в од- нофреймовое окно браузера. window.location = " http: // www.dannyg.com " window.location.href = " http: // www.dannyg.com"; Если пользователь не указывает ссылку на нужное окно, то время от времени он может сталкиваться с некоторыми трудностями. Иногда, например, в JavaScript возникает путаница и происходит ошибочное обращение к свойству document. location. Чтобы не допустить подобных ситуаций, разработчики JavaScript заменили document. location свойством document. URL. Таким образом, всегда указывая ссылку на соответствующее окно, пользователь точно не "заблудится" в сети. I Очень важно уметь правильно назначать новый URL объекту location, не включая /Ншиш/щ в него имя свойства href (например location="http://www.dannyg.com''). * ***" Однако, в отличие от большинства современных браузеров, некоторые старые программы (особенно IE3) работают более надежно, если пользователь назначает необходимый URL свойству location.href, а не location. Поэтому рекомендуется всегда использовать первое свойство, а не второе. Иногда в сценарии нужно так указать имя текущей папки, чтобы при выполнении соответствующих операторов к URL добавлялась ссылка на необходимый документ перед его загрузкой. Несмотря на то, что остальные свойства объекта location отвечают за получение любых частей URL, ни один из них не поможет получить полный URL папки текущих документов. Для выполнения этой задачи используйте обычные строковые преобразования JavaScript, не задействуя при этом объекты. Данная возможность демонстрируется в листинге 17.5. В разных браузерах небуквенные символы в значении свойства location.href были представлены по-разному, но чаще всего для этого использовался код ASCII. Такое представление символа состоит из знака % и числового ASCII-кода. Наиболее часто используемый в URL символ — это пробел: %20. Если необходимо получить строковое значение URL и вывести его в документе, примените к имеющемуся закодированному значению специальную 520 Часть III. Объекты документа
функцию JavaScript une scape (). Например, если URL одной из страниц узла Giantco имеет вид http: //www.giantco. com/product%201ist, то строковое значение адреса можно получить, подставив данный URL в функцию une scape (), как показано в примере ниже. var plainURL = unescape(window.location.href) // результат "http://www.giantco.com/product list"; В JavaScript существует и обратная функция — escape (), которая предназначена для отправки закодированных значений в CGI-программу, располагаемую на серверах. Пример В листинге 17.5 приведен пример использования свойства href. В этом примере применяется функция unescape (), которая не выполняет функционально важных операций, а всего лишь отображает URL-адрес в окне предупреждения. <html> <head> <title>Extract pathname</title> <script type="text/Javascript"> // функция общего назначения, извлекающая URL function getDirPath(URL) { var result = unescape(URL.substring(0,(URL.lastlndexOf("/")) + D); return result; } // обрабатывает события кнопки function showDirPath(URL) { alert(getDirPath(URL)); } </script> </head> <body> <form> <input type="button" value="View directory URL" . onclick="showDirPath(window.location.href)" /> </form> </body> </html> См. также: свойства location.pathname, document. location; объект String (глава 34). pathname Возвращаемое значение: строковое Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Путь является частью URL-адреса, который представляет внутреннюю структуру папок сервера. Другими словами, корневая папка (имя сервера в HTTP-соединении) не является частью пути. Если путь, указанный в URL, соответствует файлу в корневой папке, то свойство location.pathname имеет вид обычного символа обратной черты. Любой другой путь, который начинается с этого символа, указывает папку, находящуюся в корневой папке. Значение location. pathname также включает в себя и имя документа. Глава 17. Объекты history и location 521
Пример Пример использования свойства pathname приведен в листингах 17.2-17.4. См. также: свойство location.href. port Возвращаемое значение: строковое Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ В наше время редко встречаются Web-узлы, в которых необходимо указывать номер порта как часть URL. Наиболее часто номер порта встречается в малопопулярных протоколах, в URL частных узлов либо узлов, не имеющих своего имени домена. Это значение можно по- лучить с помощью свойства location.port. Намереваясь использовать значение порта одного URL-адреса в другом, удостоверьтесь в том, что не пропущен знак двоеточия между номером порта и IP-адресом сервера. Пример Пример использования свойства port приведен в листингах 17.2-17.4. См. также: свойство location. host. protocol Возвращаемое значение! строковое Чтение/Запись Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Первой составляющей любого URL является протокол, используемый для определения типа соединения. Для страниц World Wide Web (WWW) стандартный протокол— это Hypertext Transfer Protocol (http). Существуют и другие общепринятые протоколы, которые используются в браузере: HTTP-Secure (https), File Transfer Protocol (ftp), File (file) и Mail (mail to). В значениях location.protocol содержится не только имя протокола, но еще и знак двоеточия. Таким образом, для типичного URL Web-страницы в свойстве location.protocol сохраняется значение http: Запомните, что символы обратной черты, расположенные после имени протокола в URL, не являются частью значения location.protocol. Из всех свойств объекта location только в полном URL (location. href) можно увидеть обратную черту между именем протокола и другими компонентами адреса. Пример Пример использования свойства protocol приведен в листингах 17.2-17.4. См. также: свойство location.href. search Возвращаемое значение: строковое Чтение/Запись Совместимость: WinJE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Каждый пользователь, наверное, сталкивался с длинными, загадочными URL-адресами, которые отображаются в поле адреса браузера-всякий раз, когда мы пользуемся услугами поисковых средств WWW, вводя ключевое слово в соответствующем поле. Как правило, URL состоит из следующих компонентов: имени протокола и, имени хоста и пути. Традиционный 522 Часть III. Объекты документа
URL — это команда, с помощью которой приводится в действие поисковое средство (на сервере запускается соответствующая CGI-программа). Начать заново либо продолжить эту довольно долгую операцию можно с помощью свойства location. search. Каждое поисковое средство имеет собственную формулу для представления запроса, основанного на формах HTML, в которые пользователь вводит необходимую информацию. Эти запросы на поиск задаются в закодированном формате и могут представляться в любом формате, кроме языка программы. При написании сценария запроса на поиск используют свойство location, search, которое задает искомую строку (что требует полного понимания механизма поиска данных). Наиболее распространенный формат для поиска данных — это наборы пар имя/значение. Знак равенства (=) отделяет имя от значения. Если пара содержит несколько значений одного параметра, то между ними располагаются символы амперсанта (&). Если в строке URL-адреса содержатся пробелы, следует использовать функцию escape () для преобразования ее в соответствующий URL-формат. Свойство location.search применяется к любой части URL, которая следует после имени файла (включая параметры, которые отправляются в CGI-программы, расположенные на сервере). Обмен данными между страницами с помощью URL Нередко требуется сделать так, чтобы некоторые данные, содержащиеся на одной странице, были доступны для сценария другой страницы (будто он "запрашивает" их). Этого можно достичь, загрузив страницу одним из трех методов: с помощью свойства document. cookie (глава 18), в результате изменения установок в многофреймовых документах и благодаря строке, по которой проводится поиск URL-адресов. В действительности при посещении поисковых и коммерческих узлов, с которых в браузер пользователя отправляется информация, происходит следующее: вместо сохранения критериев поиска на сервере, они отправляются -обратно клиенту, но уже как часть URL. В следующий раз, когда этот URL активизируется, на сервер поступают те же значения, но уже для обработки (например, для того чтобы переслать пользователю следующую страницу результатов поиска по сделанному запросу). Обмен данными между страницами не ограничен связью клиент-сервер. Для того чтобы передать данные от одной страницы к другой, можно использовать строку поиска только на стороне клиента. Если на сервере отсутствуют CGI-приложения, запрограммированные на управление строкой поиска, на Web-сервере эта строка воспринимается как часть данных, получаемых вместе с адресом. С помощью специального сценария в последней загруженной странице может быть найдена строка поиска (благодаря свойству location, search) и "отделена" для дальнейшего ее помещения в переменные сценария. В примере на компакт- диске демонстрируется применение описанной выше методики. Как отмечалось в начале главы 16, в наборе фреймов можно одновременно отобразить несколько HTML-страниц. Воспользовавшись свойством search, примените один и тот же набор фреймов для загрузки в нем различных контекстно-зависимых документов (вместо создания отдельных наборов фреймов для каждой комбинации страниц). Именно этот принцип и продемонстрирован в приведенных ниже листингах. Таким образом, если пользователь знает URL-адрес одного из контекстно-зависимых документов (ссылка на него добавлена в папку Избранное), то соответствующий набор фреймов будет загружаться автоматически при следующем посещении страницы. Структурно приложение делится на две части. Первая часть располагается в контекстно- зависимых страницах; сценарий проверяет, загружена ли страница в наборе фреймов. Если нет, то создается строка поиска, которая добавляется в URL-адрес документа набора фреймов. Документ набора фреймов также содержит короткий сценарий, который проверяет Глава 17. Объекты history и location 523
существование в адресе строки поиска. Последняя используется для загрузки контекстно- зависимой страницы в соответствующий набор фреймов. Листинг 17.6 представляет документ набора фреймов. Функция getSearchAsArray О намного сложнее, чем требует данный пример. С ее помощью вы можете легко преобразовать любое количество пар имя-значение, подставленных из строки поиска (в стандартном формате namel=valuel&name2=value2& и т.д.), в массив, индексы которого представлены именами (таким образом в сценарии проще извлекать необходимые данные). Ветвление программы для разных браузеров необходимо, поскольку браузеры версий до ГЕ4 и NN3 не поддерживают методы управления текстовыми данными и массивами, используемыми в функции getSearchArray(). Ш^ ! <html> <head> <title>Example Frameset</title> <script type="text/javascript"> // преобразует значение location.search в массив, // индексированный по именам function getSearchAsArray() { var results = new Array(); var input = unescape(location.search.substr(l)); if (input) { var srchArray = input.split("&"); var tempArray = new Array(); for (var i = 0; i < srchArray.length; i++) { tempArray = srchArray[i] .split (" = "); results[tempArray[0]] = tempArray[1]; } } return results; } function loadFrameO { if (location.search) { var srchArray = getSearchAsArray(); if (srchArray["content"]) { self.content.location.href = srchArray["content"]; } } } </script> </head> <frameset cols="250,*" onload="loadFrame()"> <frame name="toc" src="lstl7-07.htm" /> <frame name="content" src="lstl7-08.htm" /> </frameset> </html> В листинге 17.7 показан код HTML-страницы с оглавлением. Он не является ничем особенным, поскольку создает стандартные средства навигации. 524 Часть III. Объекты документа
liiiin ****** "^ ^^^^^^^^^^r^^^^^^J "Ct^^^^i-^ <html> <head> <title>Table of Contents</title> </head> <body bgcolor="#EEEEEE"> <h3>Table of Contents</h3> <hr /> <ul> <lixa href =Mlstl7-08.htm" target="content">Page l</ax/li> <lixa href="lstl7-08a.htm" target=Mcontent">Page 2</ax/li> <lixa href="lstl7-08b.htm" target="content">Page 3</ax/li> </ul> </body> </html> Листинг 17.8 представляет одну из контекстно-зависимых страниц. В процессе ее загрузки вызывается функция checkFrameset (). Если страница не загружена в наборе фреймов, то сценарий переходит к набору фреймов, подставляя URL-адрес текущей страницы в качестве строки поиска. Обратите внимание на то, что в браузерах, поддерживающих метод location. replace (), загрузка страницы вне набора фреймов не регистрируется в журнале, а потому к ней нельзя получить доступ по щелчку на кнопке Back (Назад). <html> <head> <title>Example Frameset</title> <script type=s"text/javascript"> // преобразует значение location.search в массив, // индексированный по именам function getSearchAsArray() { var results = new Array(); var input = unescape(location.search.substr(l)); if (input) { var srchArray = input.split("&"); var tempArray = new Array(); for (var i = 0; i < srchArray.length; i++) { tempArray = srchArray[i].split(" = "); results[tempArray[0]] = tempArray[1]; } } return results; } function loadFrameO { if (location.search) { var srchArray = getSearchAsArray(); if (srchArray["content"]) { self.content.location.href = srchArray["content"]; ,-* </script> </head> Глава 17. Объекты history и location 525
<frameset cols="250, *" onload="loadFrame () "> <frame name="toc" src="lstl7-07.htm" /> <frame name="content" src="lstl7-08.htm" /> </frameset> </html> На практике рекомендуется сохранить код функции checkFrameset () в виде отдельной библиотеки (. j s), а в сценариях — создать ссылку на эту библиотеку. Именно поэтому в данной функций используется свойство location. href — его можно применить в любой контекстно-зависимой странице. Листинги 17.6-17.8 представляют двухфреймовый документ. В левом фрейме содержится оглавление, с помощью которого указывается загружаемая контекстно-зависимая страница. Первая из них загружается в правом фрейме по умолчанию. Обратите внимание на то, что новая страница задается в качестве параметра content свойства search. lstl7-06.htm?content=hello.htm См. также: свойство location.href. Методы assign("DRL") Возвращаемое значение: нет Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ В предыдущих главах при описании объекта location речь шла о назначении нового URL объекту location либо свойству location. href как об одном из способов переход* на другую страницу. При использовании метода location. assign () выполняется аналогичная операция. При установке URL в объекте location в JavaScript автоматически применяется метод assign (). С помощью данного метода нельзя выполнить важные операции (кроме приведения кода сценария к более понятному и читабельному виду). Данный метод при разработке документа используется довольно редко, но это совсем не означает, что пользователь не может применять его, если считает это удобным. См. также: свойство location. href. reload(булевФлаг) Возвращаемое значение: нет Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Для данного метода имя location.reload() не совсем уместно, так как сразу возникают ассоциации с кнопкой Reload/Refresh (Обновить), расположенной в панели инструментов браузера Метод reload () функциональнее, чем данная кнопка. Многие элементы форм при нажатии кнопки Refresh сохраняют состояние окна (кроме ШЗ). В текстовом поле и его объектах отображается любой содержащийся в нем текст; переключателям и флажкам соответствует указанный в них статус; в объектах списков (select) хранится информация о выделенном элементе. Единственное, что теряется при использовании кнопки Reload/Refresh, — это глобальные переменные и любые устанавливаемые, но явно не отображаемые на Web-странице свойства (например, значение свойства hidden (скрытого) объекта input). Перезагрузка такого типа называется программной. Загрузка документа в кэш-память браузера каждый раз осуществляется по-разному. Теоретически, применение метода location, reload О должно восстанавливать страницу из 526 Часть III. Объекты документе
кэш-памяти, если она все еще доступна в этой области памяти (хотя метод history.go (0) может быть даже более удобен, так как в нем сохраняются установки элементов управления формы). Установка параметра true в данном методе предполагает осуществление безусловного получения данных с сервера без использования уже имеющейся версии страницы. Если в приложении возникают проблемы с загрузкой страницы из кэш-памяти (быстрый способ) или с сервера (в кэш заносится новая копия), то, естественно, загрузка в браузере не происходит должным образом. Возможно, дескрипторы meta изначально разрабатывались для более частого сохранения страницы. Некоторым программистам удается успешно перезагрузить страницу, установив в location.href ее URL и слегка изменив строку поиска (например, на основе строкового представления объекта Date) так, чтобы избежать совпадения URL- адреса страницы с ее версией в кэш-памяти. Пользователь должен быть готов к тому, что придется перебирать различные схемы для достижения необходимого эффекта, а также к тому, что в конечном итоге можно и не получить ожидаемого результата. Пример В листинге 17.9 содержится код приложения, позволяющего исследовать преимущества обоих типов перезагрузки. Отобразите эту страницу в браузере и выберите один из переключателей. Введите текст и выберите значение в списке (элемент select). Щелкая на кнопках в нижней части страницы, вы будете выполнять те же действия, что и при использовании кнопок Reload (Перезагрузить) и Refresh (Обновить) браузера. В первом случае используется метод location.reload(), а настройки всех элементов управления принимают значения по умолчанию. <html> <head> <title>Reload Comparisons</title> <script type="text/javascript"> function hardReloadO { location.reload(true); } function softReloadO { history.go(0); } </script> </head> <body> <form name=HmyForm"> <input type="radio" name="radl" value="l" />Radio l<br /> <input type="radio" name="radl" value="2" />Radio 2<br /> <input type="radio" name="radl" value="3" />Radio 3 <p><input type="text" name="entry" value="Original" /></p> <pxselect name="theList"> <opt ion>Red</opt ion> <option>Green</option> <option>Blue</option> </selectx/p> <hr /> <input type="button" value="Soft Reload" onclick="softReload()" /> <input type="button" value="Hard Reload" Глава 17. Объекты history и location 527
onclick=MhardReload()" /> </form> </body> </html> См. также: метод story. go (). replace ("URL") Возвращаемое значение: нет Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ B некоторых больших Web-узлах могут содержаться страницы, не предназначенные для посещения и, тем более, занесения их в список посещенных документов. Например, последовательная структура узла может привести пользователя к одной или нескольким промежуточным HTML-страницам, которые в дальнейшем для него не будут представлять ни малейшего интереса. Особенно нежелательно, чтобы пользователи попадали на эти страницы снова, щелкнув на кнопке Back для возвращения к предыдущему URL. С помощью метода location.replace () можно перейти к необходимому URL-адресу без занесения его в список документов, переход к которым осуществляется щелчком на этой кнопке. Несмотря на то, что невозможно предотвратить добавление в список просмотренных документов посещенной пользователем страницы, при использовании данного метода в окне браузера загружается совершенно другой документ, адрес которого заменят в списке посещенных документов текущий URL. Естественно, список посещенных документов браузера не очищается, просто текущий элемент списка удаляется прежде, чем следующий URL-адрес будет загружен. Таким образом, удаление соответствующего элемента из списка не допускает повторной загрузки нежелательной страницы, выполняемой щелчком на кнопке Back. Пример Пример использования метода replace () приведен в листинге 17.10. При вызове этого метода браузер загружает в текущем окне страницу с новым URL-адресом. Но эта операция не регистрируется в журнале. Л1*ДО|£1Р^ !'.•--• ■* :.•■•' .•'■•'] <html> <head> <title>location.replace() Method</title> <script type="text/javascript"> function doReplaceO { location.replace("1st17- 01.htm"); } </script> </head> <body> <form name="myForm"> <input type="button" value="Replace Me" onclick="doReplace()" /> </form> </body> </html> См. также: объект history. 528 Часть III. Объекты документа
Объект history Свойство current length next previous Метод backO forward() go() Обработчик событий нет Синтаксис Доступ к свойствам или методам объекта history, [window.]history.свойство\метод([параметры]) Описание объекта При перемещении в Internet в браузере автоматически создается список последних URL, посещаемых пользователем. Этот список представлен в объектной модели браузера элементом history. При выполнении сценария фактические URL, содержащиеся в этом списке, извлечь нельзя. Исключением являются защищенные сценарии (в NN4+ — описанные в главе 46), предоставляющие данную возможность только отдельным пользователям. В незащищенном сценарии позволяется только переходить к каждому URL, указанному в списке состояний (выбирая соответствующий ему элемент в списке или возвращаясь к URL-адресам в обратной последовательности). В результате пользователь будет просматривать страницы, появляющиеся "сами собой" (будто браузером управляет кто-то невидимый). В Web-сообществе разработчику запрещается управлять средствами навигации, предоставленными пользователю, без его полного на то согласия за пределами разработанного им Web-узла Применение объекта history и его методов back О и до () аналогично применению кнопок Back и Forward в HTML-документах. Эти кнопки вызывают сценарий, при выполнении которого производится проверка нужных элементов списка посещенных документов, а затем осуществляется переход на предыдущую страницу. В текущем документе не должна содержаться информация о том URL-адресе, с которого осуществлялся переход на данную страницу. В NN4 есть еще одно немаловажное отличие в управлении JavaScript методами объекта history. В браузер данной версии включены два специальных метода: window. back () и window, forward (), которые также имитируют работу кнопок Back и Forward. Методы объекта history не определяются во фрейме как часть ссылки. Если пользователь с помощью метода parent. f rameName .history .back () переходит к фреймам, ссылки на которые указаны в списке посещенных страниц, то после достижения последнего фрейма в этом списке переход к предыдущим страницам не осуществляется. В Г£ механизм обращения к списку состояний не предполагает перехода к отдельным фреймам. Вместо этого методы history .back () и history. forward () приводят к тем же результатам, что и щелчок на соответствующих кнопках панели управления браузера. Чтобы осуществить правильный переход по фреймовой структуре в разных версиях браузеров, ссылки на методы history. back () и history. forward () задавайте исключительно в родительских окнах. Объект history существует уже довольно давно. Поэтому, учитывая все написанное выше, рекомендуется использовать данный объект и его методы только в случаях крайней необходимости. Проект должен быть достаточно хорошо продуман, чтобы обеспечить нормальное перемещение пользователя по страницам данного Web-узла (например, должна осуществляться проверка текущего URL-адреса перед переходом на него с помощью данных методов). Иначе существует Глава 17. Объекты history и location 529
риск запугать пользователя, отображая для него совершенно неожиданные Web-страницы. Могут возникнуть проблемы и в том случае, если в сценарии нельзя определить местоположение текущего документа в последовательности списка посещенных документов. Свойства current next previous Возвращаемое значение: строковое Только для чтения Совместимость: WinlE-, MacIE-, NN4+, Mozl+, Safari 1+ Как отмечалось ранее, в браузере существует список URL-адресов, посещенных пользователем Web-страниц, переход на которые можно осуществить щелчком на кнопках Back и Forward. Для тех, кто собирается нарушить конфиденциальность и узнать адреса узлов и страниц, посещаемых определенным пользователем, эта информация будет довольно полезной. Свойства current, next и previous, поддерживаемые только в NN, фактически оставляют незащищенными эти URL. Поэтому разработчики браузера установили ограничение: данные свойства применяются только к страницам с цифровой подписью (посетитель получает разрешение на доступ к "личным" данным браузера (см. главу 46)). С подобным разрешением можно просматривать любые данные списка посещенных документов в любом фрейме или окне. Поскольку список — это тот же массив, можно извлечь его отдельные элементы с помощью соответствующего индекса. Например, если в массиве содержится 10 элементов, то пятый можно извлечь, используя метод индексирования нормального массива. var fifthEntry = window.history[4]; He существует ни одного свойства или метода, с помощью которого непосредственно определяется значение загруженного в настоящее время URL-адреса. Но можно написать сценарий, в котором значения свойств current, next и previous объекта history будут сравниваться со значениями списка. Наверное, никому не приятно, если неизвестные люди следят за его действиями в сети. Поэтому имейте в виду, что использование данных свойств может привести к большим неприятностям. В диалоговом окне, в котором указано, что сценарий защищен, не приводится информация о последствиях раскрытия данных такого уровня. / Такие свойства доступны в NN3 только в относительной форме. Доступ к ним /на заметку требует кратковременного обеспечения безопасности. Этот процесс никогда не I ^*-*-* осуществлялся полностью, и потому разработчики браузера заменили его защищенными сценариями. См. также: свойство history, length. length Возвращаемое значение: строковое Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Для определения количества элементов в списке посещенных документов используют свойство history, length. К сожалению, эта информация не может быть особенно полезной для перемещения по страницам с помощью сценария, так как нет возможности считывать данные из этого списка. Если текущий документ находится в начале списка (последний загруженный документ), то можно ориентироваться относительно этого положения. Пользова- 530 Часть ///. Объекты документа
тели могут перемещаться по списку состояний в любой последовательности с помощью меню Go/View. Даже при возврате на предыдуыгую страницу порядок расположения элементов в списке не изменяется. Значение свойства history. length=l указывает на то, что текущий документ — единственный загруженный пользователем в текущем сеансе работы браузера. Пример Пример использования свойства length приведен в листинге 17.11. <html> <head> <title>History Object</title> <script type=Mtext/javascriptM> function showCountO { var histCount = window.history.length; if (histCount > 5) { alert("My, my, you\'ve been busy. You have visited " + histCount + " pages so far."); } else { alert("You have been to " + histCount + " Web pages this session."); </script> </head> <body> <form> <input type="button" name="activity" value="My Activity" one1ick="showCount()" /> </form> </body> </html> Методы back () forward() Возвращаемое значение: нет Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ В версиях, предшествующих NN4, результат применения данного метода был аналогичен щелчку на кнопке Back. В NN4 метод history .back () используется только для фреймов и окон. Поэтому при последовательном применении метода back () во фрейме, находящемся в пределах данного набора фреймов, метод не работает при загрузке в него одного документа. Щелчок на кнопке Back (и новый метод window. back ()) приводит к вьпрузке набора фреймов, таким образом, пользователь продолжает возвращаться назад в соответствии со списком документов браузера. Перед тем, как преднамеренно завести пользователя в тупик на своем Web-узле, удостоверьтесь в том, что HTML-документ обеспечивает возвращение назад на какое-нибудь узнаваемое место в сети. Поскольку совсем не трудно создать новое окно, не содержащее никаких панелей инструментов и меню (это не касается браузеров для Macintosh), можно самим за- Глава 17. Объекты history и location 531
вершить путешествие своего пользователя, так как он не имеет никакой возможности выбраться из подобного окна. Лучше всего, когда в документе содержится кнопка, обеспечивающая пользователю обратный путь к последнему месту его "пребывания". Если нет необходимости выполнять какие-либо дополнительные действия перед возвратом на предыдущую страницу, используйте метод history .back () как параметр обработчика событий для кнопки. Чтобы гарантировать совместимость всех браузеров, необходимо управлять данным методом из сценария родительского документа, находящегося во фрейме. Как и history .back (), метод history. forward () не предназначен для управления в сценарии. Применяя данный метод, пользователь перемещается к следующему элементу в списке состояний браузера. Уверенно использовать метод history, forward () можно только после применения метода history. back () в этом же сценарии. Причем в сценарии обязательно должно быть точно указано количество переходов посетителя в обоих направлениях. Используйте метод history.forward() осторожно и только после многократной "проверки" страницы посетителями (для подтверждения того, что были предвидены все варианты реакции пользователя). Предостережения о различиях метода history. back () в NN4 относятся и к history, forward (): переход вперед осуществляется только согласно списку посещенных документов данного окна или фрейма, а не полного списка состояний браузера. Пример Пример использования методов back () и forward () приведен в листингах 17.12 и 17.13. Лмгпшг 17.12» Шбор фро jteidtt дркуму iit ii ншвйгщин <html> <head> <title>Back and Forward</title> </head> <frameset cols="45%,55%"> <frame name="controller" src="lstl7-13.htm" /> <frame name="display" src="lstl7-01.htm" /> </frameset> </html> Листинг 17Л>* ТЦиеяьуврмлотц нютпщщй ""-у1--^ <html> <head> <title>Lab Controls</title> </head> <body> <b>Load a series of documents into the right frame by clicking some of these links (make a note of the sequence you click on): </b> <pxa href ="lstl7-01.htm" target= "display">Listing 17-1 </axbr /> <a href="lstl7-05.htm" target="display">Listing 17-5 </a><br /> <a href="lstl7-09.htm" target="display">Listing 17-9 </axbr /></p> <hr /> <form name="input"> <b>Click on the various buttons below to see the results in this frameset:</b> <ul> 532 Часть III. Объекты документа
<lixb>NN4 + </b> Substitute for toolbar buttons -- <tt>window.back()</tt> and <tt>window.forward()</tt>: <input type=nbuttonn value="Back" onclick="window.back{)" /> <input type="button" value="Forward" onclick="window.forward()" /></li> <lixtt>history.back() </tt> and <tt>history. forward 0 </tt> for righthand frame:<input type="button" value="Back" onclick="parent.display.history.back()" /> <input type="button" value="Forward" onclick="parent.display.history.forward()" /></li> <lixtt>history.back () </tt> for this frame: <input type="button" value="Back" onclick="history.back()" /></li> <lixtt>history.back () </tt> for parent: <input type="button" value="Back" onclick="parent.history.back()" /></li> </ul> * </form> </body> </html> См. также: методы history, forward (), history .go (). go(относительноеЧисло|"ияЬилиЗаголовок") Возвращаемое значение: нет Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Для перемещения в пределах списка документов, отображенных ранее браузером, используйте в своем сценарии метод history .go (). При определении URL как параметра необходимо знать, что точный URL в этом списке уже задан. Потому не расценивайте этот метод как альтернативу установки в объекте window. location нового URL-адреса. Для осуществления n-го количества переходов на любую сторону списка посещенных документов используйте параметр относительноеЧисло в методе history. go (). Этот параметр представляет собой целочисленное значение, которое определяет необходимый элемент списка относительно текущего положения пользователя. Например, если текущий URL является первым в списке (следовательно, кнопка Forward на панели инструментов не доступна) для перехода к URL, находящемся в этом же списке на два элемента ниже, данный метод используют следующим образом. history.go (-2); Другими словами, текущий URL определяется выражением history.go(O) (в данном случае произойдет перезагрузка документа). Указанное целое число обозначает переход на нужную позицию в списке. Таким образом, hi story, go (-1) выполняется аналогично методу history.back(), a history.go(1) —аналогично history.forward(). Для применения метода history. go () можно также использовать URL-адреса или заголовки документа, содержащиеся в списке посещенных документов (заголовки отображаются в меню Go/View). В данном методе указанная строка сравнивается со всеми элементами, содержащимися в списке. Первый элемент, в состав которого входит строковый параметр, принимается как искомый. Но если указанный элемент не содержится в списке, то никакого перехода не последует. Подобно большинству других методов объекта history, из сценария документа довольно трудно управлять как текущим, так и остальными URL, заданными в списке состояний. Таким образом, затрудняется возможность выполнения в сценарии следующих действий: точного определения области перемещения по списку в том или ином направлении и факти- Глава 17. Объекты history и location 533
ческих URL или заголовков, предназначенных для перехода. Используйте этот метод только тогда, когда Web-страницы и действия пользователя на них полностью контролируемы (а также для сценариев, автоматически запускаемых при посещении определенного узла). Как только пользователь получит контроль над переходами, нет никакой гарантии, что он станет просматривать страницы в том порядке, в каком хотелось бы разработчику. Следовательно, не будут работать и сценарии, построенные на использовании объекта history. Наиболее часто данный метод применяют в виде history.go(0) для осуществления "легкой11 перезагрузки текущего окна. При написании страницы, совместимой со всеми браузерами, необходимо знать, Смет что в Internet Explorer и в Netscape Navigator метод go () работает по-разному. Во- ^ первых, ошибка в IE3 приводит к тому, что при использовании в history.go О ^ любого ненулевого значения параметр всегда воспринимается как 1. Во-вторых, в IE3 данный метод вообще не работает со строками (браузер генерирует сообщение об ошибке); для IE4+ соответствующая строка должна быть частью URL, а не частью заголовка документа, как в NN. И наконец, перезагрузка страницы с использованием history .go (0) часто приводит к повторной загрузке страницы с сервера, а не восстановлению ее из кэш-памяти. Пример Пример использования метода до () для перемещения по списку журнала приведен в листинге 17.14. Введите в первом поле номер записи в журнале или название страницы, затем щелкните на соответствующей кнопке для перемещения к указанной странице. <html> <head> <title>history.go() Method</title> <script type="text/javascript"> function doGoNum(form) { window.history.go(parselnt(form.histNum.value)); } function doGoTxt(form) { window.history.go(form.histWord.value); } </script> </head> <body> <form> <k»Calling the history.goO method:</b> <hr /> Enter a number (+/-):<input type=ntext" name="histNum" size="3" value="0" /> <input type-"button" value="Go to Offset" onelick="doGoNum(this.form)" /> <p>Enter a word in a title:<input type="text" name=MhistWord" /> <input type="button" value="Go to Match" onclick="doGoTxt(this.form)" /></p> </form> </body> </html> См. также: методы history.backO , history. forwardO, location.reload(). 534 Часть III. Объекты документа
Объекты document и body н е все объекты в модели документа взаимодействуют с пользователем— этот важный фактор необходимо учитывать при создании сценария JavaScript Большинство взаимодействий между сценарием и пользователем происходит с помощью объекта document и его компонентов. Понимание возможностей данного объекта, вплоть до каждой предоставленной объектной модели,— ключ к успешному созданию приложений, совместимых со всеми версиями браузеров. Обратите внимание на расположение объекта document в общей иерархической структуре объектов. На основе рис. 18.1 можно сделать вывод о том, что document является одним из центральных объектов JavaScript. window frame self 1 history top parent document i location j Рис. 18. L Иерархическая структура объектной модели документа Объект document вместе со всем своим содержимым настолько велик, что для удобства восприятия его описание приведено в нескольких главах, в каждой из которых рассматриваются связанные между собой группы объектов.
В этой главе описаны объекты document и body (взаимосвязанные концептуально), а в каждом ее разделе речь идет об объектах, входящих в состав объекта document. Необходимо подчеркнуть, что наиболее распространенной ошибкой среди начинающих программистов на JavaScript является мнение о том, что нет ничего сверхсложного в изменении содержимого загруженной страницы. И действительно, много ли нужно: тут поменять текст, там исправить ячейку таблицы. Однако важно помнить, что эти средства, большая часть которых принадлежит динамическому HTML, доступны только в современных браузерах — в Ш4+ и N>fe+. Причем преимущество данных браузеров состоит не только в распознавании элементов HTML в языках написания сценариев. В них также появилась возможность автоматической перезагрузки страницы при неправильном изменении содержимого. Во всех предыдущих версиях браузеров при написании сценариев для страниц использовался небольшой набор объектов, поддающихся изменению (элементов форм и изображений). Если для работы приложения требуется обеспечить совместимость со всеми браузерами, поддерживающими сценарии, разработчик должен помнить, что после загрузки страницы можно изменить только часть ее неявных отображаемых свойств. Если в содержимом совместимых страниц необходимо произвести обновление или изменения, основанные на данных, которые вводит пользователь, следует разрабатывать свои страницы так, чтобы перед пересохранением страницы (с учетом сделанных настроек) сначала производилось изменение старого содержимого с помощью сценария. Объект document Свойства Методы Обработчики событий activeElement alinkColor all* anchors [] applets [] attributes* bgColor body charset characterSet childNodes* compatMode cookie defaultCharset defaultView designMode doctype documentElement domain embeds [] expando attachEvent() * captureEvents() clear() clearAttributes()* close() createAttribute() createComment() createDocumentFragment() createElement() createEvent() createEventObj ect() createStyleSheet() createTextNode() createTreeWalker() detachEvent()* elementFromPoint() execCommand() focus()* getElementByld() getElementsByName() getElementsByTagName()* onactivate** onbeforecut* onbeforedeactivate* onbeforeeditfocus* onbeforepaste* onclick* oncontextmenu* oncontrolselect* oncut* ondblclick* ondrag* ondragend* ondragenter* ondragleave* ondragover* ondragstart* ondrop* onhelp* onkeydown* onkeypress* onkeyup* 536 Часть III. Объекты документа
Продолжение таблицы Свойства Методы Обработчики событий fgColor fileCreatedDate fileModifiedDate fileSize firstChild* forms [] frames [] height ids[] images [] implementation lastChild* lastModified layers [] linkColor links [J location media mimeType namespaces [] namespaceURL* nextSibLingt* nodeName* nodeType* ownerDocument * parentNode* parentwindow plugins [] previousSibling* protocol readyState* referrer scripts [] security selection stylesheets [] tags [] .title uniquelD* getSelectionO handleEvent() hasFocus()* mergeAttributes() * open() queryCommandEnabled() queryCommandlndterm() queryCommandstate() queryCommandSupported() queryCommandText() queryCommandValue() recalc() releaseCapture()* releaseEvents() routeEvent() setActive()* write() writeln() onmousedown* onmousemove* onmouseout* onmouseover* onmouseup* onpaste* onpropertychange* onreadystatechange* onresizeend* onresizestart* onselectionchange onstop Глава 18. Объекты document и body 537
Окончание таблицы Свойства URL URLUnencoded vlinkColor width Методы Обработчики событий * См. главу 15 Синтаксис Доступ к свойствам и методам объекта document, [window. ] document. свойство \ метод ( [параметры] ) Описание объекта В объекте document описываются все элементы, расположенные в области окна браузера или фрейма (исключая панели инструментов, строки состояния и т.д.). Документ — это комбинация содержимого и элементов интерфейса, с помощь которых разработчики и привлекают посетителей на Web-страницу. В более современных браузерах, обрабатывающих элементы HTML как узлы иерархической структуры, объект document является корневым узлом, из которого происходят все остальные. Так как объект document неявно представлен в документе HTML-дескрипторами или другими элементами, разработчики JavaScript и объектных моделей решили сделать объект document своего рода "порталом" для получения доступа к атрибутам, которые представлены в HTML как принадлежащие к элементу body. В дескрипторе последнего элемента содержатся атрибуты, применяемые ко всему документу, они изменяют такие параметры, как цвет фона (bgcolor) или цвет ссылки в различных ее состояниях (alink, link и vlink). Также в данном элементе задаются формы, гиперссылки и анкеры. Несмотря на это в объекте document дублируется большинство функций элемента body. Кроме того, этот объект является наиболее удобным средством для получения в сценарии таких свойств, которые применяются за пределами элемента body, например, элемент заголовка (title) или URL-адреса ссылки, с помощью которой пользователь переходит на нужную страницу. При просмотре исходного кода HTML может показаться, что объект document представляет собой бессмысленней программный элемент. Несмотря на это, он служит прекрасной платформой для ссылок на исходные объекты — формы, изображения и аплеты. Конечно, подобная ситуация возникала до того, как каждый элемент HTML, включая элемент body, был представлен в качестве объекта в современных объектных моделях. Удивительно, но даже с использованием объектной модели Ш4+ и W3C DOM (в обоих случаях элемент body воспринимается как отдельный объект, не принадлежащий объекту document) совместимость сценария с оригинальной объектной моделью осуществляется довольно просто. Простое представление данного объекта в оригинальной объектной модели и модели, благодаря которой объект document был отделен от элемента body, содержащегося в нем, обеспечило размещение его в основе иерархии. Исходя из синтаксиса сценария определяется, к какой модели относится данный объект. Это означает, что довольно часто существует несколько разных способов обращения к одному и тому же объекту. Например, чтобы получить количество объектов форм, содержащихся в документе, можно использовать следующее выражение во всех браузерах, поддерживающих сценарии. document.forms.length 539 Часть III. Объекты документа
В Ш4+ можно даже применить такую формулировку. document.tags["form"].length В W3C DOM, аналогично Ш5+ и NN6/Mozl+/Safaril+. document.getElementsByTagName("form").length Современные версии браузеров обеспечивают универсальные способы доступа к элементам (массив tags в Ш4+ и метод getElementsByTagName () в W3C DOM) для удовлетворения требований объектных моделей, представляющих каждый элемент HTML (и XML) как отдельный объект. Итак, элемент body перешел в ранг объектов, естественно, это повлекло за собой появление нового синтаксиса для управления такой объектной моделью. Вследствие этого в объект document автоматически были добавлены некоторые свойства, которые изначально входили в состав элемента body. Многие свойства, которые принадлежали объекту document, были переименованы при их передаче элементу body. Например, свойство document. alinkColor в новой модели называется body. aL ink, хотя свойство bgColor осталось со старым именем. Для обеспечения совместимости современные браузеры признают как старые, так и новые свойства, даже притом, что в W3C DOM (в попытке не отставать от мирового развития) старые версии свойств объекта document были удалены. На первый взгляд это может показаться странным, но чтобы разобраться в том, когда обращаться к объекту document, а когда использовать новый синтаксис, не потребуется много времени. Все зависит от того, что будет указываться в правой части выражения (ссылки). Старые свойства и методы обеспечивают использование первоначального объекта document, а новый объект document, соответственно, обладает новыми свойствами и методами. К счастью, определение объекта выполняется автоматически. Свойства activeElement Значение: ссылка на объект Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- В Ш4+ свойство document .activeElement можно использовать непосредственно в сценарии для проверки того, к какому элементу в данный момент обращается браузер. Возвращенное значение и будет ссылкой на нужный элемент. Можете применять любые свойства и методы, перечисленные в главе 15, для анализа данного объекта. Но знайте, что обращаться можно далеко не ко всем элементам существующих операционных систем. Например, кнопки в IE4 для Macintosh не доступны. Обычно элементы используются для генерирования наиболее "доступных" событий мыши или клавиатуры (не считая кнопок МасШ4), однако не рекомендуется применять свойство activeElement для того, чтобы выявить элемент, генерирующий данные события. Лучше для этого подходит свойство event. srcElement в Internet Explorer. Пример Приложение The Evaluator (глава 13) позволяет изучить свойство activeElement в браузерах Ш4+. Введите в верхнее поле следующее выражение. document.activeElement.value После нажатия клавиши <Enter> в области результатов появится значение, соответствующее введенному в верхнем текстовом поле оператору. Если вы щелкнете на кнопке Evaluate, то будет отображено значение свойства value объекта кнопки. См. также: свойство event. srcElement. Глава 18. Объекты document и body 539
alinkColor bgColor fgColor linkColor vlinkColor Значение: шестнадцатеричное значение или название цвета Чтение/Запись Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Эти пять свойств являются эквивалентами атрибутов дескриптора <body> с аналогичными именами (хотя имена свойств на самом деле довольно чувствительны к регистру). Все пять параметров настройки выводят информацию только для чтения, поэтому возможность изменять как все, так и некоторые из этих свойств, не однозначна. Все зависит от браузера и платформы клиента. В табл. 18.1 приведено описание тех браузеров и платформ, в которых существует возможность установки параметров цвета. Таблица 18.1. Установка цветов в документе (версии браузеров) ' .. Netscape Navigator Internet Explorer Свойство цвета Windows Mac UNIX bgcolor Все версии 4+ 4+ Все остальные 6+ 6+ 6+ Windows Mac UNIX Все версии Все версии 4+ Все версии Все версии 4+ I Экспериментируя с установками document .bgColor в Macintosh или UNIX-версиях NN2 и NN3, можно некорректно установить свойства, даже не подозревая об этом. Даже если значение свойства остается верным, данные платформы не обновляют их должным образом в своих окнах. Если цвет изменяется после завершения компиляции содержимого сценария, то вся красота установленного пользователем нового цвета отобразится лишь после того, как окно будет перезагружено. Самый безопасный способ установки свойств цвета документа заключается в следующем действии: для содержимого фрейма или окна, описанного в сценарии, установите атрибуты цвета дескриптора <body> динамически, когда документ будет выводиться в текущем окне с помощью метода document. write (). Значения свойств цвета могут иметь формат как обычного шестнадцатеричного триплета HTML (например #OOFFOO), так и любого названия цвета, принятого в Netscape Navigator. В Internet Explorer также можно использовать простые описательные названия. Но помните, что некоторые из них работают только при установке глубины цветов монитора в 16 или 24-разрядный режим. Если сценарий рассчитан на выполнение исключительно в Ш4+ или NN6+, для обращения к этим свойствам необходимо использовать объект document. body. Пример В листинге 18.1 приведен пример произвольного применения цветовых настроек в HTML- документе. В небольшом окне содержится кнопка и небольшой текстовый фрагмент со ссылками. В результате вы сможете ознакомиться с цветовыми настройками, заданными в основном окне. Сценарий изменяет цвета небольшого окна в результате переписывания его исходного кода. Все используемые в небольшом окне цвета приведены в текстовой области основного окна (в виде шестнадцатеричных значений). Вы можете изменить цвета в исходном коде приложения, чтобы создать другие цветовые решения. 540 Часть III. Объекты документа
18Л. Изменение щеп» anoMWtiro* стршицы '" ',/ -* * ' <html> <head> <title>Color Me</title> <script type="text/javascript"> // может блокироваться при загрузке браузером var newWindow = window, open ("","", "height=150,width=3 00'») ; function defaultColors() { return "bgcolor='#c0c0c0' vlink=•#551a8b» link='#0000ff'"; } function uglyColorsO { return "bgcolor^'yellow' vlink='pink' link='lawngreen'"; } function showColorValues() { var result = ""; result += "bgColor: " + newWindow.document.bgColor + "\n"; result += "vlinkColor: " + newWindow.document.vlinkColor + "\n'»; result += "linkColor: " + newWindow.document.linkColor + "\n"; document.forms[0].results.value = result; } // динамическая запись содержимого в другое окно function drawPage(colorStyle) { // обработка блокировки if (InewWindow || newWindow.closed) { newWindow = window.open("","","height=150/width=30Q"); } var thePage = ""; thePage += "<htmlxheadxtitle>Color Sampler<\/title> <\/headxbody " ; if (colorStyle == "default") { thePage += defaultColors0; } else { thePage += uglyColors(); } thePage += ">Just so you can see the variety of items and color, <a "; thePage += "href='http://www.nowhere.com'> here\'s a link<\/a>, and <a href='http://home.netscape.com'> here is another link <\/a> you can use on-line to visit and see how its color differs from the standard link."; thePage += "<form>"; thePage += "<input type='button' name='sample' value='Just a Button'>"; thePage += "<\/formx\/body><\/html>" ; newWindow.document.write(thePage); newWindow.document.close(); showColorValues(); } // следующее корректно выполняется только в WinNN function setColors(colorStyle) { Глава 18. Объекты document и body 541
if (colorStyle == "default") { document.bgColor = "#c0c0c0"; } else { document.bgColor = "yellow"; </script> </head> <body> Try the two color schemes on the document in the small window. <form> <input type="button" name="default" value='Default Colors' onclick="drawPage('default')" /> <input type="button" name="weird" value="Ugly Colors" onclick="drawPage('ugly')" /> <pxtextarea name="results" rows="3" cols="20"> </textarea></p> <hr /> These buttons change the current document, but not correctly on all platforms <pxinput type= "button" name = "default" value='Default Colors' onclick="setColors('default')" /> <input type="button" name="weird" value="Ugly Colors" onclick="setColors('ugly')" /></p> </form> </body> </html> Чтобы удовлетворить любопытных, я добавил в рассмотренный выше пример две кнопки, позволяющие динамически изменять цветовую гамму нового окна. Если вы используете браузеры, описанные в табл. 18.1, то приложение должно выполняться у вас в полной мере. Если же у вас браузер старой версии, то в окне могут не отобразиться кнопки и другие элементы документа. Существует также вероятность полного отображения всех элементов, которые не будет корректно окрашиваться или выполнять возложенные на них программные обязанности. Если вы не уверены в том, что потенциальная аудитория ваших документов состоит из пользователей, которые регулярно обновляют программное обеспечение, откажитесь от изменения цветовой гаммы, используемой по умолчанию. См. также: свойства body.aLink, body.bgColor, body, link, body, text, body. vL ink. anchors [] Значение: массив объектов анкеров Только для чтения Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ Объекты анкеров (описанные в главе 19) представляют собой выражения в документе HTML, описанные в дескрипторе <name=" ">. Данные объекты обозначаются в URL символом #, расположенным между URL страницы и именем анкера. Подобно остальным объектным свойствам, в которых содержится список вложенных объектов, свойство document. anchors (обратите внимание на множественное число) представляет собой индексированный массив анкеров, находящихся в документе. Используйте массив ссылок для точного определения нужного анкера и дальнейшего восстановления его свойств. 542 Часть III. Объекты документа
Нумерация массива анкеров начинается с 0: таким образом, первый анкер в документе представлен ссылкой document. anchors [0]. По причине того, что это выражение выполняется в любом встроенном массиве объектов, всегда можно определить количество элементов массива, измерив его длину с помощью соответствующего свойства. var anchorCount = document.anchors.length; Свойство document. anchors предназначено только для чтения. Для перехода к нужному анкеру в сценарии определите значение одного из объектов window, location или window. location. hash (см. предыдущую главу). Пример Листинг 18.2 основан на листинге 17.1; из него вы узнаете, как в сценариях можно эффективно управлять документами, содержащими анкеры. Сценарий автоматически сохраняет в виде массива все анкеры, найденные в документе. Чаще всего вам не придутся выводить этот массив для изучения пользователями, а потому применять свойство document. anchors на практике вам придется нечасто. Объектная модель документа устанавливает его автоматически при создании объектов анкеров. <html> <head> <title>document.anchors Property</title> <script type="text/javascript"> function goNextAnchor(where) { window.location.hash = where; } </script> </head> <body> <hlxa id="start" name="start">Top</ax/hl> <form> <input type="button" name="next" value="NEXT" onelick="goNextAnchor('seel')" /> </form> <hr /> <hlxa id="secl" name="secl">Section l</ax/hl> <form> <input type="button" name="next" value="NEXT" onclick="goNextAnchor('sec2')" /> </form> <hr /> <hlxa id="sec2" hame="sec2">Section 2</ax/hl> <form> <input type="button" name="next" value="NEXT" onelick="goNextAnchor('sec3')" /> </form> <hr /> <hlxa id="sec3" name="sec3">Section 3</ax/hl> <form> <input type="button" name="next" value="BACK TO TOP" onelick="goNextAnchor('start')" /> </form> <hr /> <p> Глава 18. Объекты document и body 543
<script type="text/javascript"> document.write("<i>There are " + document.anchors.length + " anchors defined for this document<\/i>") </script> </p> </body> </html> См. также: объекты anchor и location; свойство document. links. applets Значение: массив объектов аплетов Только для чтения Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Благодаря свойству applets можно обращаться к аплетам Java, которые содержатся в документе, использующем дескриптор <applet>. Аплет не является реальным объектом до тех пор, пока не будет полностью загружен. Работа по управлению Java-аплетами в JavaScript преимущественно осуществляется с помощью методов и переменных, определенных внутри аплета. Вы можете ссылаться на аплет согласно индексу элемента массива аплетов, однако надежнее использовать имя объекта аплета (во избежание возможной путаницы). Обратите внимание на то, что аплеты не доступны для JavaScript в Internet Explorer для Macintosh. Пример Свойство applets устанавливается автоматически при создании браузером объектной модели документа, содержащего аплеты. Чаще всего это свойство используется для подсчета количества объектов аплетов в документе. См. также: объект applet. bgColor См. alinkColor body Значение: объект элемента body Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство document. body — это сокращенная ссылка на объект элемента body в новых объектных моделях. Далее в главе объясняется, что в объекте body существует целый ряд ключевых свойств, предназначенных для управления внешним видом всей страницы. Поскольку объект document является корневым элементом всех ссылок в пределах любого окна или фрейма, для получения свойств объекта BODY лучше использовать выражение document. body вместо длинных ссылок, с помощью которых обычно обращаются к объектам элементов HTML в объектных моделях IE4+ и W3C. Пример Приложение The Evaluator (глава 13) поможет вам быстро изучить свойство body. Сначала удостоверьтесь, что свойство document. body представляет собой объект элемента, вызываемого с помощью более длинной ссылки. В браузерах Ш5+, NN6+ и W3C введите в верхнее поле следующее выражение. document.body == document.getElementsByTagName{"body")[0] 544 Часть III. Объекты документа
Далее изучите свойства объекта body, также введя их в верхнее текстовое поле. document.body.bgColor document.body.tagName См. также: объект элемента body. charset Значение: строковое Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- B свойстве charset определяется набор символов, используемый браузером для компиляции текущего документа (в версии NN6 это свойство называется characterSet). Все возможные значения этого свойства можно найти по адресу: ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets В каждом браузере и операционной системе существует собственный набор символов, установленный по умолчанию. Так же значения могут устанавливаться в дескрипторе <meta>. Пример Приложение The Evaluator также с успехом применяется для изучения свойства charset. Введите следующее выражение в верхнее поле страницы, не изменяя его настроек по умолчанию. document.charset Если вы используете Winffi5+, то можете ввести в это поле такое выражение, чтобы изменить набор символов документа. document.charset = "iso-8859-2" Если ваша версия Windows не поддерживает указанный набор символов, то браузер спросит разрешения на загрузку и установку этого набора. См. также: свойства characterSet, defaultCharset. characterSet Значение: строковое Чтение/Запись Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- В свойстве characterSet определяется набор символов, используемый браузером для компиляции текущего документа (в версии Ш4+ это свойство называется charset). Все возможные значения этого свойства можно найти по адресу: ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets В каждом браузере и операционной системе существует собственный набор символов, установленный по умолчанию. Так же значения могут устанавливаться в дескрипторе <meta>. Пример Экспериментировать со свойством characterSet в приложении The Evaluator у вас получится только после загрузки его в браузере NN6+/Mozl+. Введите в верхнем текстовом поле следующее выражение, чтобы ознакомиться с набором символов в текущем документе. document.charset См. также: свойство charset. Глава 18. Объекты document и body 545
compatMode Значение: строковое Только чтение Совместимость: Winffi6+, MacIE6+, NN7+, Mozl+, Safaril+ Это свойство переводит документ в режим совместимости, что определяется содержимым элемента doctype. Свойство CompatMode принимает одно из следующих значений: BackCotnpat и CSSlCompat. Первое значение используется по умолчанию. Пример Вы можете использовать режим совместимости для выполнения специфических для одного браузера операций в другом браузере. Чтобы обеспечить обратную совместимость документа, используйте такое выражение. if (document.compatMode == "BackCompat") { // операторы, выполняемые в режиме обратной совместимости } cookie Значение: строковое Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ В Web-браузере механизм cookie-значений позволяет хранить небольшие объемы информации о компьютере клиента в довольно безопасной форме. Другими словами, если необходимо получить определенную информацию о клиенте во время загрузки различных HTML- документов (причем эта информация должна использоваться между сеансами запуска браузера), используют механизм cookie. Как правило, cookie применяется для хранения имени пользователя и пароля, который он вводит в соответствующее поле Web-узла, защищенного паролем. При первичном вводе данной информации в CGI-форму, используя Netscape Navigator, программа CGI производит запись информации в файлы cookie, сохраняемые на жестком диске пользователя (обычно после шифрования пароля). В следующий раз, когда пользователь решит перейти на тот же узел, ему не нужно будет опять вводить свои данные. Сервер найдет cookie-файл, сохраненный именно для этого сервера, и извлечет содержащиеся там регистрационное имя и пароль, которые затем будут введены автоматически. Другие записи cookie сохраняют ссылки пользователя и информацию о предыдущем посещении узла. Ссылки могут включать также стили и размеры шрифта, а при желании пользователя их содержимое будет отображаться внутри набора фреймов. Временное хранение сведений о посещенных ранее документах позволяет вывести на экран выделенные другим цветом изображения рядом с содержимым, которое было изменено со времени последнего посещения пользователем этой страницы, даже если она неоднократно обновлялась (см. главу 54). Перед тем как регистрировать "новые" состояния, возникшие с момента последнего посещения пользователем узла, сценарии "выделяют" новую информацию для пользователя. Файл cookie Некоторые CGI-программы могут как считывать, так и записывать данные на жесткий диск пользователя. Вам необходимо решить, использовать их или нет. Механизм cookie, содержащийся в браузере, не позволяет использовать папки пользователя для всеобщего доступа (или проводить незаконные операции в них). Вместо этого он обеспечивает доступ только к одному определенному текстовому файлу (в NN/Mozilla/Safari) или набору текстовых файлов (в Internet Explorer), которые сохраняются в строго определенном месте жесткого диска пользователя (в зависимости от операционной системы). 546 Часть III. Объекты документ!
Файл cookie представляет собой обычный текстовый файл (но в Netscape Navigator для Macintosh файл MagicCookie не текстовый, поэтому пользователи Macintosh могут открыть его только с помощью специальных приложений). Для того чтобы просмотреть cookie-файл, рекомендуется предварительно сделать копию в другой папке и только после этого его открывать. Любое изменение существующего файла может испортить содержащуюся в нем ценную запись, использование которой предоставляет доступ к регулярно посещаемому данным пользователем узлу. Формат данных cookie в Netscape Navigator и Internet Explorer разный, что зависит от разных методик, которые используются в них для регистрации cookie-записей. В файле Netscape Navigator (после нескольких закомментированных строчек, которые предупреждают 0 недопустимости изменения пользователем файла вручную) приводится текст в виде таблицы. Каждая строка содержит информацию одной записи. На первый взгляд, cookie-файл ничем не отличается от обычной базы данных. В Internet Explorer в cookie-файле сохраняются те же данные, что и в Netscape Navigator, но сами записи представлены в виде списка. Структура этих файлов не имеет особого значения для занесения в них данных, так как оба браузера используют одинаковый синтаксис чтения и записи, применяя свойство document. cookie. /;iщ■ Когда экспериментируют с записями браузера, то нередко возникает соблазн про- ШыШгф смотреть cookie-файл после внесения в него новых данных, cookie-файл не бу- 1 ^х^, ^ содержать недавно записанных данных; так как сохранение проводится на дис- ^ ке только после того, как пользователь покидает браузер; и наоборот, cookie- файл может быть загружен в память браузера только при запуске последнего. Когда браузер работает, пользователь может считывать, записывать и удалять данные из cookie-файла. Но результаты его деятельности останутся в оперативной памяти (для ускорения обработки данных); сохранены они будут после завершения текущего сеанса. cookie-запись Каждая cookie-запись содержит следующие "поля" (не обязательно в таком же порядке). ■ Домен сервера, создавшего запись. ■ Информацию о том, требуется ли пользователю установить безопасное HTTP- соединение для доступа к записям. ■ Путь расположения документов с URL, которым предоставлен доступ к записям. ■ Срок службы записи. ■ Имя записи. ■ Строка, содержащая запись. Заметьте, что записи зависят только от доменов. Другими словами, если запись создается одним доменом, другой домен не сможет1 считать эту запись, используя обычный cookie- формат. Поэтому совершенно безопасно хранить так называемые невосстанавливаемые пароли (пары имя пользователя-пароль, необходимые для доступа к некоторым узлам со свободной регистрацией) в записях. Кроме того, пароли к узлам, хранящиеся в записях, обычно имеют вид зашифрованных строк. Это усложняет доступ к информации, находящейся в cookie-файле, если компьютер оставлен без присмотра. Таким образом, вычислить личный пароль пользователя оказывается довольно трудно. Кстати, cookie-запись имеет срок службы. Поскольку в некоторых браузерах количество записей ограниченно (300 в Netscape Navigator), cookie-файл может за несколько лет переполниться. Поэтому, если во время работы браузера планируется сохранять cookie-запись, автор этой записи должен установить срок ее службы. Браузеры автоматически удаляют "просроченные" записи. Глава 18. Объекты document и body 547
Однако не все записи должны создаваться во время работы браузера. Сценарии, в которых используются временные записи, при работе с Web-узлами имеют сходную структуру. Многие коммерческие узлы создают одну или несколько временных cookie-переменных для дальнейшего занесения в них названий тех товаров, которые пользователь намеревается приобрести. Эти элементы содержатся в виде копии в определенной форме. Но после представления этой формы серверу, данные о клиенте, содержащиеся в ней, не будут иметь никакого определенного значения. Следовательно, если сценарий не определяет дату истечения срока службы записи, браузер продолжает записывать новые cookie в свою кэш-память, не занося их в cookie-файл. Когда пользователь покидает браузер, данные cookie исчезают, как это и предполагалось. Доступ из JavaScript Доступ к записям cookie из JavaScript ограничен заданием cookie (с рядом необязательных параметров) и получением данных cookie (но уже без параметров). Оригинальная объектная модель определяет cookie-записи как свойства документов, но такая формулировка не совсем корректна. При использовании заданного по умолчанию пути для установки cookie (текущая папка документа, при выполнении сценария из которого используется первая cookie-запись) все документы той же папки на том же сервере имеют доступ для записи и чтения к содержащимся там cookie-данным. Преимущество такого расположения состоит в следующем: если есть приложения, представленные несколькими документами, и все они обслуживаются из одной папки, то данные cookie могут использоваться ими совместно. Однако Netscape Navigator и Internet Explorer установили ограничение: 20 cookie-записей для каждого домена; в ШЗ задается еще более строгое ограничение для одной записи (одна пара имя-значение) на домен. Если пользователя не устраивают поставленные условия, то ему необходимо найти другой способ записи cookie-данных (данный способ описан в приложении Decision Helper в главе 55). Сохранение cookie-записей Для записи данных в cookie-файл в JavaScript используется простой оператор, который назначает свойству document. cookie определенное значение. Но форматирование данных является ключевым моментом в осуществлении доступа к записям. Существует определенный синтаксис для переопределения cookie (необязательные элементы заключены в квадратные скобки). document.cookie = "имяСоок!е = ДанныеСоокге [; expires = времяФорматаСМТ] [; path=путь] [; doma i n=имяДомена ] [; secure]" Отдельно изучите каждое свойство. Имя/данные Каждая cookie-запись должна иметь имя и строковое значение (даже если этому значению соответствует пустая строка). Такие пары имя-значение наиболее часто встречаются в HTML, но в соответствующем выражении они используются по отдельности. Например, если пользователь собирается сохранить слово "Фред" в cookie-записи с именем userName, выражение на JavaScript будет иметь такой вид. document.cookie = "userName=Fred"; Если браузер не находит cookie-записи с таким именем в текущем домене, он создает ее автоматически; если запись с таким именем уже существует, браузер просто заменяет ее старые данные новыми. Поиск document. cookie в этом пункте выдает следующую строку. userName=Fred 548 Часть III. Объекты документ
Можно пренебречь другими параметрами cookie-записей, в этом случае браузер использует значения по умолчанию, более подробно этот процесс описан в следующем абзаце. Для создания временных cookie (которые не должны сохраняться после выключения браузера) кроме набора имя-значения, обычно больше ничего не используют. Полный набор такого типа должен быть представлен строкой, не содержащей точек с запятой, просто запятых или символов пробелов. Для того чтобы убрать пробелы между словами, предварительно обработайте значение записи функцией JavaScript escape О, которая переведет пробелы в ASCII-код, равный %20 (примените функцию unescape (), чтобы убедиться в правильности восстановления пробелов в случае возникновения такой необходимости). Нельзя сохранять массив или объект JavaScript в cookie-записи. С помощью метода Array. j oin () преобразуйте массив в строку; используйте String. split () для создания этого массива заново после последнего прочтения полученной cookie-записи. Эти два метода доступны в NN3+, Mozillal+ и Ш4+. Срок службы (хранения) Устанавливаемая дата срока службы записи должна соответствовать значению времени по Гринвичу (Greenwich Mean Time — GMT)) (см. славу 29, повествующую о времени и датах). Чтобы вычислить дату истечения срока службы записи, основанную на сегодняшней дате, используйте объект Date, представленный в JavaScript, следующим образом. var exp = new Date(); var oneYearFromNow = exp.getTime() + (365 * 24 * 60 * 60 * 1000); exp.setTime (oneYearFromNow); Затем преобразуйте дату в принятый строковый формат GMT. document.cookie = "userName=Fred; expires=" + exp.toGMTString(); В cookie-файле срок службы и время хранятся как числовые значения (в секундах), но для их установки необходимо использовать формат времени соответственно GMT. cookie- запись можно удалить прежде, чем истечет срок ее службы — установите для данной записи новый срок, уже прошедший относительно текущего времени и даты. Самый безопасный параметр срока хранения приведен ниже. expires=Thuf Ol-Jan-70 00:00:01 GMT Отсутствие даты срока службы сообщает браузеру о том, что эта cookie-запись является временной. Таким образом, браузер не записывает ее в cookie-файл, а при следующем запуске этого браузера она не будет существовать в его буфере. Путь Для cookie-записей, осуществляемых стороной клиента, наиболее удобно принять путь, заданный по умолчанию (в текущей папке). Конечно, можно создать дополнительную копию cookie в другой папке (для другого домена), таким образом, одни и те же данные будут доступны документу, расположенному в другой области Web-узла (или вообще сети). Домен Для синхронизации cookie-данных с определенным документом (или их группой) браузер определяет домен текущего документа и помещает в cookie-файл записи, соответствующие этому домену. Поэтому, если пользователь собирается просмотреть список всех cookie-данных, содержащихся в свойстве document. cookie, он должен просмотреть все наборы имя-значение, находящиеся в cookie-файле, с именем домена текущего документа. Если пользователь уверен, что документ не будет скопирован на другой сервер в пределах его Глава 18. Объекты document и body 549
домена, он может и не использовать параметр domain при сохранении cookie-записей. Автоматическое определение домена текущего документа и занесение его в cookie-файл производится по умолчанию. Необходимо знать, что в формате представления домена должно содержаться по крайней мере две точки. .mcom.com .hotwired.corn В противном случае нужно записать полный Ш1^адрес домена, включая протокол http: //. SECURE Если при сохранении cookie-записи параметр SECURE отсутствует, подразумевается, что cookie-данные доступны для любого документа или CGI-программы, которая находится в узле пользователя, определяет другой домен и соответствующий ему путь. В процессе создания cookie-записей на стороне клиента при сохранении cookie этот параметр опускается. Получение cookie-данных Данные cookie, используемые в JavaScript, представляют собой одну-единственную строку, которая содержит все наборы имен и данных. Даже при том, что cookie-файл хранит параметры каждой cookie-записи, с помощью JavaScript можно получить только наборы имен и данных. Кроме того, когда две cookie-записи или более (максимум 20) удовлетворяют критериям домена, в JavaScript они будут представлены в одной строке данных, разграниченных точкой с запятой и пробелом. Например, строка document. cookie может выглядеть следующим образом. userName = Fred; password = NikL2sPacU Другими словами, нельзя обращаться к cookie-записям как к объектам. Необходимо анализировать всю cookie-строку, извлекая данные из нужного набора. Если пользователь уверен, что в существующем файле содержится только одна cookie- запись (и к этому домену записи больше добавляться не будут), он может извлечь эту запись, используя ее имя. Например, данные cookie-записи, имя которой состоит из семи символов, можно извлечь, используя следующее выражение. var data = unescape(document.cookie. substring(7,document.cookie.length)); Первый параметр метода substring () включает знак = дня отделения имени от данных. Целесообразно создать функцию общего назначения, которая сможет управлять одной или несколькими cookie-записями. Далее приводится подобная функция, которую используют в сценариях некоторые разработчики. function getCookieData(labelName) { var labelLen = labelName.length; // однократное чтение свойства cookie var cookieData = document.cookie; var cLen = cookieData.length; var i « 0; var cEnd; while (i < cLen) { var j = i + labelLen; if (cookieData.substring(i,j) == labelName) { cEnd = cookieData.indexOf(";",j); if (cEnd == -1) { cEnd = cookieData.length; } return unescape(cookieData.substring(j+1, cEnd)); 550 Часть ///. Объекты документ!
} i++; } return ""; } При обращении к этой функции имя нужной cookie-записи передается как параметр. Функция анализирует полную строку cookie, обрабатывая ее частями (разделенными точкой с запятой). Таким образом, отбрасываются лишние элементы до тех пор, пока не будет найдено имя требуемой cookie-записи. Если у вас возникли затруднения с пониманием данного кода, то обратитесь к набору функций, написанных опытным программистом JavaScript и Web-дизайнером Биллом Дорт- чем (Bill Dortch) из hldaho Design. Созданные им функции обеспечивают универсальный доступ к cookie-записям, которые можно использовать во всех страницах, управляемых cookie. В листинге 18.3 представлены cookie-функции Билла; они содержат различные методы предотвращения ошибок в дате, которые могут появиться в некоторых версиях NN2. Вас может смутить большой объем этого листинга, однако не волнуйтесь: большинство строк — простые комментарии. <html> <head> <title>Cookie Functions</title> </head> <body> <script type="text/javascript"> <!-- начало сценария // // Соо^е_функции — "Night of the Living Cookie" версия (25.07.96) // // Написан: Биллом Дортчем, hldaho Design < bdortch@hidaho.com > // Следующие функции созданы для работы с существующим доменом // Эта версия выполняет более "жесткое" удаление // cookie-записей. Предыдущие версии устанавливали дату истечения // срока службы записи на одну миллисекунду меньше, чем; // текущее время однако, этот метод не работал в Netscape // Navigator2.02 (хотя он работает как в более ранних, так и // в более поздних версиях этого браузера),»так как в // результате его действия появлялись вечно живущие записи- // "призраки", которые никак нельзя было удалить. // Теперь DeleteCookie устанавливает в качестве даты истечения // срока хранения записи самую раннюю дату, пригодную для // использования (первая секунда 1970 года), и на всякий случай // обнуляет ее значение. // Также в этой версии функции DeleteCookie добавлены // необязательные параметры пути и домена. Необходимо указывать // путь и/или домен как при создании, так и при удалении // cookie**, иначе запись не будет удалена. // Функция FixCookieDate должна вызываться только для исправления // ошибок в дате на Мае 2.x. Эта функция должна вызываться *один // раз* после создания объекта Date и перед обращением к // SetCookie. Поскольку ошибка в дате в Мае воздействует на все // даты, а не только на те, которые передаются // в функцию SetCookie, необходимо привыкнуть к тому, что // придется вызывать FixCookieDate при создании каждого Глава 18. Объекты document и body 551
// нового объекта: // // var theDate = new Date О; /■/ FixCookieDate (theDate) ; // // Функция FixCookieDate не работает ни на одной платформе // кроме Мае, поэтому нет необходимости определять платформу // пользователя перед каждым ее вызовом. //В этой версии также проведены некоторые незначительные // усовершенствования. // ** Заметьте, что можно устанавливать несколько записей с одним //и тем же именем, но различными путями. Например: // // SetCookie ("color","red",null."/outer"); // SetCookie ("color","blue",null ."/outer/inner"); // // Однако GetCookie не может различить эти два выражения и // возвращает значение первой найденной записи с данным именем. // Поэтому рекомендуется *не* использовать одинаковые имена // для cookie с разными путями. (Имейте в виду, что у каждой // записи *всегда* есть свой путь; если он полностью не // определен, используется путь, установленный документом.) // // История обновления: // // "Toss Your Cookies" версия (22.03.96) // Добавление функции FixCookieDate() для исправления ошибок. //в дате в Мае // // "Second Helping" версия (21.01.96) // Функция SetCookie() дополнена путем, доменом и параметрами // безопасности // "Самодельные" функции кодирования/декодирования заменены //на новые // функции escape и unescape в Netscape Navigator // // "Free Cookies " версия (декабрь 95) // // За более подробной информацией о значениях cookie параметров // и о cookie пожалуйста, обращайтесь на официальный узел: // http: /./ www.netscape.com/newsref/std/cookie_spec.html // *•*********++***•*********************•**•*******•***** // // "Внутренняя" функция для возвращения декодированного значения // function getCookieVal (offset) { var endstr = document.cookie.indexOf (";", offset); if (endstr == -1) endstr = document.cookie.length; return unescape(document.cookie.substringtoffset, endstr)); } // // Эта функция необходима для исправления ошибок в дате на // Мае 2.x. Вызывайте ее для проверки объекта даты перед // отправкой данных в функцию SetCookie. // ВНИМАНИЕ: Эта функция должна вызываться только *один раз* // для каждого полученного объекта даты! // См. пример в конце листинга. 552 Часть III. Объекты документа
// function FixCookieDate (date) { var base = new Date(0); var skew = base.getTime(); // отсчет времени (Unix) должен начинаться с О if (skew > 0) // везде кроме Mac date.setTime (date.getTime() — skew); } // // Функция предназначена для возвращения значения cookie, // используя параметр "name". // name — строковый объект, содержащий имя cookie. // returns — строковый объект, v содержащий значение cookie либо О, // если таковая запись не существует // function Get Cookie (name) { var arg = name + "="; var alen = arg.length,• var clen = document.cookie.length; var i = 0; while (i < clen) { var j = i + alen; if (document.cookie.substring(i, j) == arg) return getCookieVal (j); i = document.cookie.indexOf(" ", 1) + 1; if (i ==0) break; } return null; } // // Функция для создания или обновления cookie. // name — строковый объект, содержащий имя cookie. // value — строковый объект, содержащий значение cookie. // Может содержать любой действительный строковый символ. // [expires] — объект Date, содержащий срок службы cookie. // Если таковое отсутствует, удаляет cookie после завершения // сеанса работы браузера. // [path] — строковый объект, указывающий путь нужной cookie // записи. Если он не указан либо имеет нулевое значение, // использует путь вызванного документа. // [domen] — строковый объект, указывающий домен нужной // cookie-записи. Если он не указан или имеет нулевое значение, // используется домен вызванного документа. // [secure] — булево значение (true / false), определяет // необходимость использования безопасного соединения (HTTPS) // Первые два параметра необходимы. Остальные, если указаны, // то должны быть переданы в порядке, описанном выше. Для того // чтобы зарезервировать поле, не используемое в данный момент, // определите его как нулевое. Например, код для вызова функции // SetCookie с заданными именем, значением и путем, имеет // следующий вид: //SetCookie ("myCookieName", "myCookieValue", null, "/"); // // Заметьте, что перемещение опущенных параметров не требует // метки—заполнителя. Чтобы установить безопасный cookie в // "/myPath", срок службы которого заканчивается после // текущего сеанса, необходимо использовать выражение: // Глава 18. Объекты document и body 553
// SetCookie (myCookieVar, cookieValueVar, null, "/myPath", null, true); // function SetCookie (name,value,expires,path,domain,secure) { document.cookie = name + "-" + escape (value) + ((expires) ? "; expires=+ expires.toGMTString() : "") + ((path) ? "; path=" + path : "") + ((domain) ? "; domain'" + domain : "") + ((secure) ? "; secure" : ""); } // Функция для удаления cookie. (Устанавливает дату истечения // срока службы записи в начало) // name — строковый объект, содержащий имя cookie. // path — строковый объект, содержащий путь cookie-записи, // которая впоследствии будет удалена. Это должен быть тот же // путь, который использовался при создании cookie, или нулевое // значение, если при создании записи путь не был определен. // domen — строковый объект, который содержит домен cookie, // предназначенный для удаления. Это должен быть тот же домен, // который использовался для создания cookie, или нулевое // значение, если при создании записи домен не был определен. function DeleteCookie (name,path,domain) { if (GetCookie(name)) { document.cookie = name + " = " + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, Ol-Jan-70 00:00:01 GMT"; // Примеры: // var expdate = new Date () ; FixCookieDate(expdate); // Исправляет ошибки в дате Mac, // используется только один раз для каждого объекта Date! expdate.setTime (expdate.getTime() + (24 * 60 * 60 * 1000)); // 24 от текущего времени SetCookie ("ccpath", "http://www.hidaho.coin/colorcenter/", expdate); SetCookie ("ccname", "hidaho Design ColorCenter", expdate); SetCookie ("tempvar","Это временная cookie."); SetCookie ("ubiquitous","Эта cookie будет работать в любом месте данного домена",nul1/"/"); SetCookie ("paranoid","Эта cookie обеспечивает безопасное соединение",expdate,"/",null,true); SetCookie ("goner","Эта cookie должна быть удалена!"); document.write (document.cookie + "<br>"); DeleteCookie ("goner"); document.write (document.cookie + "<br>"); document.write ("ccpath = " + GetCookie("ccpath") + "<br>"); document.write ("ccname — " + GetCookie("ccname") + "<br>"); document.write ("tempvar = " + GetCookie("tempvar") + "<br>"); // конец сценария --> </script> </body> </html> 554 Часть III. Объекты документа
Дополнительные пакеты Можно создать узел, для которого потребуется более чем 20 cookie на соответствующий домен. Например, никогда не известно, сколько элементов может загрузить покупатель в потребительскую корзину, находясь на коммерческом узле. Так как каждая cookie-запись сохраняет данные в виде обычного текста, можно создать собственные текстовые структуры данных для последующего размещения в них записей, состоящих из нескольких частей. (Но не следует забывать о практическом пределе: 2 000 символов на пару имя-значение в пределах максимума (4 000 символов для каждой объединенной cookie-записи домена).) Таким образом определяется символ-разделитель, который не используется ни в одной из cookie-записей. Например, в приложении Decision Helper (глава 55) для разделения нескольких целых чисел, сохраненных в cookie, используется точка. В случае применения установленного символа-разделителя необходимо написать функции для сбора этих подчиненных "cookie" в одну строку, и наоборот, разделения ее на отдельные записи. Такой путь более длинный, но он обеспечивает постоянство сведений о клиенте. Пример Поэкспериментируйте с последней группой операторов в листинге 18.3 для создания, получения и удаления cookie-записей. Кроме того, вы можете активно пользоваться возможностями приложения The Evaluator (устанавливая пары имя/значение и используя в дальнейшем свойство cookie). См. также: методы строковых объектов. defaultCharset Значение: Строковое Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство defaultCharset содержит набор символов, по умолчанию используемый браузером для обработки текущего документа. Возможные значения этого свойства можно найти по адресу. ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets Каждый браузер и операционная система имеют собственный, заданный по умолчанию, набор символов. Эти значения также могут устанавливаться с помощью дескриптора <meta>. Различие между свойствами defaultCharset и charset окончательно не установлено, так как оба они предназначены для чтения/записи (изменение свойства defaultCharset не имеет никакого визуального эффекта на странице). Однако, если в сценарии временно изменяется свойство charset, для восстановления оригинального набора символов можно использовать свойство defaultCharset. document.charset = document.defaultCharset; Пример Приложение The Evaluator позволяет работать и со свойством defaultCharset. Чтобы ознакомиться с настройками по умолчанию, введите в верхнем поле следующее выражение, document.charset = document.defaultCharset; См. также: свойства charset, characterSet. Глава 18. Объекты document и body 555
defaultview Значение: строковое Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Свойство def aultview возвращает ссылку на объект, выступающий в роли *4просмотрщи- ка" документа (он отвечает за визуализацию документа). В NN6+ свойство def aultview возвращает объект window или frame, содержащий документ. В W3C DOM Level 2 это свойство предоставляет доступ к вычисляемым значениям CSS, примененным к любому HTML- элементу (с помощью метода document .def aultView.getComputedStyle О или, в более простом случае, с помощью метода window. getComputedStyle ()). См. также: свойства window и frame; метод window. getComputedStyle (). designMode Значение: строковое Чтение/Запись Совместимость: Winffi5+, MacIE-, NN7.1, Mozl.4, Safari- Свойство designMode используется только тогда, когда средства Ш5+ выступают в качестве компонента другого приложения. Это свойство указывает, будет ли модуль браузера использоваться для редактирования HTML-кода. Изменение свойства на типичной странице HTML в браузере Ш5+ не будет иметь никаких результатов. В Mozilla свойство можно применять для включения и отключения объекта document элемента if rame. Только для чтения doctype Значение: ссылка на объект DocumentType Совместимость: Winffi-, Macffi5+, NN6+, Mozl+, Safari- Свойство doc type позаимствовано из W3C DOM. С его помощью возвращается объект DocumentType — формат представления данных документов, представленный DTD. Объект DocumentType (даже если он явно не определен в исходном тексте) является первым дочерним узлом корневого узла документа (следовательно, его можно считать "потомком" HTML-элемента). В W3C DOM, как и в NN6, всего несколько свойств действительно пригодны для непосредственного использования. В табл. 18.2 представлен список типичных свойств объекта DocumentType и значений для создаваемой HTML-страницы. В новой версии DOM эти свойства будут доступны для чтения и записи. Свойство Значение entities internalSubset name notations publicid systemid null (нет) html null -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtmll/DTD/xhtml1-transitional.dtd См. также: дочерний объект (глава 14). 556 Часть III. Объекты документ»
document Element Значение: ссылка на элемент HTML или XML-объекта Только для чтения Совместимость: WinIE5+, МасШ5+, NN6+, Mozl+, Safari 1+ Свойство document Element возвращает ссылку на объект HTML-элемента (или XML- элемента), который представляет содержимое всего текущего документа. Данное имя не совсем точно соответствует действительности, так как узел корневого документа не является элементом, его единственный дочерний узел — это элемент html (или xml). В лучшем случае можно считать, что это свойство как бы присуждает звание "элемента" объекту document и узлу документа, который связан с текущей страницей, загруженной в браузере. Пример Используйте приложение The Evaluator для детального изучения свойства document- Element. В браузере IE5+/W3C введите в текстовое поле следующее выражение. .document. document Element. tagName Возвращаемый результат — HTML. См. также: свойство ownerDocument (глава 15). domain Значение: строковое Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Ограничения системы безопасности могут помешать нормальной работе сценария, если узел имеет более одного сервера в своем домене. Так как некоторые объекты, особенно объект location, не разрешают доступ к свойствам других серверов, загруженных в другие фреймы, законный доступ к их свойствам оказывается заблокированным. Например, довольно часто узлы общего доступа располагаются на сервере с именем, подобным www. popular. com. Если страница на этом сервере оснащена поисковым интерфейсом search. popular. com, то пользователь, в браузере которого установлена подобная защита, получает отказ в доступе. Для того чтобы обойти подобную защиту, можно запустить сценарии в документах обоих серверов, таким образом, оба сервера будут восприниматься браузером как одинаковые. В предыдущем примере требовалось установить в свойстве document. domain значение popular. com для обоих документов. Если данное свойство не установлено пользователем, то по умолчанию его значение содержит имя текущего сервера, что порождает несоответствие между именами. Прежде, чем "подделывать" другие сервера, сначала убедитесь в том, что сможете задать свойство document. domain для документа на серверах, относящихся к одному домену. Таким образом, для документов, расположенных только на ххх. popular. com, можно установить свойства document. domain равными именам других серверов, См. также: метод window. open (); объект window. location; безопасность (глава 46). embeds Значение: массив объектов элемента embed Только для чтения Совместимость: Winffi5+, ЦасШ5+, NN6+, Mozl+, Safari 1+ Всегда, когда необходимо загрузить данные, требующие надстройки (внедряемого модуля)— приложения для их воспроизведения либо вывода на экран, используют дескриптор <embed>. Свойство document. embeds — это единственный способ определения таких дескрипторов, добавленных в документ. var count = document.embeds.length; Глава 18. Объекты document и body SS7
Для управления надстройками в Netscape Navigator можно использовать технологию LiveConnect, описанную в главе 44. См, также: элемент embed (глава 40). expando Значение: булево Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Microsoft называет любое обычное свойство, которое не является "родным" для объекта document, расширяемым. По умолчанию в последних версиях браузеров в большинство объектов с помощью сценария можно добавить новые свойства (как способ временного хранения данных без явного определения глобальных переменных). Например, если нужен счетчик, который содержал бы количество вызовов определенной функции, можно создать пользовательское свойство объекта document и использовать его как средство хранения, document.counter = 0; ГЕ4+ позволяет управлять способностью объекта document к хранению расширенных свойств. По умолчанию значение свойства document. expando равно true. Это позволяет использовать расширенные свойства объекта. Но дело в том, что на стадии разработки страницы расширенное свойство, содержащее ошибки, может быть названо именем уже существующего стандартного свойства; оно будет принято объектом document "без всяких подозрений". В результате может получиться так, что пользователь не поймет, почему строка заголовка окна браузера не изменяется при установке свойству document.Title (которое в чувствительном к регистру JavaScript отличается от свойства document .title) нового значения. Пример Вы можете использовать приложение The Evaluator (глава 13) для изучения свойства expando в ГЕ4+. Сначала удостоверьтесь, что объект document может управлять пользовательскими свойствами. Введите в верхнее текстовое поле следующее выражение. document.spooky = "Boo!" Это свойство добавляется в документ и поддерживается в нем до выгрузки или перезагрузки документа. Заблокируйте возможность управления в документе пользовательскими свойствами. document.expando = false Если вы попытаетесь добавить новое свойство, то получите извещение об ошибке. document.happy = "tra la" Несмотря на отключение свойства document. expando исходно добавленное пользовательское свойство остается доступным для использования. См. также: свойство prototype пользовательских объектов (глава 33). fgColor См. alinkColor. fileCreatedDate fileModifiedDate fileSize Значение: строковое, целочисленное (fileSize) Только для чтения Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- 558 Часть III. Объекты документа
Эти три свойства, предназначенные для работы только в Internet Explorer, возвращают информацию о файле, который содержит текущий документ. Два из них определяют даты создания и изменения файла текущего документа. Для неизмененного файла эти даты остаются прежними. Свойство f ileSize отображает объем документа в байтах. Значения даты, возвращаемые в первых двух свойствах, отформатированы по-разному в Ш4 и Ш5. Функции предоставляют полную информацию о текущей дате, которая содержится в формате mm/dd/yyyy. Однако заметьте, что значения содержат только дату, а не время. Это значение всегда можно использовать как параметр для вызова конструктора new Date (). Значение даты пригодиться вам, например, при расчете периода времени, прошедшего с дня последнего изменения документа. Не все серверы могут определить предыдущую дату или размер файла, а если и могут, то не всегда в том формате, который поддерживается в Internet Explorer. Проверьте выполнение этой операции на сервере, чтобы убедиться в совместимости данных. Необходимо также знать, что эти свойства доступны только для чтения файла, загруженного в браузер в данный момент. Средствами языка JavaScript нельзя получить эту информацию о файле, находящемся на сервере, но не загруженном в браузер. Ш5.5+ представляет на рассмотрение разработчиков свойство с именем f ileUpdatedDate, но оно не возвращает никаких значений. Это "фантомное" свойство, возможно, осталось от предыдущей версии браузера. Пример Код листинга 18.4 динамически генерирует несколько фрагментов, указывающих на дату создания и изменения файла, а также извещающих о его размере. Что более важно, этот код демонстрирует, как преобразовать возвращаемое значение даты в объект даты, который можно использовать в вычислениях. В листинге 18.4 исчисление ведется в виде целых дней между датой создания и датой просмотра. Обратите внимание на то, что динамически - сгенерированное содержимое добавляется в документ с помощью свойства inner Text и размещается в элементах span. <html> <head> <title>fileCreatedDate and fileModifiedDate Properties</title> <script type="text/javascript"> function filllnBlanksO { •var created = document.fileCreatedDate; var modified = document.fileModifiedDate; document.getElementByld("created").innerText = created; document.getElementByld("modified").innerText = modified; var createdDate = new Date(created).getTime(); var today = new Date().getTime(); var diff = Math.floor((today - createdDate) / (1000*60*60*24)); document.getElementById("diff").innerText = diff; document.getElementByld("size").innerText » document.fileSize; } </script> </head> <body onload="fillInBlanks()"> <hl>fileCreatedDate and fileModifiedDate Properties</hl> Глава 18. Объекты document и body 559
<hr /> <p>This file (<span id=lfsizen>&nbsp;</span> bytes) was created on <span id="created">&nbsp;</span> and most recently modified on <span id="modified">&nbsp;</span>.</p> <p>It has been <span id-"diff">&nbsp;</span> days since this file was created.</p> </body> </html> См. также: свойство lastModif ied. forms [] Значение: массив Только для чтения Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Как было показано в главе 21, посвященной объекту form, форма HTML (содержится в паре дескрипторов <form>. . . </form>) представляет собой объект JavaScript, находящийся сам в себе. Можно создать ссылку на форму согласно ее имени (назначенному в атрибуте name). Например, если в документе содержится следующее определение формы. < form name = "phoneData" > определение элементов управления </form>, то в сценарии для обращения к этому объекту формы может использоваться указанное имя. document.phoneData Однако с помощью объекта document к данной форме можно обратиться и другим способом: как к массиву объектов form. Первым элементом массива document. forms является первая форма, загруженная в данный документ (она приведена в самом начале HTML-кода). Если документ определяет одну форму, свойство форм представляет собой массив, состоящий из одного элемента; в случае определения трех отдельных форм — массив из трех элементов. Используйте стандартную структуру массивов для получения доступа к определенным формам из массива document. forms. Например, первая форма документа ("нулевой" элемент в массиве document. forms) вызывается так. document.forms[0] Свойство или метод объектов форм становятся доступны, если добавить к этому выражению имя нужного свойства или метода. Например, для определения значения текстового поля с именем home Phone второй формы документа используется ссылка, которая задается следующим образом. document.forms[1].homePhone.value В использовании свойства document. forms для обращения к объектам форм или элементов, заменяющих фактическое имя формы, есть одно большое преимущество. Речь идет о возможности создания библиотеки генерируемых сценариев, с помощью которых можно в цикле получить доступ ко всем формам в документе и выбрать ту, для которой определено необходимое свойство. Следующий фрагмент сценария (часть цикла, более подробно Описанного в главе 31) использует переменную-счетчик (i) для просмотра всех форм, содержащихся в документе. for (var i = 0; i < document.forms.length; i++) { if (document.forms[i]. ... ) { операторы 560 Часть III. Объекты документа
Бще один вид ссылок на элементы формы представляет замену именем формы (строковое значение) индекса массива forms. Например, форма с именем phoneData может быть вызвана так. document.forms ["phoneData"] При назначении имен объектам рекомендуется использовать следующий способ задания ссылок на формь*: document. FormName. В этой книге описан как индексированный, так и именованный массив ссылок на формы. Преимущество применения именованных ссылок состоит в том, что даже при изменении страницы и порядка размещения форм в документе ссылки на имена этих форм остаются и будут действительны, в то время как индексы форм часто изменяются. В главе 21 описаны объекты форм и способ передачи их в функцию. Пример Документ, представленный листингом 18.5, настраивает и отображает диалоговое окно предупреждения, которое имитирует подключение к музыкальному Web-узлу, основываясь на состоянии флажка. В данном случае пользователь вводит данные на двух формах: одна содержит флажок, а вторая кнопку. В середине страницы находится простой заполнитель, который в реальных документах заменяют конечными данными. Щелчок на нижней кнопке (вторая форма) вызывает функцию, которая получает состояние флажка, используя выражение document. forms [i] как часть адреса. <html> <head> <title>document.forms example</title> ocript type="text/javascript"> function goMusicO { if (document.forms[0].bluish.checked) { alert("Now going to the Blues music area..."); } else { ' alert("Now going to Rock music area..."); </script> </head> <body> <form name="theBlues"> <input type="checkbox" name="bluish" />Check here if you've got the blues. </form> <hr /> M<br /> o<br /> r<br /> e<br /> <br /> C<br /> o<br /> p<br /> y<br /> <hr /> <form name="visit"> <input type="button" value="Visit music site" Глава 18. Объекты document и body 561
onclick="goMusic()" /> </form> s </body> </html> См. также: объект form (глава 21). frames [] Значение: массив Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Свойство document.frames подобно свойству window, frames. Иногда такая схожесть вызывает путаницу. Объекты, которые содержатся в массиве, возвращенном из этого свойства, являются объектами окна любых элементов frame (в документе, состоящем из нескольких фреймов) или элементов if rame (в простом документе HTML). Различие между объектами окна и объектами элементов существует; его очень важно понимать. Объекты окна имеют различные свойства и методы, в отличие от элементов frame и if rame. Обычно свойства последних определяют атрибуты дескрипторов этих элементов. Если документ не содержит элементов if rame, массив frames имеет нулевую длину. Можно обращаться к определенному объекту фрейма, используя синтаксис, привычный для массива (например document .frames [0]), а можно использовать дополнительный синтаксис, предусмотренный Microsoft для управления набором объектов. Индекс элемента массива можно поместить в круглые скобки, как в данном примере. document. frames (О) Более того, если фреймы имеют значения, назначенные в атрибутах name, их можно использовать (в строковой форме) как параметр или индекс. document.f rames("content s") Но будьте внимательны в ситуации, когда в наборе встречаются фреймы с одинаковыми именами. При использовании такого же имени, как и у параметра, ссылка возвращает несколько объектов фреймов, имеющих одно имя. Можно ограничить количество таких возвращаемых объектов, определив необязательный второй параметр, указывающий индекс. нужного объекта. Например, если документ имеет два элемента i frame с именем contents, сценарий может обратиться ко второму объекту window так. document.frames("contents", 1) Для обеспечения совместимости с другими браузерами рекомендуется вызвать объекты фреймов с помощью свойства window, frames. Пример В листингах 16.7 и 16.8 приведен пример использования свойства frames. Этот пример выполняется в Ш4+, если вы начинаете ссылку на свойство с window или document. См. также: свойство window. frames. height width Значение: целочисленное Только для чтения Совместимость: Winffi-, МасГЕ-, NN4+, Mozl+, Safari 1+ Свойства height и width объекта document в NN4+ определяют в пикселях размер текущего окна или фрейма. Если площадь документа имеет размер меньше, чем область браузера, 562 Часть ///. Объекты документе
размеры, возвращенные этим свойством, учитывают и пустое пространство в правой и/или нижней части окна. Но если площадь документа превышает видимые границы окна браузера, размеры задают и неотображаемое пространство. Соответствующие свойства в ГЕ4+ — document. body. scrollHeight и document. body. scrollWidth. Пример Используйте приложение The Evaluator для изучения свойств height и width. Введите в верхнее текстовое поле следующее выражение. "height=" + document.height + "; width=" + document.width Измените размер окна таким образом, чтобы видеть вертикальную и горизонтальную полосы прокрутки. Щелкните на кнопке Evaluate еще раз. Если оба одно число стало меньше, то значения в области вывода результатов определяют область, занимаемую документом. Если же вы расширите окно так, что в нем не будут отображаться полосы прокрутки, то значения будут указывать реальный размер окна. См. также: свойства document. body. scrollHeight, document. body. scrollWidth. ide[] Значение: массив Только для чтения Совместимость: WinlE-, MacIE-, NN4, Moz-, Safari- Свойство ids используется только в NN4 и в качестве альтернативы, основанной на синтаксисе таблицы стилей браузера. Таблицы стилей в JavaScript используются чрезвычайно редко. В некоторых случаях свойство document. ids работает подобно свойству document .all вШ4+, но document. ids не может использоваться в регулярных сценариях получающих доступ к объектам элементов. См. также: свойство tags. images [] Значение: массив Только для чтения Совместимость: WinIE4+, МасШЗ+, NN3+, Mozl+, Safaril-i- Изображения, обрабатываемые как объекты особой важности во всех браузерах, начиная с NN3 и Г£4, будут представлены в документе как массив дескрипторов всех изображений, указанных на странице (аналогично анкерам и ссылками). Основное преимущество в хранении изображений как объектов состоит в простоте изменения их содержимого (исходный файл, содержащий параметры изображения). Более подробно объект изображения описан в главе 20. Для точного определения текущего изображения используйте массив ссылок на изображения. Тогда можно задавать любое его свойство или назначить новые файлы изображений в его свойстве src. В массивах изображений нумерация элементов начинается с 0: первое изображение в документе определяется по ссылке document. images [0]. Аналогично любому объекту массива, можно определить количество изображений, содержащихся в данном массиве, с помощью свойства length. var imageCount = document.images.length; Изображения также могут иметь названия, поэтому в случае необходимости вы вправе обратиться к объекту изображения, используя его имя var ImageLoaded = document. имяИзображения.complete; или var ImageLoaded « document.images[имяИзображения].complete; Глава 18. Объекты document и body 563
Массив document. images применяется для определения расположения в документе новых изображений. Любой браузер, который обрабатывает элемент img как объект, всегда формирует массив document. images для данной страницы. Если на странице не найдено ни одного изображения, массив все равно существует, но с количеством элементов, равным нулю. Его существование указывает на совместимость объекта изображения с объектной моделью браузера. Так как document. images описывает массив объектов (если таковые поддерживаются), выражение может использоваться как условие для перехода к операторам, с помощью которых изменяются изображения, i f (document.images){ // Замена или предварительная загрузка изображения ) Более ранние версии браузеров, которые не имеют этого свойства, устанавливают значение document. images как undefined (неопределенное), и, таким образом, условие получает значение false. Пример Свойство document. images назначается автоматически при создании браузером объектной модели в документах, которые содержат изображения. См. также: объект Image (глава 20). implementation Значение: объект Только для чтения Совместимость: Winffi6+, МасШ5+, NN6+, Mozl+, Safari 1+ В базовой модели W3C DOM используется свойство document. implementation для нахождения сценарием средств (или элементов), которые поддерживаются в текущей среде. Объект, возвращенный данным свойством (объект DOMImplementation), не имеет никаких свойств, но поддерживает метод has Feature (), который позволяет сценариям определять, например, что именно поддерживает данная среда — HTML или только XML. Первым параметром метода hasFeature() является средство, представленное в виде строки. Второй параметр — это строковое представление номера версии. Метод возвращает булево значение. В разделе спецификации W3C DOM, называемом Conformance, приведены имена модулей (стандарт также позволяет проверить с помощью метода has Feature () средства, поддерживаемые в браузере). Имена модулей, как правило, содержат сочетания слов HTML, XML, MouseEvents и т.д. Нумерация версий модулей W3C DOM соответствует уровням W3C DOM. Таким образом, модуль XML DOM 2.0 соответствует DOM 2.0. Обратите внимание, что версии представлены для ЕЮМ-модулей, а не для отдельных стандартов (например HTML). Пример Приложение The Evaluator подойдет и для всестороннего изучения метода document. imple- mentation.hasFeature (). Введите следующие выражения поочередно в верхнее текстовое поле. document.implementation.hasFeature("HTML","1.0") document.implementation.hasFeature("HTML","2.0") document.implementation.hasFeature("HTML","3.0") document.implementation.hasFeature("CSS","2.0") document.implementation.hasFeature("CSS2","2.0") He бойтесь вводить другие значения параметров. 564 Часть III. Объекты документа
lastModified Значение: строковая дата Только для чтения Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Каждый файл на диске имеет изменяемый временный файл, и большинство серверов (но не все) настроены на то, чтобы считывать его информацию в браузере при обращении к файлу. Эта информация доступна для получения из,свойства document. lastModified. Если клиент получает подобную информацию от сервера, можно использовать значение этого свойства для предоставления данной информации посетителям Web-страниц. Сценарий автоматически обновит значение, вместо того чтобы предлагать пользователю сделать это вручную (и так каждый раз при изменении HTML-документа). Если появившееся на экране возвращенное значение представляет собой дату 1969 года, это означает, что пользователь находится западнее Гринвичского меридиана (некоторые часовые пояса, находящиеся западнее GMT, попадают в зону, где дата определяется как 1 января 1970). Исходя из этого, серверы не смогут обеспечить определение соответствующих данных при обслуживании этих файлов. Иногда конфигурация сервера может вызвать сбой, но это встречается редко. Возвращенное значение не является объектом даты (глава 29); это, скорее, строка, представляющая время и дату, сохраненные в файле документа. Формат строки изменяется в зависимости от браузеров и их версий. Но всегда можно конвертировать эту строку в объект даты JavaScript и использовать соответствующие методы для извлечения определенных элементов и преобразования их в формат, пригодный для чтения. Даже локальные файловые системы не всегда обеспечивают корректную интерпретацию данных для каждого браузера. Но тот же самый файл, помещенный в UNIX или Windows Web-сервер, имеет правильную дату изменения, если получить к нему доступ из локальной сети. Пример В листинге 18.6 представлен пример использования этого свойства. Приготовьтесь к тому, что при тестировании файлов, расположенных на локальном жестком диске, у вас могут возникнуть проблемы. <html> <head> <title>Time Stamper</title> </head> <body> <center> <hl>GiantCo Home Page</hl> </center> <script type="text/javascript"> update = new Date(document.lastModified); theMonth = update.getMonth() + 1; theDate = update.getDate(); theYear « update.getFullYear(); document.writeln("<I>Last updated:" + theMonth + "/" + theDate + "/" + theYear + "<\/I>"); </script> <hr /> </body> </html> Глава 18. Объекты document и body 565
При описании объекта Date будьте готовы к тому, что в каждой стране поддерживается свой формат даты (см. главу 29). Зачастую в этих форматах используется непривычный порядок следования, элементов. Вам обязательно необходимо учесть этот факт в собственных документах. См. также: объект Date (глава 29). layers [] Значение: массив Только для чтения Совместимость: Winffi-, Macffi-, NN4, Moz-, Safari- Объект слоя (глава 39)— это средство, использующееся только в NN4 для представления в объектной модели позиционируемых элементов. Таким образом, свойство document. layers — это массив слоев, расположенных в документе. По причине того, что NN4 использует нестандартный способ представления позиционируемых элементов, не каждый из подобных элементов содержится в массиве document. layers. Вложенные элементы должны определяться с помощью иерархической структуры слоев. Объект слоя и свойство document. layers остались только в NN4; необходимость в них со временем исчезает, поскольку число пользователей NN4 уменьшается. Поэтому следующие комментарии будут полезны только для тех, кто вынужден поддерживать позиционируемые элементы в NN4. В NN6 слой представлен любым элементом HTML, таблицы стилей которого включают атрибут position. Ссылки на подобные элементы задаются с помощью метода document. getElementByld () либо комбинаций, описанных в главе 14. В Netscape Navigator слой — это контейнер содержимого, которое нужно точно разместить на странице. Слои определяются в дескрипторе < layer >, который используется только в NN4 (или в \¥ЗС-синтаксисе стандартной таблицы стилей для позиционируемых элементов, которые описаны в главе 39). Каждый слой содержит объект document, хранящий содержимое данного слоя. Слои могут быть вложенными, но с помощью ссылки document. layers можно обратиться только к первому уровню слоев, определенному в документе. Ниже приведена соответствующая структура HTML-кода. <html> <body> <layer name="Europe"> <layer name="Germany"></layer> <layer name="Netherlands"X/layer> </layer> </body> </html> С точки зрения исходного документа, в данном случае используется только один слой (Europe). Поэтому длина массива document. layers равна 1. Но слой Europe содержит документ с еще двумя вложенными уровнями. Ссылка на массив этих вложенных слоев имеет вид document.layers[1].document.layers или document.Europe.document.layers Длина вложенного массива равна двум: Germany и Netherlands. He существует ни одного свойства, которое бы определяло полный набор вложенных массивов в документе. Но можно создать цикл for, чтобы перемещаться по всем вложенным слоям (как показано в листинге 18.7). / НшшящЩ. 566 Часть III. Объекты документа
Пример Листинг 18.7 содержит пример использования свойства layers для просмотра всех слоев документа, который отображается в NN4. С помощью функции crawl Layers () сценарий создает список слоев в такой же иерархической последовательности, как у объектов докумен* та, и выводит результат в диалоговом окне. После загрузки страницы сравните выводимый результат со структурой дескрипторов <1ауег> документа. <html> <head> <titlex/title> <script type="text/javascript"> var output = ""; function crawlLayers(layerArray, indent) { for (var i = 0; i < layerArray.length; i++) { output += indent + layerArray[i].name + "\n"; if (layerArray[i].document.layers.length) { var newLayerArray = layerArray[i].document.layers; crawlLayers(newLayerArray, indent + " H); return output; function revealLayers() { alert(crawlLayers(document.layers, "")); } </script> </head> <body onload="revealLayers() " > <layer name="Europe"> <1ayer name-"Germanyи> </layer> <layer name="Netherlands'^ <layer name="Amsterdam"></layer> <layer name="Rotterdam"></layer> </layer> <1ayer name="France"> </layer> </layer> <layer name="Africa"> <layer name="South Africa"> </layer> <layer name="Ivory Coast"> </layer> </layer> </body> </html> См. также: объект слоя (глава 39). linkColor См. alinkColor. ' Глава 18. Объекты document и body 567
links [] Значение: массив Только для чтения Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Свойство document .links подобно свойству document. anchors; его отличие состоит в том, что объекты, содержащиеся в массиве, являются объектами ссылок — элементами, созданными с помощью дескриптора <а href="M>. Используйте массив ссылок для точного определения нужной ссылки и задания любого ее свойства (подобно тому, как в HTML указывается целевое окно). В массивах ссылок нумерация элементов начинается с 0: первая ссылка в документе — document. images [0]. Аналогично любому объекту массива, можно определить количество ссылок, содержащихся в данном массиве, используя свойство length. var linkCount = document.links.length; Элементы, представленные свойством document. links, являются полноценными объектами location. Пример Свойство links назначается автоматически при создании браузером объектной модели документа. Это свойство используется очень редко; исключение составляют сценарии, в которых подсчитывается количество ссылок в документе. См. также: объект ссылок; свойство document. anchors. location URL Значение: строковое Чтение/Запись и Только для чтения Совместимость: Winffi3+, МасШЗ+, NN3+, Mozl+, Safari 1+ Суть этих методов заключается в том, что JavaScript часто использует одни и те же термины в различных контекстных ситуациях (это может запутать начинающего пользователя). Например, существует свойство document. location. Просто поразительно, как это свойство отличается от объекта location (глава 17). На практике во многих сценариях возникают ошибки, если в ссылках не указан объект window. В результате, в NN3 и ЕЕ4 появилось новое свойство document. URL вместо document .location. Конечно, можно использовать и document. location, но тогда из словаря объектной модели могут исчезнуть некоторые ключевые слова. Поэтому далее будет описываться свойство document. URL. Теперь вернемся к исходному вопросу: какая разница между объектом window, location и свойством document. URL? Ответ: разница в соответствующих им типах данных. Объект location, как уже отмечалось в главе 17, состоит из целого ряда свойств документа, в данный момент загруженного в окно или фрейм. Назначение нового URL-адреса объекту location (или свойству location.href) дает команду браузеру загрузить страницу, соответствующую полученному URL-адресу, во фрейм. С другой стороны, свойство document. URL является просто строкой (в Netscape Navigator только для чтения), в которой отображен URL-адрес текущего документа. Ее значение может быть важно для сценария, но это свойство не имеет "объектной природы" window, location. Нельзя изменить данное значение свойства (указав новое), так как документ имеет только один URL-адрес, определяющий расположение в сети (или на жестком диске локального компьютера) данного файла, и протокол, требуемый для его получения. 568 Часть III. Объекты документа
Именно в этом и состоит основное отличие вышеуказанного объекта от свойства. Используемое обращение (объект window, location или свойство document.URL) зависит от действий, которые пользователь собирается выполнить в соответствии со сценарием. Если при выполнении сценария необходимо изменить содержимое окна (загружается документ с новым URL), то пользователю ничего не остается, как использовать объект window.location. Аналогично, если в сценарии требуются составляющие части URL- адреса, то наиболее простой способ получить эту информацию — воспользоваться свойством document. URL. Для восстановления URL-адреса документа в строковой форме (независимо от того, находится этот документ в текущем окне или в другом фрейме), можно использовать как свойство document. URL, так и window. location. href. Пример HTML-документы листингов 18.8-18.10 представляют собой приложение тестирования свойства location, URL в многофреймовой среде. Результаты выводятся в виде таблицы, в которой также содержится список свойств document .title, чтобы документы было проще идентифицировать. <html> <head> <title>document.URL Reader</title> </head> <frameset rows="60%,40% "> <frame name="Framel" src="lstl8-10.htm" /> <frame name="Frame2" src="lstl8-09.htm" /> </frameset> </html> <html>• <head> <title>URL Property Reader</title> <script type="text/javascript"> function fillTopFrame() { newURL=prompt("Enter the URL of a document to show in the top frame:",""); if (newURL 1= null ScSc newURL != "") { top.frames[0].location = newURL; } } function showLoc(form,item) { var windName = item.value; var theRef = windName + ".document"; form.dLoc.value = unescape(eval(theRef + ".URL")); form.dTitle.value = unescape(eval(theRef + ".title")); } </script> </head> <body> Глава 18. Объекты document и body 569
Click the "Open URL" button to enter the location of an HTML document to display in the upper frame of this window. <form> <input type="button11 name="opener" value="Open URL..." onclick="fillTopFrame()" /> </form> <hr /.> <form> Select a window or frame to view each document property values. <p><input type="radio" name="whichFrame" value="parent" onclick="showLoc(this.form,this)" />Parent window <input type="radio" name="whichFrame" value="top.frames[0]" onclick="showLoc(this.form,this)" />Upper frame <input type="radio" name="whichFrame" value="top.frames[1]" onelick="showLoc(this.form,this)" />This frame</p> <table border="2"> <tr> <td align="RIGHT">document.URL:</td> <tdxtextarea name="dLoc" rows="3" cols="30" wrap="soft"> </textarea></td> </tr> <tr> <td align="RIGHT">document.title:</td> <tdxtextarea name="dTitle" rows="3" cols="30" wrap="soft"> </textareax/td> </tr> </table> </form> </body> </html> <html> <head> <title>Opening Placeholder</title> </head> <body> Initial place holder. Experiment with other URLs for this frame (see below). </body> </html> См. также: объект location; свойства location.href, URLUnencoded. media Значение: строковое Чтение/Запись Совместимость: Winffi5.5+, MacIE-, NN-, Moz-, Safari- 570 Часть III. Объекты документа
В ГЕ5.5 свойство document. media может принимать одно-единственное значение (по умолчанию): print. Это свойство везде описывается довольно поверхностно, но определенно можно сказать следующее: оно используется в сценарии для задания эквивалента правилу CSS 2 ©media (одно из так называемых правил "at", в честь символа @). Это правило таблицы стилей позволяет браузерам назначать отдельные стили для каждого типа устройства вывода, на котором представлена страница (например, возможны отличия в шрифтах на принтере и мониторе). Однако на практике это свойство в ГЕ5.5 не поддается изменению. mimeType Значение: строковое Только для чтения Совместимость: WinIE5+, МасГЕ-, NN-, Moz-, Safari- Данное свойство действительно применяется в Ш5+, однако его значение не соответствует типу MIME, точнее, его традиционному формату. Кроме того, в браузерах IE5 и ГЕ5.5 получаемые результаты совершенно разные. Возможно, это свойство более часто используется в XML, чем в HTML. В любом случае, такой способ никоим образом не позволяет открывать в текущем браузере документы MIME-типа. nameProp Значение: строковое Только для чтения Совместимость: Winffi6+, Macffi-, NN-, Moz-, Safari- Это свойство возвращает строку, которая содержит заголовок документа, равный значению свойства document. title. Если документ не имеет заголовка, то свойство nameProp содержит пустую строку. namespaces [] Значение: массив объектов namespaces Только для чтения Совместимость: Winffi5.5+, Macffi-, NN-, Moz-, Safari- Объект namespace (недавно появился в ГЕ5.5) может динамически импортировать основанное на XML поведение элемента Ш. Свойство namespaces возвращает массив всех объектов namespace, определенных в текущем документе. parentWindow Значение: ссылка на объект window Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Свойство document .parentWindow возвращает ссылку на объект window, который содержит текущий документ. Возвращается такое же значение, какое имеет ссылка на текущее окно. Пример Чтобы доказать, что свойство parentWindow указывает на окно документа, введите следующее выражение в верхнее поле приложения The Evaluator. document.parentWindow == self Это выражение возвращает значение true только в случае равенства двух ссылок. См. также: объект window. Глава 18. Объекты document и body 571
plugins [] Значение: массив Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ Свойство document. plugins возвращает тот же массив элементов embed, который можно получить с помощью свойства document. embeds. Но его практически не используют, в отличие от document. embeds. См. также: свойство document. embeds. protocol Значение: строковое Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Свойство document. protocol используется только в Internet Explorer и определяет •версию протокола, с помощью которой и осуществлялся доступ к текущему документу. Например, если за файлом обращаются на Web-сервер, то возвращается свойство Hypertext Transfer Protocol. Данное свойство отличается от location.protocol, так как последнее возвращает только часть URL-адреса, содержащую наиболее часто встречающуюся аббревиатуру протокола (например http:). Как правило, разработчик скрывает эти данные от пользователя приложения в Web. Пример Если вы будете использовать приложение The Evaluator для изучения свойства protocol, то обнаружите, что оно возвращает значение File Protocol, поскольку вы получаете доступ к программному коду, расположенному на жестком или компакт-диске. См. также: свойство location.protocol. referrer Значение: строковое Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Когда пользователь с помощью ссылки, находящейся в одном документе, попадает в другой документ, то в этом втором документе, используя JavaScript, можно определить URL-адрес первого документа, содержащего ссылку на него. Свойство document. referrer содержит строку с этим URL-адресом. Такая возможность может пригодиться для настройки содержимого страниц, основанного на предыдущем посещенном пользователем документе. Свойство содержит значение, только когда пользователь попадает на текущую страницу с помощью ссылки. Любой другой способ перемещения (например, с помощью списка посещенных страниц, закладки или ручного введения URL-адреса) устанавливает в этом свойстве пустую строку. / Свойство document. referrer обычно возвращает пустую строку, если файлы /наздютку получены не с Web-сервера. Более того, ранние версии WinlE никогда корректно I ^0^' не определяли это свойство. Пример Этот пример состоит из двух документов (в случае использования Ш вам необходимо открыть документы с Web-сервера). Первый документ (листинг 18.11) содержит простую текстовую ссылку на другой документ. Сценарий второго документа (листинг 18.12) проверяет, из какой страницы пользователь перешел к текущей, а затем отображает соответствующее сообщение. Откройте второй документ в новом окне браузера с помощью команды Open File (Открыть) и убедитесь, что свойство referrer в данном случае будет не определено. 572 Часть III. Объекты документа
<html> <head> <title>document.referrer Property l</title> </head> <body> <hlxa href="lstl8-12.htm">Visit my sister document</ax/hl> </body> </html> <html> <head> <title>document.referrer Property 2</title> </head> <body> <hl> <script type="text/javascriptf,> alert(document.referrer.length + " : " + document.referrer); if(document.referrer.length > 0 && document.referrer. indexOf("lstl8-ll.htm") != -1){ document.write("How is my brother document?"); } else { document.write("Hello, and thank you for stopping by."); } </script> </hl> </body> </html> См. также: объект ссылки. scripts [] Значение: массив Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Свойство document. scripts возвращает массив всех элементов script, содержащихся в текущем документе. К отдельному объекту элемента script можно обратиться не только для чтения свойств, совместно используемых всеми элементами HTML (глава 15), но и для определения таких свойств сценариев, как def er, src и html For. Фактическое создание сценария выполняется с помощью innerText и text для любого объекта элемента script. В отличие от массива document. scripts, который предназначен только для чтения, многие свойства отдельных объектов элементов script поддаются изменению. Добавление или удаление элементов script приводит к изменению длины массива document. scripts. Если в сценарии требуется получить доступ к определенному элементу script, то ему можно назначить атрибут id, и уже с его помощью обратиться к данному элементу. Глава 18. Объекты document и body 573
Описываемое свойство предназначено для использования только в Internet; оно является более удобным, чем выражение document .getElementsByTagName ("script") в Ш4+ и NN6, которое возвращает массив таких же объектов. Пример Вы можете экспериментировать со свойством scripts в приложении The Evaluator. Если ввести в верхнее поле следующее выражение, то можно узнать, что страница приложения содержит только сценарий. document.scripts.length Для ознакомления со свойствами объекта script введите в нижнее поле такой оператор. document.scripts[0] В числе его свойств вы найдете innetText и text. Если установить в качестве значения одного из них пустую строку, то сценарий будет удален из объектной модели, но не из памяти браузера. Сценарий не исчезает, хотя в объектной модели он представлен не будет. Если ввести следующее выражение в верхнее поле document.scripts[0].text = "" то содержимое сценария будет удалено из объектной модели, хотя использование кнопок Evaluate и List Properties в дальнейшем приведет к возвращению результатов. См. также: элемент script (глава 36). security Значение: строковое Только для чтения Совместимость: Winlp5.5+, MacIE-, NN-, Moz-, Safari- Свойство security представляет информацию о типе защиты, если таковая применяется в текущем документе. selection Значение: объект Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство document. selection возвращает объект selection, содержимое которого отображается в окне браузера как выделение основного текста. Это выделение может осуществляться пользователем (по щелчку и перемещению указателя вдоль текста) или с помощью сценария в объекте TextRange, поддерживаемом в WinlE (см. главу 35). Так как выделение в сценарии (например, нахождение следующего фрагмента выделенного текста) выполняется с помощью объекта TextRange, то полученный текстовый фрагмент необходимо преобразовать в этот объект, используя метод document .selection.createRange (). Более подробно объект selection описан в главе 35. Учтите, что невозможно написать сценарий управления текстового выделения с помощью элементов пользовательского интерфейса (например кнопок). Щелчок на кнопке снимает выделение. Используйте другие события (такие как document. onmouseup) для выполнения действия по отношению к выделенному фрагменту. Пример Пример использования свойства selection приведен в листингах 15.30 и 15.39 (только для Ш). См. также: объекты selection, TextRange. 574 Часть III. Объекты документ*)
stylesheets [] Значение: массив Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Массив document. stylesheets состоит из ссылок на все элементы style, присутствующие в документе. Правда, к ним не относятся таблицы стилей, назначенные элементам с помощью атрибута style дескрипторов или связанные с помощью элементов link (см. главу 26). См. также: объект stylesheet (глава 26). tags[] Значение: массив Только для чтения Совместимость: Winffi-, МасШ-, NN4, Moz-, Safari- Свойство tags используется только в NN4 в альтернативном синтаксисе таблиц стилей, основанных на JavaScript. Таблицы стилей JavaScript применяются редко. В некоторых случаях свойство document. tags работает подобно методу document. getElementsByTagName () в W3C, но document. tags не может использоваться в обычных сценариях для обращения к объектам элементов. См. также: свойство ids. title Значение: строковое Только для чтения и Чтение/Запись Совместимость: Winffi3+, МасЕЕЗ+, NN2+, Mozl+, Safaril+ Заголовок документа— это текст, который находится между парой дескрипторов <title>. . . </title> в разделе Head документа HTML. Обычно он появляется в строке заголовка однофреймового окна браузера. В многофреймовом окне браузер выводит только заголовок самого верхнего документа. Даже в этом случае для отдельного документа, находящегося в пределах фрейма, свойство title доступно в сценарии. Например, если доступны два фрейма (UpperFrame и LowerFrame) в сценарии документа, занимающего LowerFrame, можно обратиться к свойству title документа другого фрейма. parent.UpperFrame.document.title Это свойство предназначено только для чтения во всех более ранних версиях браузеров, чем Ш4 и NN6. Свойство document.title— это "пережиток** первоначальной объектной модели документа. В последних версиях браузеров HTML элементы по-разному применяют свойство title (см. главу 15). В Ш4+ и NN6 заголовок документа задается непосредственно с помощью элемента title. См. также: объект history. URL См. location. URLUnencoded Значение: строковое Только для чтения Совместимость: WinIE5.5+, МасШ-, NN-, Moz-, Safari- Свойство document. URL возвращает строку URL-адреса в виде кода. Это означает, что все небуквенные и цифровые символы в URL преобразованы в символы, соответствующие ШЫ|дресу (например, пробел будет выглядеть как %20). Можно, конечно, применить функцию Глава 18. Объекты document ы body 575
unescapeO к значению, которое возвращает свойство document.URL, но зачем делать это вручную, если свойство URLUnencoded само выполняет эту операцию. Если в URL- адресе нет закодированных символов, то оба свойства возвращают одинаковые значения. См. также: свойство document. URL. vlinkColor См. linkColor. width См. height. Методы captureEvents (списокСобытнй) Возвращаемое значение: отсутствует Совместимость: Winffi-, МасШ-, NN4+, Moz-, Safari- Только в NN4 естественная обработка события начинается с объекта window (через объект document) и уже после этого достигает своей цели. Например, если щелкнугь на кнопке, событие щелчка сначала поступит в объект window; затем перейдет к объекту document; если кнопка определена в пределах слоя, событие также пройдет через этот слой; в конечном счете (в доли секунды) событие достигнет кнопки, и обработчик события onclick произведет действие, соответствующее щелчку. Структура объектной модели NN4 позволяет объектам window, document и объектам слоев перехватывать события и обрабатывать их самим (или не допускать их возникновения). Но внешнему контейнеру для перехвата события необходим соответствующий сценарий, содержащий инструкции по перехвату определенного типа события (дня предварительной обработки его в приложении). Если возникла необходимость в перехвате всех событий определенного типа объектом document, используйте метод document. captureEvents () для осуществления данной возможности. # Перехват события с различным синтаксисом был стандартизирован в W3C DOM /назаштф и осуществлен в NN6. В главе 15 описан метод addEventListener () для W3C ' J**0*' и метод captureEvents () для NN4. В главе 25 также речь идет о средствах перехвата события, работающих в W3C DOM. В методе document. captureEvents () указывается один или несколько типов события в качестве параметров. Тип события — это постоянное значение, которое хранится в объекте Event, поддерживаемом NN4. Существует тип события, который подходит для любого обработчика событий (его можно встретить в объектах document (NN4)). Синтаксис перехвата представлен ссылкой на объект Event и именем события заглавными буквами. Например, при перехвате объектом document всех событий click выражение имеет такой вид. document.captureEvents (Event.CLICK); Для нескольких событий их указывают как параметры, разделенные символом (|). document.captureEvents(Event.MOUSEDOWN | Event.KEYPRESS); После установки объекта document на перехват определенного типа события нужно определить функцию для его обработки. Например, пусть функция просматривает все события Event. MOUSEDOWN и следит за тем, действительно ли правая кнопка мыши вызывает событие, 576 Часть III. Объекты документа
и какой элемент формы (если таковой существует) соответствует назначенной цели. Целью, например, может быть вызов меню по щелчку правой кнопкой мыши (на отдельном слое). Если щелчок сделан левой кнопкой мыши, то происходит стандартная реакция на это событие. Для того чтобы связать функцию с определенным типом события, перехваченного объектом document, назначьте ее этому событию. Например, чтобы назначить пользовательскую функцию doClickEvent () событиям click, захваченным объектом document, используйте следующее выражение. document.onClick=doClickEvent; Заметьте, что имя функции указано только как имя ссылки, в отличие от обработчика событий, находящегося в дескрипторе. Данная функция подобна любой другой, если не учитывать того, что она имеет дополнительную возможность автоматического получения объекта события как параметра. Чтобы отменить перехват события для одного или нескольких типов события, используйте метод document iReleaseEvent (). Более подробно вопрос управления событиями NN4 освещен в главе 25. Перехват событий объектами уровня window и document в NN4 не всегда происходит так, как это запланировано. Это случается особенно часто, если в странице содержатся таблицы. Например, перехват события мыши не дает никакого результата в NN4 для Windows, если указатель не находится над границей ячейки. Наиболее надежно захват события работает, когда объекту в сценарии соответствует определенный обработчик событий (даже если обработчик — просто пустая строка), а элемент является целью события (например, при вводе данных в текстовое поле). Для всех других элементов захват события не может быть проведен непосредственно на уровне window или document. Изучите пример из листинга 16.21 для ознакомления с методом captureEvents (). В нем представлены ссылки на объекты window как ссылки на объекты document. Если вы поняли особенности механизма для объектов окон, то без труда сможете изучить механизм захвата событий для документов. Подобное справедливо для всех остальных методов управления событиями в NN4. См. также: методы document. handleEvent (), document. releaseEvents (), document. routeEvent (); параллельные методы событий объекта window. clear() Возвращаемое значение: отсутствует Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ В любой версии, начиная с NN2, метод document. clear () предназначен для очистки текущего документа из окна браузера. Этот метод непрактичен, так как обычно требуется, чтобы после очистки документа выполнялся следующий сценарий. Если сценария нет, то, соответственно, ничего и не происходит. На практике метод document. clear () непредсказуем (и в более ранних версиях браузера это приводит к ошибкам). Вместо использования document .clear () рекомендуется сгенерировать новую страницу с помощью метода document. write (), который очищает оригинальный документ в окне перед добавлением в него нового содержимого. Если нужно действительно очистить окно или фрейм, то используйте document .write (), чтобы создать пустой HTML-документ или загрузить его с сервера. См. также: методы document. close (), document, write (), document. writeln (). / HtMftMTxy Пример Глава 18. Объекты document и body 577
Указатель в состоянии "ожидания' Иногда браузеры не могут восстановить нормальное состояние указателя после выполнения методов document, write () и document .close О (и некоторых других сценариев, изменяющих содержимое окна браузера). Указатель упрямо остается в состоянии "ожидания", при том что обработка соответствующих данных давно завершилась. Существует один, хоть и нестандартный, способ, который поможет в данной ситуации. Метод document, close О дополнительно вызывается в конструкции javascript тсевдо-хть (простое добавление еще одного метода document. close () в сценарий ни к чему не приведет). Чтобы использовать этот способ в наборе фреймов, javascript: url должен соответствовать вершине иерархии набора фреймов, в то время как document. close () выполняется по отношению к фрейму, содержимое которого изменено. Например, если был изменен фрейм с именем content, создайте функцию следующего вида. function recloseDocO { top.location.href = "javascript:void (parent.content.document.close 0)"; Если функция recloseDoc () запускается в многофреймовом документе, то в тех сценариях, в которых производится изменение содержимого фрейма, можно вызвать эту функцию после любого действия, которое препятствует нормальной работе указателя. close О Возвращаемое значение: отсутствует Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Если рабочий поток был открыт в окне с помощью метода document. open () или любого другого метода для записи документа (выполняющего эту же функцию), его следует закрыть после создания документа. В ответ на эти действия в строке состояния появятся сообщения Layout: Complete и Done (хотя на некоторых платформах могут возникнуть ошибки при их отображении). Процесс закрытия документа очень важен для подготовки окна к последующей загрузке новой HTML-страницы, содержащей сценарий. Если документ не закрыт, следующая запись дописывается в нижней части основного документа. Некоторые или даже все данные, предназначенные для отображения в окне, не будут представлены должным образом, если не применить метод document. close О, особенно если изображения должны выводиться как часть потока документа. Основной признак подобного поведения — это мгновенное появление, а затем исчезновение частей документа. Если подобное происходит на экране, то это значит, что после последнего вызова метода document. write () не был выполнен метод document. close (). Пример Перед использованием метода close () внимательно изучите метод document. write (), описанный далее в этой главе. После этого создайте в разных папках три отдельных документа для исследования метода close () (листинги 18.16-18.18). В функции takePulse () закомментируйте оператор с методом document. close (). msg += "<p>Make it a great day!</body></html>"; parent.frames[1].document.write(msg); //parent.frames[1].document.close(); Отобразите страницу в браузере. Как вы видите, при каждом щелчке на верхней кнопке в верхний фрейм добавляется текст, при этом исходный текст из фрейма не удаляется. Причина состоит в том, что не закрыт предыдущий процесс. Браузер считает, что вы все еще работаете 578 Часть III. Объекты документа
с ним. Если вы не воспользуетесь свойством close О, то в последней текстовой строке может не отобразиться добавленный недавно текст. См. также: методы document. open (), document. close (), document. write О , document. writeln (). createAt tribute (" имяАтрибута") Возвращаемое значение: ссылка на объект атрибута Совместимость: Winffi6+, МасШ5+, NN6+, Mozl+, Safari 1+ Метод document.createAttribute генерирует объект атрибута (формально известный как объект Attr в терминологии W3C DOM) и возвращает ссылку на последний. При вызове метода указывается только имя атрибута, таким образом, в сценарии назначается значение свойству node Value (этого объекта), а затем новый атрибут добавляется в существующий элемент с помощью метода setAttributeNode () (описанный в главе 15). Следующий код генерирует атрибут, который становится принадлежным к элементу table. var newAttr = document. createAttribute("width"); newAttr.nodeValue = "80%"; document.getElementByld("myTable").setAttributeNode(newAttr); Атрибуты не всегда должны соответствовать HTML-стандарту, так как метод применим и для XML-элементов, атрибуты которых задаются пользователем. Пример Для создания атрибута и исследования его свойств в верхнее поле приложения The Evaluator введите следующее выражение. а = document.createAttribute("author") Далее используйте нижнее текстовое поле для отображения списка свойств объекта Attr. См. также: метод setAttributeNode () (глава 15). createComment ("текстКомментария") ' Возвращаемое значение: ссылка на объект комментария Совместимость: Winffi6+, MacIE5+, NN6+, Mozl+, Safari 1+ Этот метод создает экземпляр узла комментария. После создания узел будет находиться в памяти браузера; он потребует вставки в документ с помощью метода appendChildO или infcertBef ore (). createDocumentFragment () Возвращаемое значение: ссылка на фрагмент документа Совместимость: WinIE6+, Macffi5+, NN6+, Mozl+, Safaril+ Данный метод создает экземпляр узла пустого фрагмента документа. Этот узел представляет собой контейнер, в который добавляются Другие узлы документа. После создания и вставки в него всех необходимых узлов сам узел фрагмента документа можно будет вставить в объектную модель документа. Узел фрагмента документа особенно эффективен в случаях, когда требуется пополнить документ последовательностью новых элементов или текстовых узлов. Выступая в качестве родительского элемента, он сможет предложить все необходимые для управления другими узлами средства (например, метод appendChildO). Если узел фрагмента документа вставить в объектную модель документа, то в последнюю будут встроены только содержащиеся в нем элементы, но не он сам. Глава 18. Объекты document и body 579
createElement (" имяДескрилтора") Возвращаемое значение: ссылка на объект элемента Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Метод document. createElement () генерирует объект элемента для любого дескриптора HTML (или XML), указанного в качестве параметра. Этот объект официально не является частью объектной модели текущего документа, так как в состав документа он пока еще не входит. Однако данный метод используется для вызова объекта элемента, который в конечном счете будет помещен в документ. Возвращаемое значение — ссылка на объект. К свойствам этого объекта относят все атрибуты (значения которых установлены по умолчанию), определенные объектной моделью браузера для данного элемента. Таким образом, из сценария можно обращаться к объекту с помощью этой ссылки для задания его свойств. Обычно это осуществляется перед вставкой объекта в документ, иначе свойства, предназначенные только для чтения, могут быть изменены прежде, чем элемент будет вставлен в документ. После выполнения операции вставки первоначальная ссылка (например, глобальная переменная, используемая для хранения значения, возвращенного с помощью метода createElement ()) все еще будет указывать на объект, даже если он находится в документе и просматривается пользователем. В следующем примере создается простой элемент абзаца, содержащий некоторый текст. van newText = document.createTextNode("Four score and seven years ago..."); var newElem = document.createElement("p"); newElem.id = "newestP"; newElem.appendChild(newText); document.body.appendChild(newElem); Суть метода состоит в том, что новый абзац является видимым в документе. Чтобы изменить, например, стиль абзаца, обратитесь либо к элементу объектной модели document, либо к переменной, которая содержит ссылку на созданный объект newElem.style.fontSize = "2Opt"; или следующим образом document.GetElementByldC'newestP").style.FontSize = "2Opt"; Эти две ссылки неразрывно связаны между собой и указывают на один и тот же объект. Поэтому, если нужно использовать сценарий для того, чтобы сгенерировать серию подобных элементов (например, несколько LI элементов), можно воспользоваться методом createElement () для создания первого элемента и установки всех свойств, ему присущих. После этого с помощью cloneNode () создайте новую копию, а уже ее представьте как отдельный элемент (назначьте ей собственный идентификатор). При написании сценария в среде W3C DOM (в рамках моделей, поддерживаемых IE5 и NN6) можно использовать document. createElement () для обновления содержимого страницы или ее части (если, конечно, вы не предпочитаете свойство innerHTML для добавления содержимого в виде строк HTML). В строгой среде W3C DOM создание новых элементов — это не способ вставки HTML-кода, а, скорее, создание подлинного объекта элемента (и текста). Пример В главе 15 приводились многочисленные примеры использования метода createElement () (см. листинги 15.10, 15.21, 15.22, 15,28 и 15.31). См. также: метод document. createTextNode (). 580 Часть III. Объекты документа
createEvent (" типСобытия") Возвращаемое значение: ссылка на объект события Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safaril+ Этот метод создает в W3C DOM экземпляр объекта Event указанного типа. После создания объект события относится к одной из категорий событий. В соответствии с указанным типом объект приобретает набор свойств. После назначения свойств событие можно вызвать, воспользовавшись методом dispatchEvent (). В NN6+/Moz распознаются следующие типы событий: Key Event s, MouseEvents, MutationEvents и UIEvents. Процесс инициализации события каждого типа требует использования различных параметров в методе initEvent () (см. главу 25). Пример Следующий пример демонстрирует методы создания события, его инициализации к требуемому типу и отправки в указанный объект. var evt = document.createEvent("MouseEvents"); evt. initEvent ("mouseup" , true, true); document.getElementById("myButton").dispatchEvent(evt); См. также: метод createEventObj ect (); объекты Event в W3C DOM (глава 25). createEventObject([объектСобытия) ] Возвращаемое значение: объект события Совместимость: WinIE5.5, МасШ-, NN-, Moz-, Safari- Метод createEventObject О используется только в Internet Explorer; он создает объект event, который можно применять как параметр в любом объекте элемента в методе f ireEvent (). Объект event, который создан этим событием, применяется подобно объекту event, созданному пользователем или системой. Необязательный параметр позволяет добавить в данный объект новое событие. Другими словами, свойства только что созданного объекта event аналогичны свойствам объекта, подставленного в качестве параметра. По мере необходимости эти свойства можно изменять. Если параметры в методе не указываются, то нужно задать их вручную (более подробно свойства объекта event описаны в главе 25). Пример Обратитесь к описанию метода f ireEvents () в главе 15, чтобы детальнее ознакомиться с использованием createEventObj ect () на практике. См. также: метод f ireEvent () (глава 15); объект event (глава 25). createRange([" URL" [, индекс] ] ) Возвращаемое значение: ссылка на объект Range Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Этот метод создает пустой объект Range (W3C DOM), который имеет точечный размер и располагается перед первым символом тела документа. См. также: объект Range. Глава 18. Объекты document и body 581
createStyleSheet([" URL" [, индекс] ]) Возвращаемое значение: ссылка на объект stylesheet Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Метод createStyleSheet () используется (только в Internet Explorer) для создания объекта stylesheet. Он включает в себя объекты элементов style аналогично таблицам стилей, которые импортируются в документ с помощью элемента link. Таким образом можно динамически загрузить внешнюю таблицу стилей даже после загрузки самой страницы. Обратите внимание на то, что этот метод не работает в МасШ4. В отличие от других методов "создания", используемых в W3C DOM, метод createStyleSheet () не только создает таблицу стилей, но и вставляет объект в объектную модель документа. Таким образом, любые правила таблиц стилей, установленные для данного объекта, сразу же вступают в силу. Если таблица стилей создается отдельно и отдельно подключается, то для выполнения первой задачи используется метод createElement (), а для второй — метод внедрения элемента в объектную модель. Если параметры не передаются в метод, создается пустой объект таблицы стилей. Подразумевается, что впоследствии будут использоваться методы объекта stylesheet, например, addRule () (не поддерживаемые в МасШ5), для добавления в таблицу стилей детальных характеристик. Чтобы связать таблицы стилей во внешнем файле, в первом параметре метода назначают URL-адрес этого файла. Вновь созданная таблица стилей добавляется в качестве последнего элемента массива document .Stylesheets объекта stylesheet. Второй параметр — необязательный, но он позволяет точно определить расположение в наборе элементов новой вставленной таблицы стилей. Установки таблиц стилей для любого элемента переписываются при подключении в документ новой таблицы стилей для этого же элемента. Пример В листинге 18.13 приведен пример использования метода createStyleSheet О для создания внешней и внутренней таблицы стилей в документе. Для внутренней таблицы стилей этот метод вызывается в функции addStylel (). Созданная таблица стилей включается в элементы р страницы (не используются в МасШ5). Функция addStylel () управляет внешней таблицей стилей. Она состоит из следующих двух правил. h2 {font-size:2Opt; color:blue} p {color:blue} Обратите внимание, что в такой структуре внутренний стиль доминирует над внешним. За исключением случаев использования только внешнего стиля, красный цвет элементов р всегда будет подавлять синий цвет внешнего стиля. Если удалить второй аргумент метода в функции addStyle2 (), то внешний стиль будет добавляться в конец списка таблиц стилей. В результате доминировать будет синий цвет. Щелкая на кнопках этого документа, вы будете изменять порядок применения стилей на странице. <html> <head> <title>document.createStyleSheet() Method</title> <script type="text/javascript"> function addStylel() { var newStyle = document.createStyleSheet(); newStyle.addRuleC'P", "font-size:16pt; color:red"); } 582 Часть III. Объекты документа
function addStyle2() { var newStyle = document.createStyleSheet("1st18-13.ess",0); } </script> </head> <body> <hl>document.createStyleSheet() Method</hi> <hr /> <form> <input type="button" value="Add Internal" onclick="addStylel()" />&nbsp; <input type="button" value="Add External" onclick="addStyle2()" /> </form> <h2>Section l</h2> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat,</p> <h2>Section 2</h2> <p>Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseruntmollit anim id est laborum.</p> </body> </html> См. также: объект stylesheet (глава 26). createTextNode (" текст") Возвращаемое значение: текстовый объект Совместимость: WinIE5+, Macffi5+, NN6+, Mozl+, Safari 1+ Текстовый узел — это объект W3C DOM, который содержит основной текст, не принадлежащий ни одному дескриптору HTML (или XML). Обычно он находится в элементе HTML (или XML) (как дочерний элемент). В отличие от Internet Explorer, в котором существует специальное свойство inner Text для изменения текста элемента, W3C DOM полагается на иерархию узлов документа (NN6 опередил W3C DOM, поддержав свойство innerHTML). Чтобы вставить или заменить текст внутри элемента HTML, по аналогии с W3C DOM создается текстовый узел, а затем для изменения содержимого документа используются методы родительского элемента (например, appendChild (), insertBef ore () и replaceChild (), описанные в главе 15). Для того чтобы сгенерировать новый текстовый узел, используйте метод document.createTextNode(). Единственным параметром createTextNode () является строка, содержимое которой становится значением свойства node Value объекта текстового узла, возвращаемого данным методом. Также можно создать пустой текстовый узел (содержащий пустую строку) и назначить строку в качестве значения nodeValue. Можно изменить свойство nodeValue в сценарии, тем самым изменив и текст существующего элемента, но только при условии, что текстовый узел находится в документе (более подробно о роли текстовых узлов в W3C DOM рассказывается в главе 14). Глава 18. Объекты document и body 583
Пример В главах 14 и 15 (например, в листинге 15.21) уделено должное внимание методу create- TextNode (). Приложение The Evaluator также поможет вам разобраться в его возможностях. Вы можете использовать в этом приложении встроенные глобальные переменные для сохранения ссылок на только что созданные текстовые узлы. Для этого введите в верхнее текстовое поле следующее выражение. а = document.createTextNode("Hello") В области результатов будет указано, что данная операция приводит к созданию объекта. Изучим свойства полученного объекта, воспользовавшись нижним текстовым полем. В списке свойств содержатся элементы, поддерживаемые в ГЕ5+ и W3C DOM. Последние свойства указывают, что нами создан объект третьего типа с именем #text. Он пока не имеет родительских, дочерних и сестринских объектов, поскольку не включен в иерархическую структуру документа. Чтобы научится вставлять текстовый узел в объектную модель документа (абзац туР), введите в верхнее текстовое поле следующий оператор. document.getElementByld("myP").appendChild(a) Теперь в конце простого абзаца в нижней части страницы появится слово Hello. Вы можете изменить текст узла по своему усмотрению, воспользовавшись ссылкой на узел в иерар^ хической структуре или глобальной переменной, назначенной ранее. document .getElementByld ("myP") . last Chi Id. node Value = "Howdy11 или a.nodeValue = "Howdy" См. также: метод document. createElement (). createTreeWalker(корневойУзел, фильтр, filterFunction, entryRefExpansion) Возвращаемое значение: ссылка на объект TreeWalker Совместимость: Winffi-, MacIE-, NN7+, Mozl.4+, Safari- Этот метод создает экземпляр объекта TreeWalker, который используется для навигации по дереву объектов документа. Первый аргумент этого метода указывает узел, используемый в документе в качестве корневого. Второй аргумент — это целочисленная константа, задающая один из встроенных фильтров. Ниже приведен список допустимых значений этого аргумента. NodeFilter.SHOW_ALL NodeFilter.SHOW_ATTRIBUTE NodeFilter.SHOW_CDATA_SECTION NodeFilter.SHOW_COMMENT NodeFilter.SHOW_DOCUMENT NodeFilter.SHOW_DOCUMENT_FRAGMENT NodeFilter.SHOW_DOCUMENT_TYPE NodeFilter.SHOW_ELEMENT NodeFilter.SHOW_ENTITY NodeFilter.SHOW_ENTITY_REFERENCE NodeFilter. SHOW_NOTATION NodeFilter. SHOW_PROCESSING_INSTRUCTI0N NodeFilter.SHOW_TEXT Третий аргумент представляет ссылку на функцию фильтра, которая анализирует узлы детальнее, чем позволяет сам фильтр (заданный во втором параметре). Эта функция принимает в качестве аргумента всего один узел и возвращает целочисленное значение, основанное на следующих константах: NodeFilter.FILTER_ACCEPT, NodeFilter.FILTER_REJECT или NodeFilter. FILTER_SKIP. Идея функции заключается в анализе каждого узла и возвращении значения, указывающего на необходимость включения или исключения его из дерева объектов документа. Эта функция не просматривает циклически все узлы. Объект TreeWalker устроен так, что функция вызывается необходимое количество раз тогда, когда требуется проанализировать характеристику, по которой будет проводиться фильтрация. 584 Часть III. Объекты документа
Последний аргумент этого метода принимает булево значение и указывает, необходимо ли рассматривать в качестве иерархической структуры содержимое ссылки. Этот параметр используется исключительно в XML-документах. elementFromPoint (x, у) Возвращаемое значение: ссылка на элемент текстового узла Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Метод elementFromPoint () используется только в Internet Explorer. Он возвращает ссылку на любой объект элемента, находящегося в точке, целочисленные координаты которой определены в методе как параметры. Координатная плоскость в документе начинается с левого верхнего угла в точке (0,0). Эта плоскость может применяться в интерактивных проектах, в которых выполняется проверка на пересечение позиционируемых объектов и управление поведением указателя мыши. Когда в одной точке оказывается несколько объектов (например, один элемент находится над другим), возвращается элемент с самым высоким значением z-индекса (уровнем расположения). Позиционируемый элемент всегда "выигрывает", если он помещается над обычным элементом тела документа. Если несколько накладывающихся друг на друга позиционируемых элементов имеют одинаковое значение z-индекса (или не имеют его вообще по умолчанию), значения координат последнего поступившего в исходный код элемента возвращаются и используются как общие значения. Пример В коде листинга 18.14 приведено большое количество элементов самых разных типов. Каждый из них имеет атрибут id. Обработчик onmouseover объекта document вызывает функцию, которая определяет, над каким объектом располагается указатель при возникновении события. Обратите внимание на то, что координаты события сохраняются в переменных event. clientX и event. clientY. Эти координаты измеряются в той же плоскости, что и размер страницы. Как только вы наведете указатель мыши на элемент документа, его идентификатор отобразится на странице. Отдельные элементы (например, br или tr) не занимают место на странице, поэтому их идентификатор вы не увидите. В рассматриваемом примере элементы позиционированы в верхней части документа, чтобы вы могли изучить возможности метода elementFromPoint () по управлению перекрывающимися объектами. При прокрутке документа координаты события изменяются соответствующим образом. <html> <head> <title>document.elementFromPoint() Method</title> <script type="text/javascript"> function showElemUnderneath() { var elem = document.elementFromPoint(event.clientX, event.clientY); document.getElementByldC'mySpan") .innerTexb = elem.id; } document.onmouseover = showElemUnderneath; </script> </head> <body id="myBody"> Глава 18. Объекты document и body 585
<hl id="header">document.elementFromPoint() Method</hl> <hr id="myHR" /> <p id="instructions">Roll the mouse around the page. The coordinates of the mouse pointer are currently atop an element<br id=;"myBR" />whose ID is:"<span id="mySpan" style=" font-weight :bold"x/span>" .</p> <form id="myForm"> » <input id="myButton" type="button" value="Sample Button" onclick="" />&nbsp; </form> <table border="l" id="myTable"> <tr id="trl"> <td id="td_Al">Cell Al</td> <td id="td_BlM>Cell Bl</td> </tr> <tr id="tr2"> <td id="td_A2">Cell A2</td> <td id="td_B2">Cell B2</td> </tr> </table> <h2 id="secl">Section l</h2> <p id="pl">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <h2 id="sec2">Section 2</h2> <p id="p2">Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseruntmollit anim id est laborum.</p> <div id="myDIV" style="position:absolute; top:340; left:300; background-color:yellow"> Here is a positioned element. </div> </body> </html> См. также: свойства event .clientx, event .clientY; позиционируемые объекты (глава 39). execCommand (" имяКоманды" [, флаг*] [, параметр]) Возвращаемое значение: булево Совместимость: WinIE4+, МасШ-, NN7.1, Mozl.4, Safari- В ГЕ4+ содержится большой набор команд, которые не входят в состав методов, определенных для объектов в объектной модели. Эти команды доступны для программистов, которые используют элементы управления ActiveX в Internet Explorer для выполнения задач в приложениях. Метод execCommand () (не поддерживаемый в МасШ5) — это способ обращения JavaScript к этим командам. Серии связанных методов (queryCommandEnable О и другие) также облегчают управление этими командами. Синтаксис для метода execCommand () требует, по крайней мере, одного параметра — имя команды в строковом формате. В именах команд регистр не учитывается. Второй параметр 586 Часть III. Объекты документа
необязателен — это булев флаг, определяющий, следует ли отображать в интерфейсе сделанные пользователем изменения, которые вызваны данной командой. По умолчанию устанавливается значение— false. Некоторые команды нуждаются в третьем параметре и ждут получения его значения для дальнейшей работы. Например, чтобы установить размер шрифта для текста, применяется следующий синтаксис. myRange.execCommand("FontSi ze",true, 5) ; Метод execCommand () возвращает булево значение true, если команда выполнена успешно; false, если безуспешно, и undefined — в МасШ5. Некоторые команды могут возвращать другие значения (например при выборе имени шрифта), но к ним необходимо обращаться с помощью метода queryCommandValue (). Большинство таких команд форматирует текст тела документа, заданный в объекте TextRange. Объект TextRange необходимо создавать исключительно в сценарии (см. главу 35), хотя объект также будет создан в случае выделения пользователем текста в документе. Так как данный объект не зависит от иерархии элементов (действительно, TextRange может генерироваться во многих узлах), он не соответствует спецификации таблиц стилей. Таким образом, многие команды, которые изменяют объект TextRange, должны выполнять форматирование или изменять текст. Список команд, которые выполняются исключительно для объектов TextRange, приведен в главе 35 (описание метода TextRange. execCommand ()). Многие команды, предназначенные для управления объектом TextRange, также выполняются из объекта document, однако в данном разделе внимание сосредоточено на тех командах, которые применяются ко всему документу. В табл. 18.3 приведен список этих команд. Кроме того, будут перечислены команды, управляющие исключительно текстовыми фрагментами в документе (независимо от того, приведено изменение пользователем вручную или с помощью объекта TextRange (см. главу 35)). Команда Параметр Описание Refresh SelectAII Unselect BackColor CreateBookmark CreateLink FontName FontSize Fontcolor Indent Нет Нет Нет Строковое значение цвета Строковое значение анкера Строковое значение URL-адреса Название шрифта Строковое значение размера шрифта Строковое значение цвета Нет Перезагрузка страницы Выделение всего содержимого страницы Отмена любого выделения на странице Заключение выделенного фрагмента в дескриптор font, с помощью атрибута style которого задается параметр background-color Заключение выделенного фрагмента (или текстового диапазона) в элемент анкера, атрибут name которого приобретает значение параметра Заключение выделенного фрагмента в элемент а, атрибут href которого установлен в значение параметра Заключение выделенного фрагмента в элемент font, атрибут face которого установлен в значение параметра Заключение выделенного фрагмента в элемент font, атрибут size которого установлен в значение параметра Заключение выделенного фрагмента в элемент font, атрибут color которого установлен в значение параметра Занесение в буфер выделенного фрагмента Глава 18 Объекты document и body 587
Окончание табл. 18.3 Команда JustifyCenter JustifyFull JustifyLeft JustifyRight Outdent RemoveFormat SelectAll UnBookmark Unlink Unselect Параметр Нет Нет Нет Нет Нет Нет Нет Нет Нет Нет Описание Выравнивание выделенного фрагмента по центру Выравнивание выделенного фрагмента по ширине Выравнивание выделенного фрагмента по левому краю Выравнивание выделенного фрагмента по правому краю Удаление выделенного фрагмента Удаление форматирования для выделенного фрагмента Выделение всего текста в документе Удаление анкерных дескрипторов, содержащихся в выделенном фрагменте Удаление дескрипторов ссылок, содержащихся в выделенном фрагменте Снятие выделения с любого фрагмента в документе Mozilla 1.4 поддерживает возможность преобразования объекта документа элемента i frame в редактируемый HTML-документ. Метод document. exec Command () — это часть данной технологии. Пример Примеры использования метода execCommand () для объекта text Ranges приведены в главе 35. В настоящий момент вы можете воспользоваться для изучения этого метода приложением The Evaluator. Поочередно введите каждое из приведенных ниже вьфажений в верхнее текстовое поле приложения. document.execCommand("Refresh") document.execCommand("SelectAl1") document.execCommand("Unselect") См. также: методы queryCommandEnabledO, queryCommandlndtermO, queryCommandState(), queryCommandSupported(), queryCommandText(}, queryCommandValue(). getElementByld (" идентификаторЭлемента") Возвращаемое значение: ссылка на элемент Совместимость: WinIE5+, МасШ5+, NN6+, Mozl+, Safari 1+ Метод document .getElementByldО относится к синтаксису W3C DOM и применяется для задания ссылок на любой элемент в документе, который имеет уникальный идентификатор, назначенный атрибуту id. Если документ содержит более одного экземпляра указанного идентификатора, метод возвращает ссылку на первый элемент в исходном коде с соответствующим id. Так как данный метод используется для записи ссылок на объекты, которые должны быть изменены при управлении сценарием, то можно только предположить, насколько важно назначить элементам уникальные ID. Имя этого метода вводит программистов в заблуждение, особенно если принять во внимание, что в IE4+ ссылка на любой элемент должна начинаться с идентификатора объекта. Но пока в NN6 не будет проведена нормализации массива document. all, метод getElementByld () 569 Часть /W. Объекты документа
будет использоваться как способ задания ссылок на элементы в браузерах IE5+ и NN6+. При работе с данным методом убедитесь в том, что последний символ в имени этого метода (d) введен в нижнем регистре. В отличие от других, управляющих элементами методов (например, ge t Element s By - TagName ()), которые могут быть вызваны в любом элементе документа, get Element By Id () метод выполняется исключительно для объекта document. Пример Далее вы ознакомитесь со многими примерами использования метода getElementByld (). Вы всегда можете применить для его изучения приложение The Evaluator. В документе этого приложения многие элементы имеют идентификаторы. Введите приведенные ниже операторы как в верхнее, так и в нижнее текстовые поля. Результат их выполнения в верхнем поле представлен ссылками на объекты. Результат выполнения этих выражений в нижнем поле состоит из списка свойств. document.getElementByld("myP") document.getElementByld("myEM") document.getElementByld("myTitle") document.getElementByld("myScript") См. также: метод getElementsByTagName () (глава 15). getElementsByName ("имяЭлемента") Возвращаемое значение: массив Совместимость: Winffi5+, Macffi5+, NN6+, Mozl+, Safari 1+ Метод document .GetElementsByName () возвращает массив ссылок на объекты, атрибут Name которых определяет имя элемента и передается как параметр метода. В NN6 атрибуты Name используются даже для элементов, которые не имеют их по умолчанию; в Ш5+ этого не происходит. Поэтому для максимальной совместимости документов с браузерами применяйте этот метод только для элементов, имеющих атрибуты Name, определенные для них по умолчанию (например элементы управления форм). Если элемент не существует в документе, метод возвращает массив нулевой длины. В большинстве случаев рекомендуется использовать идентификаторы элементов и метод getElementByld () для задания ссылок на отдельные объекты. Но некоторые элементы, особенно элемент input типа '"переключатель", используют атрибут Name для того, чтобы собрать элементы в одну группу. В этом случае выполнение метода getElementsByName () возвращает массив всех элементов, которые совместно используют одно имя. В результате упрощается цикл for, в котором проверяется свойство checked группы переключателей. Таким образом, вместо использования старомодной (хотя и полностью совместимой) ссылки с указанием формы объекта var buttonGroup = document.forms[0].radioGroupName; можно задать прямую ссылку на имя элемента var buttonGroup = document.getElementsByName(radioGroupName); В последнем случае операция выполняется независимо от номера или имени имеющейся формы объекта. Конечно, подразумевается, что имя группы переключателей на текущей странице нигде больше не используется. Глава 18 Объекты document и body 589
Пример Приложение The Evaluator позволяет ознакомиться и с методом getElementByNmae (). Все элементы управления формы, представленной в верхней части страницы, имеют имена. Введите в верхнее текстовое поле следующие выражения. document.getElementsByName("output") document.getElementsByName("speed").length document.getElementsByName("speed")[0].value Введя приведенный далее оператор в нижнее поле, вы исследуете все свойства текстового Ъоля. document.getElementsByName("speed")[0] См. также: методы document .getElementsByld (), getElementsByTagName (). getSelection() Возвращаемое значение: строковое Совместимость: Winffi-, МасШ-, NN4+, Moz-, Safari- Многие пользователи Web-браузеров даже и не подозревают о том, что могут сами выделять, копировать и вставлять в другие прикладные документы основной текст страницы. Для данной возможности в NN4+ предлагается способ сохранения текста, выделенного пользователем на странице, с помощью сценария. Метод document .Get Select ion () возвращает строку текста, выделенного пользователем. Если документ не содержит выделенного текста, то возвращаемым результатом является пустая строка. Возвращенные значения состоят только из текста, отображаемого на странице в браузере, а не основного HTML-текста. В IE4+ также представлена подобная возможность. Для этого используется свойство document • selection, которое возвращает объект selection в Internet Explorer (в МасШ5 не поддерживается). Для получения текста, содержащегося в selection, нужно создать в нем объект TextRange, а затем просмотреть свойство text. var selectedText = document.selection.createRange().text; Пример В листинге 18.15 приведено межбраузерное приложение (не реализуется только в МасШ5), позволяющее захватить текст, выделенный пользователем на странице. Выделенный текст выводится сценарием в текстовой области. В сценарии выполняется проверка используемого браузера, и на основе полученного результата распознаются события выделения текста. <html> <head> x <title>Getting Selected Text</title> <script type="text/javascript"> var isNav4 = (navigator.appName == "Netscape" && parselnt(navigator.appVersion) == 4); var isNav4Min = (navigator.appName == "Netscape" && parselnt(navigator.appVersion) >= 4); var isIE4Min = (navigator.appName.indexOf("Microsoft") != -1 && parselnt(navigator.appVersion) >= 4); function showSelectionO { if (isNav4Min) { document.forms[0].selectedText.value = 590 Часть ///. Объекты документа
} document.getSelection(); } else if (isIE4Min) { if (document.selection) { document.forms[0].selectedText.value = document.selection.createRange()\ text; event.cancelBubble = true; } } if (isNav4) { document.captureEvents(Event.MOUSEUP); } document.onmouseup = showSelection; </script> </head> <body> <hl>Getting Selected Text</hl> <hr /> <p>Select some text and see how JavaScript can capture the selection:</p> <h2>ARTICLE I</h2> <p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.</p> <form> <textarea name="selectedText" rows="3" cols="4 0" wrap="virtual"> </textarea> </form> </body> </html> 1 " " HII 'I ■ См. также: свойство document. selection. handle Event (событие) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN4, Moz-, Safari- В NN4 при явном перехвате события объектами window, document или слоя (в результате вызова метода captureEvents () для этого объекта) можно контролировать расположение событий после их первоначального использования. Чтобы перемещение события к первоначальной цели было продолжено (например, кнопка нажата пользователем), используется метод routeEvent (). Но если нужно переадресовать одно событие (или целый класс) в определенный обработчик событий, находящийся в другой части документа, используйте метод handleEvent(). Более подробно метод handleEvent () для объекта window был описан в главе 16. Этот метод для всех объектов работает одинаково. См. также: методы document. captureEvents (), document. releaseEvents (), document. routeEvent (); объект event (глава 25). Глава 18. Объекты document и body 591
open ([" типМхте " ] [, замена]) Возвращаемое значение: отсутствует Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Процесс открытия документа отличается от процесса открытия окна. При открытии окна создается новый объект и на экране, и в памяти браузера. С другой стороны, при открытии документа браузер готовится принять данные для дальнейшего отображения их в окне, названном или указанном в методе document. open (). (Например, parent. frames [1] . document. open () может обращаться к разным фреймам одного набора, принимая во внимание, что document. open () подразумевает текущее окно или фрейм.) Поэтому имя метода может вводить в заблуждение начинающих разработчиков, так как метод document. open () не имеет никакого отношения к загрузке документов с Web-сервера или жесткого диска. Этот метод является "прелюдией" к отправке данных в окно с помощью методов document. write () или document .writeln (). В некотором смысле, метод document. open () просто открывает канал, а другие методы пересылают поток данных по этому каналу; метод document. close () закрывает этот канал, когда данные страницы полностью отправлены. Метод document. open () использовать необязательно, так как document. write () при записи данных в закрытый документ автоматически очищает старый документ и открывает поток. Независимо от того, использовался ли метод document. open (), убедитесь в том, что выполнены все нужные операции записи; только после этого используйте document. close (). В методе document. open () существует необязательный параметр, который позволяет определить тип данных, передаваемых в окно. Тип MIME является спецификацией для передачи и представления мультимедийных данных в Internet (первоначально применялся для передачи почтовых сообщений, а теперь — для любого обмена данными в Internet). В параметрах настройки свойств браузера есть описание типов MIME. Тип MIME представлен двумя элементами, разделенными символом косой черты (например, text /html или image /gif). При определении типа MIME как параметра метода document. open () необходимо определить в браузере соответствующий тип получаемых им данных как обрабатываемый. Ниже приведены общие значения, которые принимаются большинством браузеров. text/html; text/plain; image/gif; image/jpeg; image/xbm; Если данный параметр не указан, JavaScript выбирает наиболее часто используемый тип text /html, который обычно указывают в сценарии перед записью данных в окно. Тип text /html представляет любые изображения, ссылки на которые содержит HTML- документ. Определение произвольного типа изображения означает наличие необработанного двоичного представления изображения, которое должно появиться в новом документе. Существует еще одна возможность, с помощью которой можно направлять содержимое метода write () на выполнение в надстройке. В параметре mimeType укажите тип MIME- надстройки (например application/x-director для Shockwave). В следующий раз запись данных в эту надстройку будет выполняться автоматически. Указанный метод также применим и для записи данных в приложение справочной системы. # В IE принимается только параметр типа MIME text/html. /На штщ 592 Часть ///. Объекты документа
В NN4+ и Ш5+ задается второй необязательный параметр метода: замена. С помощью этого параметра метод document. open () выполняет операции, подобные тем, которые производятся для объекта location в методе replace (). Для document. open () это означает, что новый документ, который должен быть помещен в окно или фрейм, заменяет предыдущий документ, находящийся в списке посещенных страниц этого окна или фрейма. Пример Пример использования open () приведен в листинге динамического создания содержимого другого фрейма (см. описание метода document. write () далее в этой главе). См. также: методы document. close (), document. clear (), document. write (), document. writeln (). gueryCommandEnabled (" имяКоманды") gueryCommandlndterm ("имяКоманды") gueryCommandCommandState ('■ имяКоманды") gueryCommandSupported("имяКоманды") gueryCommandText ("имяКоманды") gueryCommandValue ("имяКоманды") Возвращаемое значение: любое Совместимость: WinIE4+, MacIE-, NN7.1, Mozl.4, Safari- Перечисленные шесть методов выполняются совместно с методом execCommand () для объектов Text Range и document. При выборе метода execCommand () для выполнения стилистического форматирования текста можно использовать некоторые из этих методов запросов, чтобы удостовериться в том, что браузер поддерживает нужную команду, и получить любые возвращаемые значения. В табл. 18.4 описано предназначение и приведены возвращаемые каждым из методов значения. Запрашиваемая команда Возвращаемое значение Ш^Щ^Щ^Й^^;'Н#W''b4<аЧ;. - *: Описание Enabled Indterm CommandState Булево значение Булево значение Булево значение!null Supported Text Value Булево значение Строковое значение Любые значения Определяет, находятся ли объекты document, TextRange в приемлемом для вызова состоянии Определяет, находится ли команда в приемлемом для вызова состоянии Определяет, завершено ли выполнение команды (true), процесс все еще идет (false) или данная команда находится в неопределенном состоянии Определяет, поддерживается ли команда в текущем браузере Возвращает любой текст, поддерживаемый данной командой Определяет, возвращено ли командой значение (если таковое существует) Глава 18. Объекты document и body 593
По причине того, что метод execCommand () нельзя вызвать на странице во время ее загрузки, перед запуском команды любые подобные обращения должны проверяться с помощью метода queryCommandEnabled (). Следует также проверить, поддерживает ли сценарий, запускаемый в данной версии браузера, нужную команду (особенно для команд, появившихся в Ш4+). Таким образом, можно анализировать любую команду, вызвав ее с помощью следующего выражения. i f (queryCommandEnabled(имяКоманды)&& queryCommandSupported{имяКоманды) ) { ... } Для получения сведений о выделенном тексте используйте методы queryCommandText () или queryCommandValue () (заметьте, что в методе execCommand (), независимо от того, какая команда вызвана, возвращается булево значение). Пример Пример использования методов queryCommandEnabled (), queryCommandlndterm (), queryCommandCommandState (), queryCommandSupported (), queryCommandText (), queryCommandValue () приведен в главе 35, посвященной объекту TextRange. См. также: объект TextRange (глава 35); метод execCommand {). recalc([флаг]) Возвращаемое значение: отсутствует Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- B Ш5 представлена концепция динамических свойств. С помощью метода set Express ion () для всех элементов и значений таблицы стилей expression () можно установить зависимости между свойствами объектов и потенциально динамическими свойствами — размером окна или расположением перетаскиваемого элемента. После установки этих зависимостей метод document. recalc () заставит обновить зависимости в ответ на действие пользователя (например, на изменение размеров окна или перемещение элемента). Единственный необязательный параметр имеет булев тип данных. По умолчанию установлено значение false. Это означает, что обновление выполняется только для выражений, в которых браузер обнаружил изменения, произошедшие со времени последнего обновления. Однако, если указывается значение true, обновляются все выражения, независимо от того, изменились они или нет. Mozilla 1.4 поддерживает возможность преобразования объекта документа элемента iframe в редактируемый HTML-документ. Метод document. execCommand () — это часть данной технологии. Пример Пример использования метода recalc () приведен в листинге 15.32 при описании метода setExpressionO. В данном примере устанавливается зависимость между текущим временем и свойствами стандартных элементов. См, также: методы getExpression(), removeExpression(), setExpression() (глава 15). releaseEvents (списохСобытяй) Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN4+, Moz-, Safari- 594 Часть III. Объекты документа
Если при выполнении сценариев в NN4 проводится перехват события объектом document (window или слоя), то эту операцию можно отменить с помощью метода releaseEvents (). Такой метод фактически не препятствует событию по достижению поставленной цели. Отменив перехват событий объектами высокого уровня, вы больше не сможете заставить эти объекты ожидать генерирования событий в документе. Пример В главе 16 описывается метод releaseEvents () для объекта window. Данный метод одинаково работает для всех объектов. См, также: методы document. captureEvents (), document. routeEvent (). routeEvent (событие) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN4+, Moz-, Safari- Если в NN4 осуществляется перехват события в объектах слоя, window или document (с помощью соответствующих методов captureEvents ()), назначенный обработчик событий действительно перехватывает те события, на которые он настроен, не позволяя им достичь поставленной цели. Для некоторых страниц этот перехват осуществляется намеренно, чтобы позволить объекту более высокого уровня обработать все события определенного типа. Но если цель состоит в том, чтобы выполнить предварительную обработку событий перед тем, как они достигнут своего адресата, используйте способ передачи этого события по обычному пути — собственно для этого и нужен метод routeEvent (). Пример Более подробно метод routeEvent () для объекта window описан в главе 16. Данный метод одинаково работает для всех объектов. См. также: методы document. captureEvents () i document. releaseEvents (). wri te(■cvpoxaln [,"строка2"...[, ■строкап■]]) writeln(■строка!" [,н строка2"...[, "строкап"]]) Возвращаемое значение: при удачном выполнении — булево true Совместимость: WinIE3+, MacIE3+, NN2+, Moz 1 +, Safari 1+ Оба метода пересылают текст документу для дальнейшего его вывода в окне. Единственное различие между этими методами состоит в том, что document .writeln () добавляет в конце каждой строки документа невидимый символ перехода на другую строку. Этот переход нужен для форматирования исходного кода при просмотре его в окне браузера. В откомпилированном HTML-документе, который генерируется этими методами, для перехода на новую строку используется дескриптор <br>, который определяет конец данной строки. Как правило, многие начинающие JavaScript-разработчики делают ошибочное заключение о том, что данные методы позволяют изменять содержимое любого существующего документа с помощью сценариев, но это совсем не так. После полной загрузки документа в окно (или фрейм) единственный совместимый (с браузером) текст, который можно изменять без перезагрузки или перезаписи всей страницы, — это, собственно, текст страницы и объектов textarea. В Ш4+ код HTML и текст можно изменять с помощью следующих свойств: innerHTML, innerText, outerHTML и outerText, которые задаются для любого элемента. В NN6 и Ш5+ допускается Глава 18. Объекты document и body 595
изменять текст элемента, устанавливая его свойства nodeValue или innerHTML; строгое соблюдение правил в W3C DOM требует создания, вставки, а также замены элементов (см. главу 15). Приведем два наиболее безопасных способа использования методов document .write () и document.writeln(): И сгенерировать часть или все содержимое страницы с помощью встроенных в до- кумент сценариев; ■ отправить НТМЫсод либо в новое окно, либо в отдельный фрейм многофреймового окна. В первом случае отдельные части сценария задаются непосредственно в HTML-документе. Сценарии выполняются при загрузке документа, записывая любой нужный HTML-код (эта операция подобна той, которая была представлена в script 1. htm — глава 3). С помощью этого способа можно сгенерировать HTML-страницу, предназначенную для определенного типа браузеров, однако при этом помните, что для браузера нужно использовать специфический синтаксис. Во втором случае сценарий может запрашивать у пользователя информацию в одном фрейме, а затем в пределах иерархической структуры задавать размещение и результат преобразования этой информации в другом фрейме. Сценарий вызывает HTML-код последнего как строковую переменную (включая все необходимые дескрипторы HTML). Прежде чем во фрейм будет записана какая-либо информация из сценария, с помощью этого же сценария необходимо открыть поток (чтобы закрыть текущий открытый документ в этом фрейме), используя метод parent. f rameName. document. open (). Метод parent. f rameName. document. write () добавит полную строку в другой фрейм. И наконец, использование метода parenjt. f rameName . document. close () гарантирует запись в текущее окно полного потока данных. Такой созданный в памяти фрейм внешне ничем не отличается от фрейма, который создан текущим документом, находящимся на сервере. Объект document отдельного окна или фрейма является таким же полноправным, как и стандартный объект document. Поэтому во временную HTML-страницу можно совершенно спокойно включать сценарии как часть определенного HTML-документа. Вызов HTML-документа в сценарии для дальнейшей его записи с помощью метода document .write () часто требует навыка в конкатенации строковых значений и совмещении вложенных строк. Некоторые быстрые методы управления строковыми объектами в JavaScript облегчают форматирование текста в дескрипторах HTML (см. главу 27). При записи в различные фреймы или окна можно использовать метод document. write () довольно часто. В определенной степени от сложившейся ситуации, а также от стиля программирования зависит, будет ли сценарий отправлять в документ короткие строки, многократно используя document .write () метод, или он вызовет большую строку с помощью одной команды. С профессиональной точки зрения, чем больше проведено предварительных действий в памяти и чем меньше осуществлено запросов ввода/вывода, тем лучше. С другой стороны, появление ошибки более вероятно при объединении строк в одну более длинную строку. Я предпочитаю использовать длинные строки, вы можете руководствоваться личными предпочтениями. Далее мы рассмотрим еще один малоизвестный способ передачи параметров в данный метод. Вместо объединения строковых значений с помощью оператора объединения (+), можно также записать значения, разделив их запятыми. Например, оба следующих выражения приводят к одинаковым результатам. document .write ("Today is " + new DateO); document.write("Today is ", new Date()); И вновь повторим, что не существует универсальной формы объединения строковых данных, поэтому вы должны использовать тот способ, который больше подходит для избранного стиля программирования. 596 Часть III. Объекты документа
Генерируемые динамически сценарии требуют дополнительных эксклюзивных методов, особенно в NN. Часто проблема возникает в том случае, когда используется следующий код: document.write(H<scriptx/script>n). Браузер интерпретирует закрывающий дескриптор сценария как конец сценария, с помощью которого производится запись нового документа. Вам необходимо "обмануть" браузер, разместив закрывающий дескриптор в отдельной строке. Старайтесь не использовать символ обратной косой черты. Например, если необходимо загрузить различные файлы .js для каждого типа браузеров, код представьте следующим образом. // Переменная 'browserVer' — строка, используемая только //в браузерах, // a 'page' — HTML-документ, для которого вызывается сценарий page += "<script type='text/javascript' src='" + browseVer + ".js'x" + "\/script>"; Использование методов document. open (), document. write () и document. close () для вывода на экран изображений, содержащихся в документе, требует некоторых дополнительных операций. Во-первых, любые URL-адреса, указанные в document .write (), должны быть полными (не относительными) ссылками URL (особенно для пользователей NN2). Альтернативным способом является задание дескриптора <base> для динамически сгенерированной страницы (значение его атрибута href должно соответствовать тому файлу, в который записывается страница). Еще один способ— указать атрибуты height и width для каждого изображения, содержащегося в сценарии или другой части документа. С помощью этих значений браузер располагает элементы на странице перед их загрузкой. Далее приведены примеры использования document. write () (см. листинги 18.16-18.18); однако более полное описание этого метода, предназначенного для отображения изображений и диаграмм, можно найти в приложениях глав 48-57. Известно, что любой существующий HTML-документ можно вызвать как строку, которая будет записана в окно или фрейм, поэтому настроенный непрерывный документ может быть настолько сложным, насколько вообще можно себе вообразить документ HTML. Пример Пример использования методов write () и writeln () приведен в листингах 18.16-18.18. С их помощью данные добавляются в другой фрейм. Вы можете ввести в этот фрейм любой HTML-код — браузер воспринимает его как исходный код документа фрейма, сохраненный в файле. В данном примере таким образом введены все HTML-дескрипторы документа. <html> <head> <title>Writin' to the doc</title> </head> <frameset rows="50%,50%"> <frame name="Framel" src="lstl8-17.htm" /> <frame name="Frame2" src="lst!8-18.htm" /> </frameset> </html> /- Нязямвцсу Глава 18. Объекты document и body 597
<html> <head> <title>Document Write Controller</title> <script type="text/javascript"> function takePulse(form) { var msg = "<html><headxtitle>On The Fly with " + form.yourName.value + "<\/titlex\/head>"; msg += "<body bgcolor='salmon'><hl>Good Day " + form.yourName.value + "!<\/hlxhr />"; for (var i = 0; i < form.how.length; i++) { if (form.how[i].checked) { msg += form.how[i].value; . break; msg += "<br />Make it a great day !<\/bodyx\/html>" ; parent.Frame2.document.write(msg); parent.Frame2.document.close(); } function getTitleO { alert ("Lower frame document.title is now:" + parent.Frame2 .document.title) ; </script> </head> <body> Fill in a name, and select how that person feels today. Then click "Write To Below" to see the results in the bottom frame. <form> Enter your first name:<input type="text" name="yourName" value="Dave" /> <p>How are you today? <input type="radio" name="how" value="I hope that feeling continues forever." checked="checked" />Swell <input type="radio" name="how" value="You may be on your way to feeling Swell" /> Pretty Good<input type="radio" name="how" value="Things can only get better from here." />So-So</p> <p><input type="button" name="enter" value="Write To Below" onclick="takePulse(this.form)" /></p> <hr /> <input type="button" name="peek" value="Check Lower Frame Title" onclicks"getTitle()" /> </form> </body> </html> <html> <head> <title>Placeholder</title> </head> <body> </body> </htjj\l> 598 Часть III. Объекты документа
Важно понимать, что содержимое документа зависит от заданных пользователем настроек. Установить эти параметры могут только опытные пользователи, которые знакомы с работой CGI-программ. Еще один момент, на котором следует акцентировать внимание, связан с документом, расположенным в отдельном фрейме. В рассматриваемом приложении данные изменяются динамически. Например, дескриптор <title> записываемого документа изменяется, если его заново отобразить с другим именем в верхнем текстовом поле. Если щелкнуть на нижней кнопке после обновления нижнего фрейма, то можно заметить, что свойство document. title изменяется, чтобы отобразить изменение в дескрипторе <title>. Вы можете легко изменить листинг 18.17 так, чтобы результат сохранялся в том же фрейме, в котором располагается поле и кнопка. Вместо следующих операторов parent. frames [1] . document. open () parent.frames[1].document.write(msg) parent.frames[1].document.close() используйте такие выражения. document.open () document .write (msg) document.close() Как видите, в данном случае фреймы не используются вообще — они попросту не нужны. Поскольку все содержимое документа сохраняется в одной переменной, то для вывода его в документе достаточно использовать всего один оператор document. write (). Документ набора фреймов (листинг 18.16) создает новый фрейм в результате загрузки пустого документа (листинг 18.18). Рекомендуем сначала создать фрейм, а затем загрузить в него пустой документ (см. главу 16). См. также: методы document. open (), document. close (), document. clear (). Обработчики событий onselectionchange Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Событие onselectionchange может быть вызвано многими действиями пользователя, хотя все эти действия происходят с элементами, которые находятся в Winffi5.5 в режиме редактирования. См. также: обработчик события oncontrolselect. onstop Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Событие onstop возникает в Г£5 при щелчке пользователя на кнопке Stop в браузере. Используйте этот обработчик события для остановки потенциально неконтролируемого сценария на странице, так как кнопка Stop не позволяет управлять сценариями после загрузки страницы. Если у вас возникает проблема потери контроля над циклом во время его работы, можно временно использовать этот обработчик события, чтобы приостановить сценарий для отладки. Пример Листинг 18.19 представляет пример использования обработчика onstop. Если вы загрузите эту страницу в браузере Ш5+, то сможете воспользоваться кнопкой Halt Counter для остановки цикла. Эта кнопка и обработчик onstop вызывают одну и ту же функцию. Глава 18. Объекты document и body 599
<html> <head> <title>onStop Event Handler</title> <script type=*"text/javascript"> var counter = 0; var timerID; function startCounter() { document. forms [0] .display.value = ++counter; //clearTimeout(timerlD) timerID = setTimeout("startCounter()", 10); function haltCounter() { clearTimeout(timerID); counter = 0; } document.onstop = haltCounter; </script> </head> <body> <hl>onStop Event Handler</hi> <hr /> <p>Click the browser's Stop button (in IE) to stop the script counter.</p> <form> <p><input type="text" name="display" /></p> <input type="button" value="Start Counter" onclick="startCounter()" /> <input type="button" value="Halt Counter" onclick="haltCounter()" /> </form> </body> </html> См. также: циклы (глава 31). Элемент body Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий alink background bgColor bgProperties bottomMargin leftMargin createControlRange() createTextRange() doScroll() onafterprint onbeforeprint onscroll Часть ///. Объекты документ*
Окончание таблицы Свойства Методы Обработчики событий link noWrap rightMargin scroll scrollLeft scrollTop text topMargin vLink Синтаксис Доступ к свойствам и методам объекта элемента body. [window. ] document. body. свойство \ метод [параметры] ) Описание объекта В объектных моделях, в которых отображаются объекты элементов HTML, элемент body используется для хранения основного содержимого страницы, представляемой посетителям. Элемент body содержит весь обрабатываемый код HTML. Объект body занимает особое место в иерархии элементов, которое предполагает и некоторые особые возможности. В наибольшей степени это относится к объектной модели в Internet Explorer. Если говорить о поддержке этого объекта браузерами, то следует отметить, что и в Internet Explorer, и в W3C элемент body вызывается одной и той же ссылкой: document. body. Однако данный объект является объектом элемента HTML первого уровня (как указано в списке свойств, методов и обработчиков событий, приведенном в главе 15), поэтому для доступа к элементу body можно использовать любой другой синтаксис. Пользователь, конечно, знаком с некоторыми атрибутами элемента body, которые управляют отображением его содержимого на странице: это цвета состояний ссылок и параметр фона (цвет или изображение). Но при создании сценариев в документах Internet Explorer и Netscape Navigator (и пока W3C) данный элемент играет разные роли. Многие методы и свойства, которые используются в Netscape Navigator как отдельные объекты, предназначенные для представления средств управления окном (например, полосы прокрутки и т.д.), в Internet Explorer рассматриваются исключительно как свойства и методы элемента body. Поэтому при использовании одной и той же команды в Netscape Navigator прокручивается все окно (и соответственно, все его содержимое), а в Internet Explorer — только тело программы (в том окне, в котором оно расположено). По причине того, что элемент body заполняет всю просматриваемую область окна браузера или фрейма, размер этой области определяется в Internet Explorer свойствами scrollHeight и scrollWidth, а в NN4+ — window. innerHeight и window. inherWidth. Важно учесть это различие при определении в сценарии размеров выводимого окна или документа, поскольку вам, возможно, придется указывать соответствующие свойства и методы для объекта window, а также для элемента body (в зависимости от используемого браузера(ов)). Глава 18. Объекты document и body 601
Будьте осторожны при доступе к объекту document. body во время загрузки страницы. Пока страница полностью не загружена, объект официально не существует. Если необходимо установить некоторые начальные свойства в сценарии, сделайте это с помощью обработчика событий onload, расположенного в дескрипторе <body>. Попытки установить свойства рбъекта элемента body непосредственно в сценарии (в элементе head) могут привести к сообщениям об ошибке в процессе поиска данного объекта. Свойства aLink bgColor link text vLink Значение: шестнадцатеричный числовой триплет или название цвета Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойства aLink, link, vLink представляют собой новые версии свойств alinkColor, linkColor и vlinkColor объекта document. Свойство bgColor является аналогом старого свойства document .bgColor, a text— document. fgColor. Эти новые свойства — эквиваленты HTML-атрибутов для элемента body. Их новые названия соответствуют атрибутам HTML в большей степени, чем старые. Обращение к цветам ссылок, установленных с помощью псевдоатрибутов в таблицах стилей (они представляют атрибуты style элемента body) производится в свойстве style объекта body. Вскоре это свойство, вероятно, перестанет применяться, поскольку таблицы стилей становятся все более популярными. Пример Вы можете изменить листинги 18.1 для использования его в Ш4+, NN6+/Mozl+/W3C. Замените все ссылки на объект document ссылками на объект document. body. Пример использования aLink, bgColor, link, text, vLink приведен на прилагаемом к книге компакт-диске. Например, одна из функций будет обновлена следующим образом. function showColorValues() { var result = ""; result += "bgColor: " + newWindow.document.body.bgColor + "\n"; result += "vLink: " + newWindow.document.body.vLink + "\n"; result += "link: " + newWindow.document.body.link + "\n"; document.forms[0].results.value = result; } См. также: document .alinkColor, document .bgColor, document. fgCo lor, document.linkColor, document.vlinkColor. background Значение: строка URL-адреса Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ / Назшмтсу 602 Часть III. Объекты документа
С помощью свойства background можно установить или получить URL-адрес фонового изображения страницы (если таковое существует), назначенного в элементе body. Это изображение размещается поверх цвета фона в случае, когда установлены оба атрибута или свойства. Для удаления фонового изображения документа установите в качестве значения свойства document. body. background пустую строку. Пример Если у вас есть изображение, например, images/logoBG.gif, то его можно использовать в качестве фона, если выполнить следующий оператор. document.body.background = "images/logoBG.gif"; Для очистки фона от изображения применяется следующее выражение. document.body.background = ""; Если перед изображением фон окрашивался в однородный цвет, то после удаления изображения фон заливается этим цветом. См. также: свойства body .bgCotor, body .bgProperties. bgColor См. aLink bgProperties Значение: строковая константа Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Свойство bgProperties, используемое только в Internet Explorer, предназначено для установки такого предписания: следует ли фоновому изображению перемещаться при прокручивании документа пользователем. Начальные установки для этого свойства сохраняются в CSS-атрибуте background-attachment, а изменять их можно в сценарии с помощью свойства style .backgroundAttachment элемента body. Независимо от того, какой способ используется для обрадения к этому свойству, допустимыми значениями будут только строковые константы scroll (по умолчанию) или fixed. Пример Оба приведенных ниже оператора изменяют поведение фонового изображения при прокрутке, заданное по умолчанию document.body.bgProperties = "fixed"; или document.body.style.backgroundAttachment = "fixed"; Последний вариант также выполняется в NN6+. См. также: свойство body. background. bottomMargin leftMargin rightMargin topMargin Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Главв 18. Объекты document и body 603
Данные четыре свойства используются только в Internet Explorer и являются альтернативой средства задания четырех атрибутов полей в таблице стилей элемента body (body.style.marginBottom и т.д.). Поля таблицы стилей представляют собой пустое пространство между краем содержимого элемента и наиболее удаленным от него объектом. В элементе BODY этот объект является неявно отображаемым на странице элементом документа. Из всех четырех свойств трудности могут возникнуть только при использовании bottomMargin и то в случае, когда площадь окна или фрейма не заполнена содержимым по вертикали. Границы поля автоматически не увеличиваются для заполнения дополнительного пространства. В Ш4+ существует немало целочисленных значений этого свойства, заданных по умолчанию для каждой операционной системы. Однако помните, что свойства не возвращают эти значения до тех пор, пока пользователь не установит их в собственных атрибутах Internet Explorer для элемента body. Даже при том, что у заданного по умолчанию элемента body видимые границы, свойство не возвращает по умолчанию их значения. Пример Оба приведенных ниже оператора изменяют левое поле в Ш4+, заданное по умолчанию. document.body.leftMargin = 30; document.body.style.marginLeft = 30; См. также: объект style. leftMargin Cm. bottomMargin. link Cm. alink. noWrap Значение: булево Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Используя свойство noWrap, можно управлять поведением элемента body, если вы измените его обычные настройки, заданные с помощью атрибута nowrap. Так как имя свойства имеет негативную форму (по), то пользователь может запутаться, анализируя булеву логику, применяемую для управления этим свойством. По умолчанию в элементе body существует установка на распределение текста по ширине окна или фрейма. Это происходит, когда noWrap имеет значение false. При переключении свойства noWrap в значение true текст приобретает вид одной строки, которая продолжается до тех пор, пока не встретится признак конца строки (закончится абзац) или она не выйдет за правую границу окна или фрейма. Вследствие того, что текст выходит за боковую границу окна, в окне (или фрейме) появляется горизонтальная полоса прокрутки (если, конечно, во фрейме не отменено ее использование). Как известно, пользователи вообще не любят прокручивать документ, если в этом нет особой необходимости. Поэтому лучше оставить значение, заданное по умолчанию. Пример Оператор изменения настройки перетекания текста со значения по умолчанию выглядит следующим образом. document.body.noWrap = true; 604 Часть III. Объекты документа
rightMargin См. bottomMargin. scroll Значение: строковая константа Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство scroll используется только в Internet Explorer. С помощью данного свойства можно обеспечить доступ к атрибуту scroll элемента body в Internet Explorer в сценарии. По умолчанию в элементе body (Internet Explorer) назначено отображение вертикальной полосы прокрутки, даже если высота документа не превышает высоту окна и для его просмотра прокрутка не требуется; горизонтальная же полоса прокрутки появляется только тогда, когда содержимое документа выходит за рамки окна или фрейма по ширине. Можете убедиться в том, что обе полосы прокрутки будут скрыты, если установить атрибут scroll в значение 14нет" или изменить его в сценарии. Возможными значениями этого свойства являются только строковые константы yes и по. Кроме атрибутов frame и защищенных сценариев в NN4+, другие браузеры не обеспечивают разработчика средствами отключения полос прокрутки в сценарии. Всегда можно сгенерировать новое окно (методом window. open ()) и задать в нем скрытие полос прокрутки. Пример Чтобы изменить состояние полос прокрутки со значения по умолчанию, выполните следующий оператор. document.body.scroll = "no"; См. также: свойство window. scrollbars; метод window. open (). scrollLeft scrollTop Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safari 1+ Даже при том, что свойства scrollLeft и scrollTop объекта body используются аналогично подобным свойствам обычных объектов элементов HTML, они играют важную роль при позиционировании элементов (см. главу 39). По причине того, что событие щелчка мышью и свойства позиционирования элемента обычно устанавливаются относительно отображаемого содержимого окна браузера, то всегда необходимо учитывать и величину прокрутки объекта document. body для указания точного позиционирования. Для обоих свойств используются целочисленные значения, заданные в пикселях. Пример Пример использования свойств scrollLeft, scrollTop приведен в листинге 18.20. Он представляет собой модифицированный пример применения свойств pageXOf f set HpageYOffset (листинг 16.13). Эти два листинга полностью идентичны, за исключением полученных значений, которые указывают, насколько документ прокручен в окне. Глава 18. Объекты document и body 60S
<html> <head> <title>Master of all Windows</title> <script type="text/javascript"> function leftFrameO { var output = "<htmlxbody><h3>Body Scroll Values <\/h3xhr />\n"; output += "<form>body. scrollLeft :<input type= ' text' name='xOf f set' size=4 /xbr />\n"; output += "body.scrollTop:<input type=•text' name='yOffset• size=4 /> <br />\n"; output += "<\/fprmx\/bodyx\/html>"; return output; } function rightFrameO { var output = "<htmlxheadxscript type='text/javascript!>\n"; output += "function showOffsets() {\n"; output += "parent.readout.document.forms[0].xOffset.value = document.body.scrollLeft\n"; output += "parent.readout.document.forms[0].yOffset.value = document.body.scrollTop\n}\n"; output += "document.onclick = showOffsets\n"; output += "<\/scriptx\/headxbodyxh3>Content Page<\/h3>\n" ; output += "Scroll this frame and click on a table border to view page offset values.<br /xhr />\n"; output += "<table border=5 width=800>"; var oneRow = "<td>Cell l<\/tdxtd>Cell 2<\/tdxtd>Cell 3 <\/tdxtd>Cell 4<\/tdxtd>Cell 5<\/td>"; for (var i = 1; i <= 30; i++) { output += "<trxtdxb>Row " + i + "<\/bx\/td>" + oneRow + "<\/tr>"; } output += "<\/tablex\/bodyx\/html>"; return output; } </script> </head> <frameset cols="30%/70%"> <frame name="readout" src="javascript:parent.leftFrame()" /> <frame name="display" src="javascript:parent.rightFrameO" /> </frameset> </html> См. также: свойства window. pageXOf f set, window. pageYOf f set. text Cm. alink. topMargin Cm. bottomMargin. vLink Cm. alink. 606 Часть ///. Объекты документа
Методы createControlRange() Возвращаемое значение: массив Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Пока разработчики Microsoft толком не ответили на вопрос, когда и как использовать объеет control Range, известно только одно: данный объект имеет некоторое отношение к документу в режиме редактирования. В обычном режиме просмотра документа метод createControlRange () (не осуществленный в МасГЕ5) возвращает пустой массив. createTextRange() Возвращаемое значение: объект TextRange Совместимость: WinIE4+, Macffi-, NN-, Moz-, Safari- Объект элемента body — наиболее часто используемый объект для генерирования объекта TextRange в ГЕ4+, особенно если текст, с которым работает пользователь, является частью основного текста документа. В первоначальном объекте TextRange, возвращенном методом createTextRange () (не поддерживаемом в Мас1Е5), содержался весь HTML-код и основной текст элемента body. Для дальнейших операций с возвращенным объектом требуется задать начальную и конечную точки диапазона. Более детально объект TextRange описан в главе 35. Пример Пример практического использования этого метода приведен в листинге 35.8. См. также: объект createTextRange () в главе 35. doScroll ( ["действие"]) Возвращаемое значение: отсутствует Совместимость: WinTE5+, Macffi-, NN-, Moz-, Safari- Используйте метод doScroll () для обеспечения ответной реакции на применение пользователем полос прокрутки в том окне или фрейме, в котором располагается текущий документ. Этот метод используется при создании собственных полос прокрутки вместо стандартных. Прокрутка производится мгновенно, даже быстрее, чем проигрывание анимации. Параметром данного метода служит одна из строковых констант, приведенных в табл. 18.5. На практике рекомендуется использовать более длинное имя действия прокрутки для имитации щелчка мышью на элементах панели прокрутки, так как сокращенные названия обрабатываются с несравненно большей скоростью. scrollbarDown scrollbarHThumb scrollbarLeft down нет. left Щелчок на стрелке "вниз" Щелчок на горизонтальном бегунке полосы прокрутки (прокрутка не осуществляется) Щелчок на стрелке "влево" Глава 18. Объекты document и body 607
Окончание табл. 18.5 Полное имя параметра Сокращенное Имитируемое действие прокрутки имя параметра scroilbarPageDown pageDown Щелчок на нижней области страницы или нажатие <PgDn> (по умолчанию) scrollbarPageLef t pageLef t Щелчок на левой области страницы scrolIbarPageRight pageRight Щелчок на правой области страницы scroiibarPageUp pageUp Щелчок на верхней области страницы или нажатие <PgUp> scrollbarVThumb нет Щелчок на вертикальном бегунке полосы прокрутки (прокрутка не осуществляется) В отличие от прокрутки, которая осуществляется в соответствии с определенным координатным расположением (достигаемым установкой свойств scroll Top и scroll Left элемента body), метод doScroll () полностью зависит от пространственного соотношения содержимого body и размера фрейма или окна. Метод doScroll () также вызывает обработчик события onscoll для объекта элемента body. Помните, что изменение содержимого body в сценарии может привести к изменениям в пространственных соотношениях. В Internet Explorer любые внутренние размеры обновляются после изменения содержимого. При попытке вызвать метод doScroll () после подобного изменения расположения элементов прокрутка может выполняться неправильно. В таких случаях обычно используют метод set Timeout (), который задает задержку в несколько долей секунды при обращении к методу doScroll (). Пример Приложение The Evaluator можно использовать для изучения метода doScroll () в Ш5+. Измените размер окна браузера таким образом, чтобы в нем отображалась хотя бы вертикальная полоса прокрутки. Введите следующее выражение в верхнее текстовое поле и нажмите несколько раз <Enter>, чтобы сымитировать нажатие клавиши <PgDn>. document.body.doScrol1() Перейдите в верхнюю часть страницы и выполните те же действия, сымитировав использование кнопки со стрелкой на полосе прокрутки. document.body.doScroll("down") Продолжите, выполнив прокрутку в обратном направлении. См. также: свойства body, scroll, body, scrollTop, body.scrollLeft; методы window.scroll(), window.scrollBy(), window.scrollTo(). Обработчики событий onafterprint onbeforeprint См. обработчик событий onafterprint для объекта window (глава 16). onscroll Совместимость: Winffi4+, МасШ4+, NN-, Moz-, Safari- Обработчик события onscroll вызывается для объекта элемента body в результате ручной прокрутки документа (с помощью полос прокрутки или клавиш) и прокрутки, 608 Часть III. Объекты документа
осуществляемой в сценарий с помощью методов doScroll (), scrolllntoView (). Обработчик onscroll также вьвывается при корректировке таких свойств объекта элемента body, как scrollTop и/или scrollLeft. При ручной прокрутке и прокрутке с помощью doScroll О событие должно вызываться дважды подряд. Кроме того, свойство event. srcElement возвращает нулевое значение (null), даже если в элементе body используется обработчик события onscroll. Пример В листинге 18.21 приведен пример несколько необычного инструмента, добавляемого на Web-страницы. Представьте себе, что размещенный в окне или фрейме документ нужно сделать абсолютно непрокручиваемым (даже с помощью современных мышей, оснащенных колесиками). Если пользователь попытается прокрутить документ, то этот документ должен сразу сместиться в обратном направлении. Обратите внимание, что в данном примере обработчик события задается как свойство объекта document. body. Его также можно назначить как атрибут дескриптора <body>. Но в последнем случае необходимо сначала загрузить саму страницу. До этого объект body официально не присутствует в иерархической структуре объектов документа. fttCTW 18.21. Пред^ <html> <head> <title>onscroll Event Handler</title> <script type="text/javascript"> function zipBackO { window.scrol1(0,0); } function init() { document.body.onscroll = zipBack; } </script> </head> <body onload="init()"> <hl>onscroll Event Handler</hl> <hr /> This page always zips back to the top if you try to scroll it. <p><iframe frameborder="0" scrolIing="no" height="1000" src= "bof right. htm" ></if ramex/p> </body> </html> См. также: свойства body.scrollTop, body.scrollLeft; методы srcolllnto- ViewO, body.doScroll (). Объект treewalker Свойства Методы Обработчики событий currentNode expandEntityReference filter firstChildO lastChildO nextNode() (нет) 609 Глава 18. Объекты document и body
Окончание таблицы Свойства Методы Обработчики событий root nextSibling() whatToShow parentNode() previousNode() previousSibling() Синтаксис Создание объекта TreeWalker. var treewalk = document.createTreeWalker(document, whatToShow, filterFunction, entityRefExpansion); Доступ к свойствам и методам объекта элемента TreeWalker такой. TreeWalker. свойство \ метод ( [параметры] ) Совместимость: Winffi-, MacIE-, NN7, Mozl+, Safari- Описание объекта Объект TreeWalker выступает контейнером для списка узлов, которые удовлетворяют критериям фильтрации. Указанные критерии задаются методом document. createTreeWalker (), который используется для создания объекта TreeWalker. Список узлов, содержащийся в объекте TreeWalker, полностью повторяет иерархическую структуру текущего документа. Этот объект используется для навигации по списку узлов, унаследовавших древообразную структуру. Представьте себе объект TreeWalker в виде указателя, поскольку основное его предназначение — это перемещение по списку узлов. Тем не менее, список представляет собой иерархически упорядоченную структуру, а не простой перечень элементов. Объект TreeWalker содержит указатель в списке узлов, всегда указывающий на "текущий узел". Таким образом, навигация с помощью объекта TreeWalker всегда выполняется относительно указателя. Например, ссылка на предыдущий или следующий узел с помощью методов previousNode () и nextNode () полностью зависит от расположения указателя в структуре. Используйте метод document. createTreeWalker () для создания объекта TreeWalker в текущем документе. Этот метод требует применения пользовательской функции, которая фильтрует узлы, включаемые в древовидную структуру. Ссылка на функцию представлена третьим аргументом метода. Данная функция возвращает константу, определяющую состояние текущего узла: NodeFilter.FILTER_ACCEPT, NodeFilter.FILTER_REJECT или NodeFilter.FILTER__SKIP. Разница между значениями NodeFilter.FILTER_REJECT и NodeFilter. FILTERJSKIP заключается в том, что зависящие от пропущенных узлы могут все еще рассматриваться как часть дерева, а отвергнутые узлы и зависящие от них узлы всегда исключаются из древовидной структуры. Следующая функция используется в процедуре создания объекта TreeWalker. function ratingAttrFilter(node) { if (node.hasAttribute("rating")) { return NodeFilter.FILTER ACCEPT; } return NodeFilter.FILTER REJECT; } 610 Часть III. Объекты документа
В этом примере только узлы, содержащие атрибут с именем rating, удовлетворяют условию фильтра, а потому только они добавляются в список (дерево). Имея в распоряжении эту функцию, вы можете вызвать в сценарии метод document. createTreeWalker () для создания объекта TreeWalker. var myTreeWalker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT/ ratingAttrFilter, false); После создания объекта TreeWalker можно использовать его методы и свойства для получения доступа к отдельным узлам и перемещения по списку узлов. Свойства currentNode Значение: ссылка на узел Чтение/Запись Совместимость: Winffi-, МасГЕ-, NN7+, Mozl+, Safari- Свойство currentNode возвращает ссылку на текущий объект, определяемый указателем объекта TreeWalker. Вы можете использовать это свойство не только для доступа к текущему узлу, но и для установки текущего узла. Пример Чтобы назначить текущий узел в соответствии с текущим расположением указателя в структуре, выполните выражение определения свойства currentNode. myTreeWalker.currentNode - document.getElementById("info"); См, также: свойство root. expandEntityReference filter root whatToShow Значение: см. текст Только для чтения Совместимость: Winffi-, МасШ-, NN7+, Mozl+, Safari- Эти свойства отражают атрибуты, которые подставляются в метод document .createTreeWalker (), создающий объект treeWalker. См. также: метод document. createTreeWalker (). Методы firstChildO lastChildO next Sibling () parentNode() previousSibling Значение: ссылка на узел Совместимость: Winffi-, MacIE-, NN7+, Mozl+, Safari- Глава 18. Объекты document и body 611
Эти методы возвращают ссылку на узел в древовидной структуре объекта TreeWalker. Они представляют дочерне-родительские отношения в упомянутой структуре узлов. При выполнении одного из этих методов указатель перемещается в указанное место, которое и становится в дальнейшем текущим. Пример Приведенный ниже код позволяет получить имя дескриптора родительского узла для текущего узла в объекте TreeWalker, if (myTreeWalker.parentNode()) { var parentTag = myTreeWalker.currentNode.tagName; } См. также: методы nextNode () и previousNode (). nextNode() previousNode() Значение: ссылка на узел Совместимость: WinlE-, MacIE-, NN7+, Mozl+, Safari- Эти методы используются для навигации по списку узлов, который содержится в объекте TreeWalker. Следует обратить внимание на то, что эти методы воспринимают древовидную структуру в виде "плоского" списка элементов, а потому используют внешние указатели на узлы. Пример Приведенный ниже код демонстрирует применение функции фильтрации узлов и простой функции отображения идентификаторов всех элементов объекта body (которым назначены атрибуты id). Метод nextNode () вызывается первым для установки указателя в первый элемент коллекции. Далее в конструкции do-while извлекаются и фильтруются все остальные элементы объекта. function idFilter(node) { if (node.hasAttributeC'id") ) { return NodeFilter.FILTER_ACCEPT; } return NodeFilter.FILTER_SKIP; } function showIdsO { var tw = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, idFilter, false); // проверка сохранения в TreeWalker по крайней мере одного узла if (tw.nextNode()) { do { alert(tw.currentNode.id); } while (tw.nextNode()); } } См. также: метод parentNode (). 612 Часть III. Объекты документа
Объекты ссылки и анкера eb базируется на простом принципе: любую информацию можно объединить в единое целое с помощью гиперссылок — специальных текстовых фрагментов или изображений, щелчок на которых перенаправляет браузер к необходимому для посетителя материалу или информации, которая поможет в дальнейших поисках интересующих его данных. Всеми объектами в документе управляет JavaScript; ссылка — это то, что задает связь между данными. Анкеры тоже представляют собой средство навигации, но только в пределах текущего документа, задавая места страницы, на которые можно перейти с помощью ссылок. Подобно тому, как объекты сценариев задают структуру документа, ссылки и анкеры определяют структуру Web. Но кажущаяся простота не уменьшает их важности в Web. Под управлением сценария ссылки могут стать намного более мощными инструментами, чем простое средство навигации в Web. В современных браузерах (Ш4+ и W3C) разделение элементов навигации на ссылки и анкеры привело к тому, что им стали соответствовать разные объекты во всех известных объектных моделях. Ключевое слово link далеко не всеми разработчиками сопоставляется с объектом документа из-за существования в объектной модели новых браузеров элементов link (см. главу 36), которые имеют совершенно иное предназначение в сценариях. Занимая место ссылки и анкера в объектной модели, этот объект HTML представляет собой элемент, созданный дескриптором <а>. Как объект элемента а, он получает все свойства, методы и обработчики событий, которые имеют любые HTML-элементы в современных объектных моделях. Вы найдете в этой главе описание всех трех типов объектов. При разработке страниц, которые должны быть совместимы с ранними версиями браузеров, необходимо' уделять особое внимание комментариям о поддержке свойств и обработчиков событий. W
Объекты элементов link, anchor и а Свойства, методы и обработчики событий этих элементов описаны в главе 15. Свойства Методы Обработчики событий charset coords hash host hostname href hreflang Methods mimeType name nameProp pathname port protocol protocolLong rel rev search shape target text type urn X _У Синтаксис Доступ к свойствам объекта link. (Все) [window.] document.links[индекс] .свойство Доступ к свойствам элемента а. (IE4+) [window. ] document .all. идентификатор. евойство \ метод ( [параметры]) (IE5+/NN6) [window. ] document. all.getElementByld ("идентификатор" ) . свойство | метод ( [параметры] ) 614 Часть III. Объекты документа
Описание объектов История создания сценария может вам помочь понять, как создавались объекты ссылки и анкера и какое участие в их образовании принимали элементы а. Используя терминологию базовой объектной модели, можно смело заявить, что объекты ссылки и анкера созданы на основе дескриптора <а>. Ссылку от анкера отличает присутствие атрибута href в дескрипторе. Если атрибут href отсутствует, элемент является объектом анкера, который (в браузерах до версии 4) не имеет свойств, событий и обработчиков событий. Даже в NN4 объект анкера получает только четыре свойства, из которых в NN6+/W3C остается только свойство name. Ссылка, с другой стороны, имеет гораздо больше характеристик объекта — как раз благодаря включению в нее атрибута href, который обычно указывает URL документа, загружаемого в окно или фрейм. Многие свойства объекта link в ранних объектных моделях подобны свойствам ранних объектов location— они содержат информацию об URL, присвоенному атрибуту href. Еще одной важной характеристикой объекта ссылки (особенно отличающей его от объекта анкера) является то, что ссылка может реагировать на события. Первоначально обработчиков событий у ссылки было только два: onclick и onmouseover. Начиная с NN4, к этому набору присоединились дополнительные обработчики события движений мыши и двойного щелчка ondblclick. Когда объектная модель обращается к HTML-элементам как к объектам (Ш4+ и NN6), объекты ссылок и анкеров представляются элементами а. Таким образом, до сих пор действительной остается одна важная особенность, которую имеют все объекты, — все элементы а, которые ведут себя как ссылки (благодаря присутствию атрибута href), являются членами массива document .links. Если сценарий требует проверки или изменения свойств всех ссылок на странице, то это реализуется в цикле for просмотра массива объектов ссылки. Это справедливо даже в том случае, если сценарий выполняется только в современных браузерах и в нем необходимо изменить атрибуты стилей всех ссылок (например, свойства style.textDecoration со значения попе на underline). Вышеупомянутый элемент может иметь совершенно разное поведение в зависимости от установленных атрибутов (что делает элемент а потенциально "двуликим" объектом). Поэтому внимательно задавайте ссылки и анкеры в процессе создания собственных сценариев, поскольку функциональное различие между ними намного больше, нежели синтаксическое. Начинающие пользователи часто ошибаются при задании атрибута target элемента а, когда определяют в сценарии ссылку на другой фрейм или окно. Согласно стандарту HTML, атрибут target указывает на окно или фрейм, в котором загружается новый документ (адрес которого присвоен атрибуту href), оставляя текущее окно или фрейм без изменений. Если вы хотите использовать обработчик события для навигации к другому документу (с помощью свойства location.href), то атрибут target в этой ситуации останется невостребованным в сценарии. Вместо этого свойству location.href соответствующего окна или фрейма определяется URL необходимого документа. Например, если один фрейм содержит таблицу с данными, целиком состоящими из ссылок, то обработчик события onclick этих ссылок может загружать другие страницы во фрейм main после присвоения соответствующего URL свойству parent .main, location.href. При этом также необходимо отменить стандартное поведение ссылки (см. описание обработчика события onclick в главе 15). Если при щелчке на ссылке (добавленной к текстовому фрагменту или изображению) необходимо инициировать действие, отличное от перехода к странице с другим URL, следует использовать специальную методику—задайте оператор javascript:псевдо-URL, который с помощью URL вызывает функцию JavaScript. Адрес javascript гимяФункции() является допустимым значением атрибута href (а не только объекта ссылки). Браузеры, в которых JavaScript не поддерживается, никак не реагируют на щелчок на подобной ссылке. Глава 19. Объекты ссылки и анкера 615
Если необходимо, чтобы ссылка принимала участие только в изменении содержимого строки состояния, выполняемого в обработчике события onmouseover, то создайте пустую функцию и определите ей в JavaScript адрес URL (например href =" j avascript: voidsomeFunct ion {) "). Начиная с NN3 и Ш4, можно также добавить специальный оператор void, который гарантирует, что созданная пустая функция не будет выпрлнять стандартное для ссылки действие (href=" javascript .-voidsomeFunction () ")• Задание пустой строки в атрибуте href приводит к отображению FTP-структуры файлов текущего клиентского компьютера — весьма нежелательный побочный эффект. Не следует также забывать и о том, что если URL указывает на файлы, которые запускаются вспомогательными приложениями браузера (например звуковые файлы RealAudio), то внедряемый модуль или надстройка загружаются автоматически, а указанный файл воспроизводятся без изменения текущей страницы в окне браузера. Одна ссылка, заданная с помощью JavaScript, может изменить содержимое более чем одного фрейма сразу. Если вы хотите, чтобы только браузеры, поддерживающие JavaScript, реагировали на щелчок на подобной ссылке, используйте выражение javascript тсевдо-ШЬ, в котором вызывается функция, изменяющая свойство location.href нескольких фреймов. Например, рассмотрим следующую функцию, которая изменяет содержимое двух фреймов. function navFrames(urll, url2) { parent.product.location.href = urll; parent.accessories.location.href = url2; } Полученная многоцелевая функция вызывается с помощью выражения javascript: леев до - URL, и ей передаются специфические параметры ссылок. <а href="javascript: void navFrames('products/gizmo344.html', 'access/access344.html•)">Deluxe Super Gizmo</a> Если необходимо, чтобы ссылка выполняла определенные действия в любых браузерах и в то же время инициализировала специальные операции в JavaScript-браузерах, совместите стандартное поведение ссылки с обработчиком события onclick, обеспечив поддержку этих двух ситуаций. function setAccessFrame(url) { parent.accessories.location.href = url; } <a href="products/gizmo344.html" target="product" onclick="setAccessFrame('access/access344.html')">Deluxe Super Gizmo</a> Заметьте, что атрибут target определяет стандартное поведение ссылки в то время, как 'сценарий присваивает URL свойству location. href фрейма. Один дополнительный метод позволяет отдельному дескриптору ссылки выполняться в любых браузерах, поддерживающих и не поддерживающих сценарии (NN3+ и Ш4+). Для браузеров, не поддерживающих сценарии, задание настоящего URL проводится в ссылке. В этом случае обработчик события onclick ссылки должен заканчиваться оператором return false. Во время щелчка на ссылке браузер, поддерживающий сценарии, выполняет обработчик события и игнорирует атрибут href; браузер, не поддерживающий сценарии, не выполняет обработчик события и следует ссылке. Более детально этот вопрос рассмотрен при описании обработчика события onclick в главе 15. В процессе создания ссылок не избегайте использования обработчиков события onmouseover и onmouseout в соответствующем операторе ссылки. В общем случае эти обработчики событий применяются для определения значения свойства window, status или установки состояний ролловера. (Раньше элементы img не имели собственных обработчиков событий, поэтому они заключались внутрь элементов а, для которых обработчики события были зада- 616 Часть III. Объекты документа
ны с первого дня существования). В таком случае, когда пользователь наводит указатель мыши на ссылку, специальное сообщение (более детальное и содержательное, нежели текст или изображение самой ссылки) появляется в строке состояния в основном окне. Заметит пользователь представленное ему сообщение или нет — это отдельная тема для разговора, поэтому не особо полагайтесь на строку состояния как средство взаимодействия с посетителями. Изменение изображения, однако, более заметно; оно обеспечивает пользователя обратной связью, которая осуществляется при наведении указателя на значок кнопки. Благодаря обработчику события onmousedown возможной становится даже загрузка изображения при наведении указателя мыши на него или специальную ссылку. Свойства charset Значение: строка Чтение/Запись Совместимость: Winffi6+, МасГЕ6+, NN6+, Mozl+, Safaril+ Свойство charset представляет собой атрибут charset, используемый в HTML 4.0 для элемента а. Это свойство задает в браузере набор символов, используемых для отображения документа, который указан в атрибуте href. Значение этого свойства— один из наборов символов, с которыми вы можете ознакомиться по адресу ftp://ftp.isi.edu/in- notes/iana/assignments/character-sets. coords shape Значение: строка Чтение/Запись Совместимость: Winffi6+, Macffi6+, NN6+, Mozl+, Safari 1+ В описании элемента а в HTML 4.0 указано, что ссылка может добавляться к изображению разной формы (прямоугольной, круглой и многоугольной); в этом случае необходимо задать координаты области, для которой задается ссылка. Свойства coords и shape элемента а представлены в NN6 (как и в W3C DOM), однако их активная поддержка все еще не реализована. hash host hostname pathname port protocol search Значение: строка Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Этот большой набор свойств тождественен подобным по имени свойствам объекта location (см. главу 17). Все свойства являются компонентами URL, который задается в ссылках с помощью атрибута href объекта. Ни одно из этих свойств не указано в спецификации W3C DOM для элемента а, однако они продолжают поддерживаться в современных браузерах для обес- Глава 19. Объекты ссылки и анкера 617
печения обратной совместимости. Если вам необходимо изменить адрес в ссылке, преобразуйте значение свойства href, а не отдельные компоненты URL. См. также: объект location. href Значение: строка Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ Свойство href (поддерживается W3C DOM)— это URL конечного документа, на который указывает элемент а, используемый в качестве ссылки. Адреса URL могут быть относительными или абсолютными. В ГЕ4+ и NN6 вы можете преобразовать объект анкера в объект ссылки, добавив значение свойству href даже в том случае, когда элемент а в HTML не имеет атрибута href. Конечно, это преобразование является временным; оно справедливо до того момента, пока страница загружается в браузер. При задании значения свойству href элемента а, в который включен текст, этот текст преобразуется в ссылку (текст принимает как стандартный для ссылок вид, так и специальный, указанный в таблицах стилей). См. также: объект location. hrefLang Значение: строка Чтение/Запись Совместимость: Winffi6+, MacIE6+, NN6+, Mozl+, Safari 1 + Свойство href Lang информирует браузер (если браузер его поддерживает) о языке, используемом для представления содержимого документа, на который указывает атрибут href элемента а. Значения этого свойства представлены в виде двухсимвольного кода языка (например, en-us для американского английского). Methods Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Свойство Methods (обратите внимание на заглавную букву "М") представляет собой атрибут methods элемента а в HTML 4.O. Значения этого атрибута и свойства служат в качестве рекомендаций для браузера, в которых указано, какие HTTP-методы лучше использовать для доступа к указанному документу. Практически всегда атрибут HTML 4.0 повторяется в W3C DOM. Несмотря на то, что Ш4+ поддерживает это свойство, предоставляемая им информация в этих браузерах никак не используется. mimeType Значение: строка Только для чтения Совместимость: WinIE4+, МасГЕ-, NN-, Moz-, Safari- Введенное в Г£4 (но не в МасШ4) свойство mimeType по-прежнему поддерживается в Ш5, но это, по всей видимости, последний браузер, в котором оно будет использоваться. HTML 4.0 и W3C DOM спецификации вместо него представляют атрибут type и свойство type. Возможно, это свойство было задумано как рекомендательное, чтобы позволить браузеру предварительно "ознакомимся" с типом MIME. В сценарии соответственно типам МГМЕ можно задавать ветвление, устанавливая разные типы указателей мыши в зависимости от объекта, на который наводится указатель мыши. Свойство не обладает возможностью управления типом MIME загружаемого документа. 618 Часть III. Объекты документа
name Значение: строка Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Пока атрибут name является необязательным для элемента а, являясь только объектом ссылки, в объекте анкера без него просто не обойтись. Этой величиной управляет в сценарии свойство name. Свойство можно применить как средство определения объекта ссылки в массиве document. links, используя цикл для его просмотра. for (var i = 0; i < document.links.lenght ; i++) { if (document.links [i].цате == "bottom" { // операторы управления ссылкой с именем "bottom" } } nameProp Значение: строка Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство name Prop, специфическое для IE, удобно использовать для получения фрагмента href, расположенного справа от крайнего правого символа наклонной черты (слеша) в URL. Чаще всего его значение является именем файла, указанного в URL. Но если URL также содержит номер порта, то он тоже возвращается как часть значения name Prop. protocolLong Значение: строка Только для чтения Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Свойство protocolLong, специфическое для Ш, возвращает подробное значение свойства protocol для атрибута href элемента а. Например, если атрибут href указывает на использование протокола http, то свойство protocolLong возвращает HyperText Transfer Protocol. Введенное в Г£4 (но не в Мас1Е4) свойство protocolLong, по-прежнему поддерживается в Ш5, но, по-видимому, в следующих версиях оно реализовано не будет. rel rev Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойства rel и rev определяют связь в обратном и прямом направлениях относительно документа, указанного в элементе а. Браузеры до сих пор используют большую часть потенциала этих атрибутов и свойств. Длинный список значений, заранее определенных для этих свойств, основывается на соответствующих величинах атрибутов, которые определяются в HTML 4.O. Если браузер не использует определенное значение, то оно игнорируется. Можно объединить вместе несколько значений в виде отдельной строки. Допускается использовать следующие значения. alternative contents index start appendix copyright next stylesheet bookmark glossary prev subsection chapter help section Глава 19. Объекты ссылки и анкера 619
target Значение: строка Чтение/Запись Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safaril+ Важным свойством объекта ссылки является target. Эта величина указывает на имя окна, заданное атрибутом target в элементе к. Можно временно изменить целевой объект ссылки. Однако, как и со многими другими свойствами кратковременных объектов, заданные значения удаляются при мягкой перезагрузке. Вместо изменения целевого объекта, подобным образом можно безопасно указать цель, задав в атрибуте href значение javascript rfunctionName О — псевдо-URL, в котором с помощью функции документ загружается в соответствующем окне, определенном в свойстве window, location. Если вы часто используете в своем документе атрибуты HTML, то избежать использования атрибута target может оказаться весьма проблематично. См, также: свойство document. links. text Значение: строка Только для чтения Совместимость: WinlE-, Macffi-, NN4, Moz-, Safari- Между открывающим и закрывающим дескрипторами ссылки указывается текст (или изображение), который выделяется цветом, характерным для ссылки в документе. NN4 предоставляет возможность получить этот текст с помощью свойства link. text. Это свойство предназначено только для чтения. В более поздних версиях браузеров — ГЕ4+ и/или W3C DOM — для получения текста узла ссылки используются специальные свойства (innerText, innerHTML и nodeValue) элемента а. Это свойство не реализовывалось в NN4, который выпущен перед версией 4.02. type Значение: строка Чтение/Запись Совместимость: WinIE6+, МасГЕ6+, NN6+, Mozl+, Safari 1+* Свойство type представляет собой атрибут type в HTML 4.0, который задает тип МГМЕ содержимого указанного документа, на который указывает атрибут href элемента а. Первоначально это свойство предназначалось для использования в рекомендательных целях для браузера, которому необходимо знать, например, какой указатель мыши использовать при отображении документа, на который указывает ссылка. До сих пор браузеры не используют преимущества этого свойства. Однако значение типа MIME можно задать в атрибуте (например video/mpeg), чтобы впоследствии использовать его в сценариях для соответствующего стилевого изменения текста ссылки после загрузки страницы. ЕЕ4+ представляет это свойство как mimeType. См. также: свойство mimeType urn Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- 620 Часть III. Объекты документа
Свойство urn представляет собой атрибут urn, специфический для Г£, он позволяет разработчикам использовать URN (Uniform Resource Name —г Универсальное имя ресурса) для указания места назначения элемента а (см. http: //www. ietf . org/rf c/rf c2141. txt). Это свойство не приспособлено для массового пользования. X У Значение: строка Только для чтения Совместимость: WinlE-, МасГЕ-, NN4, Moz-, Safari- Сценарий в NN4 может получать координаты х и у объекта ссылки (верхний правый угол прямоугольного пространства, занимаемого текстом или изображением ссылки) с помощью свойств link.x и link.у. В Ю4+ и NN6+/W3C получить координаты типичной ссылки можно с помощью свойств offset Left и of f set Top элемента а. Глава 19. Объекты ссылки и анкера 621
Объекты изображения, области и карты изображений зображения и карты изображений являются высокоуровневыми объектами, созданными для браузеров NN3+ и ГЕ4+ с помощью дескрипторов <img> и <агеа>; они используются в сценарии для обеспечения его интерактивности. Изображение, указанное в дескрипторе <img>, можно заменить другими изображениями (это относится только к изображениям одинакового размера в NN3 и NN4). Чтобы разнообразить визуальное представление страницы, можно использовать эффект подсвечивания кнопки со значком в момент наведения на нее указателя мыши. Использование клиентских карт изображений поможет вам сделать ваши страницы "интеллектуальнее" в ответ на щелчки пользователя на каком-либо графическом объекте. Заметьте, что разработчик сценария имеет возможность отобразить изображения предварительно, во время загрузки всей страницы. Применение кэшируемых изображений позволяет избежать временной задержки при смене одного изображения другим. Изображения и элементы img Свойства, методы и обработчики событий этого HTML- элемента описаны в главе 15. и
Свойства Методы Обработчики событий align onabort alt onerror border onload complete dynsrc fileCreatedDate fileModifiedDate fileSize fileUpdatedDate height href hspace isMap loop longDesc lowsre mimeType name nameProp naturalHeight naturalWidth protocol sre start useMap vspace width x _У Синтаксис Создание объекта image. imageName = new Image([ширина, высота]); Доступ к свойствам и методам элемента img и объекта image. (NN3+/IE4+) [window. J document. имяИзображеиия. свойство \ метод ( [параметры] ) (NN3+/IE4+) [window. ] document. images [индекс] . свойство \ метод ( [параметры] ) (NN3+/IE4+) [window. ] document. images [ "имяИзображеиия" ] . свойство \ метод ( [параметры] ) Глава 20. Объекты изображения, области и карты изображений 623
(IE4+) [window. 3 document. al 1. идентификатор. свойство | метод ( [параметры]) (IE5+/W3C) [window. ] document. getElementByld ( "идентификатор") . свойство | метод ( [параметры] ) Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ Описание объекта Прежде чем приступить к описанию изображений как объектов, необходимо четко представить разницу между образцами статического объекта Image и объектом элемента img. Статический объект Image существует только в памяти браузера. Пользователю он ничего на экране не отображает. Элементы img — это объекты на странице, сгенерированной с помощью дескриптора <img> (формально не оговоренный, но допустимый вариант дескриптора <image>). В сценариях объекты Image используются с целью предварительного кэширования изображений на странице; вполне очевидно, что они имеют меньшее количество соответствующих свойств, методов и обработчиков событий, потому что они невидимы на странице и на них не влияют атрибуты, установленные в дескрипторе. Элементы img присутствуют в словаре ключевых слов HTML довольно давно. Но NN3 был первым, кто стал обращаться с ними как с равноправными объектами (наряду с объектом Image), используя для предварительного кэширования изображений. МасЕЕ3.01 обеспечивает частичную поддержку обоих вариантов (предварительное кэширование и смена изображения), а все версии IE4+ рассматривают элементы img как полноценные объекты. Одним из самых главных преимуществ управления img-элементом как объектом является возможность замены изображения, которое представлено на странице даже после загрузки документа и отображения в браузере исходного рисунка. Эта задача выполняется с помощью свойства src изображения. В типичном сценарии страница загружается с начальным изображением. Дескрипторы изображения задают любые дополнительные атрибуты изображения, например, height и width (которые помогают ускорить отображение страницы), и определяют, используется ли в рисунке клиентская карта изображения, предоставляющая пользователю дополнительную интерактивность (см. описание объекта area ниже в этой главе). Пока пользователь просматривает страницу, изображение может измениться (в ответ на действие пользователя или вследствие анализируемого в сценарии события); оно заменяет исходное изображение на новое в той же самой области. В браузерах ТЕЛ и NN6, которые поддерживают объект img, высоту и ширину начального изображения представляет прямоугольник фиксированного размера, за рамки которого изображение "выйти" не может. Преобразование изображения с целью обеспечения соответствия выделенной для него области приводит к необходимости масштабирования. Но в ГЕ4+ и NN6+ изменение размера изображения приводит к автоматической перезагрузке содержимого страницы уже другого размера. Преимущество отдельного объекта Image состоит в том, что с его помощью в сценарии создается виртуальное изображение, в котором удерживается предварительно загруженное изображение. (Изображение загружается в кэш-память, но браузер в начальный момент его не отображает.) Одно или несколько скрытых изображений загружаются в память, в то время как пользователь занят просмотром страницы или ожиданием ее загрузки. Впоследствии в ответ на действия пользователя изображение может отображаться (или изменяться) мгновенно, что избавит посетителя от дополнительных ожиданий. Предварительная загрузка изображения начинается с назначения нового, пустого объекта изображения глобальной переменной. Новое изображение создается с помощью конструктора объекта Image. var переменнаяОбъекта = new Image {ширина, высота); 624 Часть III. Объекты документа
Чтобы помочь браузеру выделить необходимую память для изображения, необходимо передать в сценарий информацию о высоте и ширине изображения (в пикселях) в виде параметров. В результате этого в памяти создается объект, свойства которого не инициализированы. Чтобы заставить браузер загрузить изображение в кэш-память, назначьте файл изображения URL свойству src объекта. var oneImage = new Image(55,68); onelmage.src = "neatlmage.gif"; В процессе загрузки изображения в строке состояния отображается диаграмма загрузки, как для любого другого файла. После этого необходимо приравнять свойство src предварительно загружаемого изображения к свойству src объекта элемента img, который отображается на странице. document.images ["somelmage"].src = onelmage.src; В зависимости от типа и размера изображения вы будете удивлены быстрой реакцией на, отображение предварительно загруженного изображения. Графические объекты с небольшой палитрой цветов отображаются на экране в этом случае практически мгновенно. Чтобы усовершенствовать пользовательский интерфейс документа, добавьте на страницу изображение в виде активной кнопки, изменяемой при наведении на него указателя мыши. В этом случае предполагается, что генерируется соответствующее событие мыши, которое и активизирует элемент, связанный с объектом. До появления IE4 и NN6 объекты элемента img не отвечали на события (щелчки) мыши. Описанный выше эффект требует вставки img- элемента внутрь элемента а. Это действие позволяет событиям onmouseover, onmouseout и onclick, связываемым с изображением, вызывать определенное действие (обычно переход к другой странице). Если IE4+ и NN6+ задают эти события непосредственно в объектах элемента img (чтобы гарантировать, что все страницы будут обратно-совместимыми с другими версиями браузеров), то необходимо обязательно включить их внутрь элементов А. Примеры использования изображений можно найти в главах 12 и 20. Ролловеры обычно могут находиться в двух различных состояниях: нормальном и активном. У вас может появиться желание увеличить число таких состояний, чтобы более гибко моделировать работу графических кнопок. В некоторых случаях используется третье состояние, определяющее нажатую кнопку. Например, если вы используете ролловер в одном фрейме для представления Web-страниц в другом фрейме, и пользователь щелкает на кнопке перехода к разделу Products, то эта кнопка остается в активной, но в состоянии, отличном от представляемых ролловером. Некоторые разработчики идут дальше, обеспечивая четвертое, временное, состояние, задаваемое в процессе загрузки изображения. Каждое из этих состояний требует загрузки в документ своего изображения. Чем больше состояний ролловера используется, тем меньшим будет эффект задержки отображения изображений при использовании предварительной загрузки страницы. Скорость, с которой происходит замена предварительно загруженных изображений, наводит на мысль об использовании этого метода для добавления на страницу анимации. Несмотря на то, что этот метод и применяется для добавления коротких анимационных клипов, многие другие способы создания анимационных движений на вашей Web-странице (с помощью графического формата GIF89a или Java-аплетов) обеспечивают более высокую эффективность. Смена предварительно загруженных объектов изображений в JavaScript для получения анимационных эффектов может быть очень быстрой. Поэтому при их использовании необходимо в обязательном порядке создать механизм задержки, реализуемый с помощью метода set Interval (). При этом точная синхронизация кадров будет напрямую зависеть от производительности процессора. Все браузеры, которые поддерживают объект элемента img, вместе с ним поддерживают массив document. images. Можно (и следует) использовать этот массив как условие поддержки объектов элементов img в любых операторах сценария, которые управляют изображениями. Глава 20. Объекты изображения, области и карты изображений 625
if (document.images) { // Операторы, управляющие изображениями как объектами) } Более ранние браузеры воспринимают отсутствие этого массива как эквивалент значения false в условной инструкции if. Свойства, обсуждаемые ниже, представляют атрибуты элемента img. Для получения более детальной информации о значениях и использовании атрибутов обратитесь к документации по спецификации HTML4.0 (http://www.w3 .org/TR/REC-html40) и расширений Microsoft для Ш (http: //msdn.microsoft. com/workshop/author/dhtml/reference/ objects/img.asp). Свойства align Значение: строка Чтение/Запись Совместимость: Winffi6+, Macffi6+, NN6+, Mozl+, Safari 1+ Свойство align определяет, как изображение располагается относительно окружающего его текста. Это свойство двойного назначения, так как его можно использовать для управления вертикальным или горизонтальным выравниванием, в зависимости от значения (и значения атрибута стиля float для данного изображения). В качестве значений этого свойства используются следующие строковые константы. absbottom middle absmiddle right baseline texttop bottom top left Выравнивание, заданное для изображения по умолчанию, — bottom. Все чаще выравнивание задается с помощью стилей. В Safari поддерживаются только варианты left и right. Пример В листинге 20.1 приведен пример использования свойства al ign и его влияние на макет документа (расположение текста вокруг изображения на HTML-странице). Измените размер окна браузера, чтобы увидеть, как при этом изменяется способ обтекания текстом графических объектов. Каждый браузер по-своему устанавливает параметр align в рассматриваемых случаях. chtml> <head> <title>img align Property</title> ocript type="text/javascript"> function setAlignment(sel) { document.getElementById("mylMG").align = sel.options[sel.selectedlndex].value; } </script> </head> <body> 626 Часть III. Объекты документа
<hl>img align Property</hl> <hr /> <form> Choose the image alignment: <select onchange= "setAlignment (this) "> <option value="absbottorn">absbottom</option> <option value=f,absmiddle">absmiddle</option> <option value="baseline">baseline</option> <option value="bottom" selected*"selected">bottom</option> <option value="left">left</option> <option value="middle">middle</option> <option value="right">right</option> <option value="texttop">texttop</option> <option value="top">top</option> </select> </form> <hr /> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod temper incididunt ut labore et dolore magna aliqua. <img alt="image" id="myIMG" src="deskl.gif" height="90" width="120" /> Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p> </body> </html> См. также: атрибуты стиля float, text-align. alt Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство alt позволяет задавать или изменять текст, который браузер отображает в прямоугольном заполнителе изображения (если его высота и ширина определены) перед тем как в нем отобразится изображение. Если в браузере отключено отображение рисунков (или браузер не способен отображать изображения), то текст свойства alt поможет пользователям идентифицировать изображение, которое обычно представлено в текущей области страницы. Альтернативный текст можно изменять даже после загрузки страницы. Пример Используйте приложение The Evaluator для изучения свойства alt объекта изображения document. myImg. Сначала назначьте свойству src несуществующее изображение, чтобы удалить в документе текущее изображение. document.myIMG.src = "fred.gif" Прокрутите страницу к изображению, и вы сможете увидеть занимаемое им место в документе. Теперь задайте значение свойства alt. document.mylMG.src = "Fred\■s face" Обратная косая черта используется для вывода апострофа в текстовой строке. Прокрутите страницу еще раз, чтобы ознакомиться с заменяющим изображение текстом. См. также: свойство title. border Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN3+, Mozl+, Safari 1+ Глава 20. Объекты изображения, области и карты изображений 627
Свойство border определяет толщину в пикселях границы вокруг изображения. Помните: если поместить изображение внутрь элемента а, чтобы впоследствии использовать события мыши (в ролловерах и т.д.), то необходимо убедиться в том, что атрибут border дескриптора <img> имеет нулевое значение. В результате вы не допустите генерирования обычной границы вокруг изображения. Даже при том, что по умолчанию значение атрибута нулевое, помещение изображения в элемент а или вставка изображения в клиентскую карту изображения вызывает добавление границы вокруг изображения. Пример Постарайтесь максимально детально изучить свойство border объекта document. my IMG, воспользовавшись приложением The Evaluator. Это свойство принимает самые различные целочисленные значения. См. также: свойства isMap, useMap. complete Значение: булево Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Иногда необходимо удостовериться, что загрузка изображения не происходит (например, перед выполнением другой задачи). Данная ситуация в корне отличается от проверки полной загрузки изображения, требуемой для выполнения определенного процесса (который задается в обработчике события onload для объекта изображения). Гарантией того, что объект img содержит все изображение, выступает значение свойства complete. Чтобы убедиться в полной загрузке графического файла, проверьте, является ли значение свойства complete истинным (т.е. равным true); после этого сравните значение свойства src с требуемым именем файла. Свойство complete изображения принимает значение true, даже если указанное изображение загружено в формате lowsrc. He полагайтесь только на это свойство для определения загруженности изображения. Обязательно проверьте свойство src или lowsrc, если оно определено в дескрипторе <img>. Один из лучших путей применения этого свойства заключается в использовании условной инструкции if. if (document.myImage.complete) { // операторы, которые выполняются с объектом document. myImage I Свойство complete нельзя назвать надежным в NN4 и некоторых версиях IE. /назаметку Для этих браузеров это свойство возвращает true в любых случаях. Пример Чтобы ознакомиться со свойством complete, завершите работу и заново запустите браузер. Далее загрузите в нем документ, представленный листингом 20.2 (изображения расположены в кэше браузера). В процессе загрузки изображений щелкните на кнопке Is it loaded yet?, чтобы ознакомиться с состоянием свойства complete объекта image. Значение false сохранится в этом свойстве до тех пор, пока изображение не будет загружено. В противном случае будет установлено значение true. Изображение скалы несколько больше фотографии клавиатуры. Для очистки кэша завершите работу в браузере и заново загрузите его. Если у вас возникают трудности с использованием этого свойства в сценариях, то попробуйте применить обработчик onload дескриптора <img>. 628 Часть III. Объекты документа
Листанг20.2^ <html> <head> <titlex/title> <script type="text/javascript"> function loadlt(thelmage,form) { form.result.value = ""; document.images[0].src = theImage; } function checkLoad(form) { form.result.value = document.images[0].complete; } </script> </head> <body> <img alt="image" src=Mcpu2.gif" width="12 0" height="90" onload="" /> <form> <input type="button" value="Load keyboard" onclick=MloadIt('cpu2.gif',this.form)" /> <input type="button" value="Load arch" onclick="loadIt('arch.gif',this.form)" /> <p><input type="button" value="Is it loaded yet?" onclick="checkLoad(this.form)" /> <input type="text" name="result" /></p> </form> </body> </html> См. также: свойства img.src, img.lowsrc, img.readyState; обработчик события onload. dynsrc Значение: строка URL Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство dynsrc — это URL исходного видеофайла, который (в Ш) можно воспроизвести с помощью элемента img. Используйте область, отведенную статическому изображению для отображения видеоклипа, указав URL видеофайла (например . avi или . mpg файлов) в свойстве dynsrc объекта изображения. В отличие от свойства src объектов изображений, определение URL в свойстве dynsrc не позволяет провести предварительную загрузку видеоклипа. После того, как элемент img отобразит изображение . gif или . jpg, будет рисковано задавать в нем свойство dynsrc. В такой ситуации можно столкнуться с ошибками в ранних версиях Ш. В WinIE5 строка состояния указывает на то, что видеофайл все еще загружается, даже если загрузка уже завершена. Щелчок на кнопке Stop никак не повлияет на сложившуюся ситуацию. WinIE5.5 даже может проигнорировать видеофайл, оставив область страницы пустой. В МасШ5 переход от статического к динамическому изображению происходит без особых проблем, но при многократном воспроизведении видеофайла в элементе img область за пределами прямоугольника окрашивается в черный цвет (см. листинг 22.3). Ни одна из этих ошибок не фатальна, но они должны предостеречь вас от использования элемента img при передаче видеосодержимого. Глава 20. Объекты изображения, области и карты изображений 629
Пример Переход от статического изображения к динамическому выполняется с помощью всего одного свойства. В листинге 20.3 показан простой пример подобной операции, заключающейся в изменении свойства dynsrc. Как и следовало ожидать, этот код имеет все недостатки, описанные выше. <html> <head> <title>img dynsrc Property</title> <script type="text/javascript"> var trainlmg = new Image(160,120); trainlmg.src = "amtrak.jpg"; trainlmg.dynsrc = "amtrak.mpg"; function setLoopO { var selector = document.forms[0].looper; document.getElementByld("myIMG").loop = selector.options[selector.selectedlndex].value; } function setImage(type) { if (type == "jpg") { document.getElementByld("mylMG").dynsrc = ""; document.getElementById('■ mylMG") .srс = trainlmg.src; } else { document.getElementByld("mylMG").src = ""; document.getElementByld("mylMG").start = "fileopen"; setLoop(); document.getElementByld("mylMG").dynsrc = trainlmg.dynsrc; </script> </head> <body> <hl>img dynsrc Property</hl> <hr /> <form> Choose image type: <input type="radio" name="imgGroup" checked="checked" onclick="setImage('jpg')" />Still <input type="radio" name="imgGroup" onclick="setImage('mpg*)" /> Video <p>Play video how many times after loading: <select name="looper" onchange="setLoop()"> <option value="l" selected="selected">Once</option> <option value="2">Twice</option> <option value="-l">Continuously</option> </selectx/p> </form> <hr /> <img alt="image" id="myIMG" src="amtrak.jpg" height="12 0" width="160" /> </body> </html> См. также: свойства img. loop, img. start. 630 Часть III. Объекты документа
fileCreatedDate fileModifiedDate fileUpdateDate fileSize Значение: строка, целочисленное значение (fileSize) Чтение/Запись Совместимость: WinIE4+, МасГЕ5+, NN-, Moz-, Safari- Эти три свойства в IE возвращают информацию о файле, отображаемом в элементе img (в случаях статического и динамического содержимого). Два из этих свойств содержат даты создания и изменения текущего изображения. Для статического (неизменяемого) файла даты создания и изменения — одни и те же. Свойство fileSize показывает размер в байтах текущего файла. Значения даты, возвращенные первыми двумя свойствами, форматируются по-разному в Ш4 и Ш5. ВЕ4 обеспечивает полный формат представления времени и даты; Ш5 возвращает их в формате, подобном mm/dd/yyyy. Обратите внимание, однако, что возвращаемые значения содержат только дату, но не время. В любом случае, вы можете использовать эти значения как параметр в функции-конструкторе new Date (). Это позволит использовать дату для получения такой информации, как число дней между текущим днем и датой последнего изменения файла. Не все серверы предоставляют корректные сведения о датах создания и изменения файла или возвращают их в формате, который IE может интерпретировать. Проверьте эти характеристики на интересующем вас сервере, чтобы убедиться в его совместимости с создаваемыми вами документами. Примите во внимание, что эти свойства доступны для чтения только в случае, когда файл загружен в браузер. JavaScript самостоятельно не может получить информацию о файлах на сервере, которые не загружены в браузер. Й Все свойства, предоставляющие сведения о файлах, поддерживаются в IE для /нашил? Мае, но при этом возвращаемые ими значения будут пустыми. Пример Эти свойства подобны свойствам управления именами объекта document. Вы можете ознакомиться с примером их использования в листинге 18.4. Скопируйте этот листинг и создайте изображение, перед тем как заменять ссылку на объект изображения из объекта документа. Детально изучите свойства объекта элемента img. height width Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ Свойства height и width возвращают, а в более поздних браузерах задают высоту и ширину объекта изображения в пикселях. Свойства доступны только для чтения в NN3 hNN4, но во всех остальных браузерах, поддерживающих объект элемента img, они представлены в режиме чтения и записи. Если вы изменяете свойство высоты изображения, браузер автоматически сохраняет пропорции изображения, заданные исходными размерами оригинала. Но изменение свойства ширины никак не влияет на свойство высоты в большинстве версий браузеров. Масштабирование изображения может вызывать нежелательные искажения, поэтому выполняйте его с чрезвычайной осторожностью. Глава 20. Объекты изображения, области и карты изображений 631
Пример Используйте приложение The Evaluator для изучения свойств height и width. Начните с получения значений по умолчанию, введя в верхнее текстовое поле следующие выражения. document.myIMG.height document.myIMG.width Увеличьте высоту изображения в два раза. document.myIMG.height = 180 Если вы прокрутите страницу, то увидите, что изображение сохранило свои пропорции. Далее измените ширину изображения. document.myIMG.width = 400 Просмотрите полученный результат. См. также: свойства hspace, vspace. href См. src. hspace vspace Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Свойства hspace и vspace управляют полем в виде прозрачной границы, окружающей изображение; его значения задаются в пикселях. Свойство hspace управляет отображением полей в верхней и нижней частях изображения, vspace — в левой и правой. По умолчанию изображения имеют значение поля, равное нулю пикселей. Пример Приложение The Evaluator также позволяет ознакомиться и со свойствами hspace и vspace. Сначала изучите изображение в левой нижней части страницы — оно не имеет границ и привязано к левому полю документа. Теперь установите отступ — 30 пикселей. document.mylMG.hspace =30 Как видите, изображение сместилось вправо на 30 пикселей. См. также: свойства height, width. isMap Значение: булево Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство isMap позволяет определить, должно ли изображение восприниматься как карта изображения на стороне сервера. Когда свойство определяет рисунок в качестве карты изображения на стороне сервера, координаты пикселя, на котором производится щелчок мышью, передаются как параметры ссылке href, в которую включено изображение. Клиентские карты изображения описаны в свойстве useMap далее в этой главе. 632 Часть III. Объекты документа
Пример Изображение в приложении The Evaluator не настроено в качестве карты изображения. Поэтому если ввести в верхнее текстовое поле следующее выражение, то будет возвращено значение false. document.myIMG.isMap См. также: свойство img. useMap. longDesc Значение: URL-адрес Чтение/Запись Совместимость: Winffi6+, Macffi5+, NN6+, Mozl+, Safari 1+ Свойство longDesc — это URL файла, который предназначен для предоставления детального описания изображения, вставленного в элемент img. NN6+ распознает это свойство, однако браузер не применяет полученную информацию для решения определенных задач — независимо, от того задана она в сценарии или с помощью атрибута longdesc. loop Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство loop определяет количество воспроизведений видеоклипа, отображаемого с помощью объекта элемента img. После воспроизведения клипа указанное количество раз в области изображения будет отображаться только первый его кадр. Значение свойства по умолчанию 1; но если установить значение -1, то видеоклип будет воспроизводиться непрерывно. К сожалению, установка свойства в значение 0 до задания свойства dynsrc не предотвращает воспроизведения видеофайла по крайней мере единожды (кроме браузеров для Мае, как отмечалось при описании свойства dynsrc ранее в этой главе). Пример Пример использования свойства loop приведен в листинге 20.3, который уже рассматривался при изучении свойства dynsrc. См. также: свойство dynsrc. lowsrc lowSre Значение: строка URL Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Для файлов изображений, которые загружаются в течение десяти и более секунд, в последних версиях браузеров определяются копии с низким разрешением или быстро загружающиеся заполнители, которые "бронируют" место для изображения, в то время как оно само загружается в браузер. Это альтернативное изображение задается в атрибуте lowsrc • дескриптора <img>. Такой атрибут представлен свойством lowsrc объекта изображения. Все поддерживающие его браузеры признают только версию этого свойства, введенную в нижнем регистре. Но W3C DOM спецификация гарантировано распознает только вариант lowSrc. NN6 также признает только эту версию. Помните, если вы назначаете URL атрибуту lowsrc, то свойство complete принимает значение true, и обработчик события onload активизируется, когда файл с альтернативным изображением завершает загрузку в браузер. Браузер не дожидается загрузки файла, заданного в атрибуте src. Глава 20. Объекты изображения, области и карты изображений 633
Пример В листинге 20.5 в обработчике onload объекта изображения используются операторы определения этим свойствам значений. См. также: свойства img. src, img. complete. mimeType Значение: строка Только для чтения Совместимость: Winffi6+, MacIE-, NN-, Moz-, Safari- Это свойство возвращает описание MIME-типа в формате простого текста, например, JPEG Image или GIF Image. Пример Вы можете использовать свойство mimeType для определения формата изображения. if (document.myIMG.mimeType.indexOf("JPEG") != -1) { // Операторы обработки JPEG-изображения > В этом примере метод indexOf () используется для поиска фразы "JPEG" в строке описания MIME-типа. name Значение: идентификатор Чтение/Запись Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Свойство name возвращает значение, присвоенное атрибуту name элемента img. Начиная с Ш4 и NN6, вы можете использовать ГО элемента, чтобы сослаться на объект элемента img в document. all и document. getElementByld (). Но ссылки в формате document. имя- Изображения и document. images [имяИзображения] принимают только значение, назначенное атрибуту name. В некоторых случаях элементам img удобнее назначить упорядоченные в алфавитном порядке имена (imgl, img2 и т.д.). Как и любое другое имя объекта, идентификатор не может начинаться с цифры. На практике вы редко будете заменять имя объекта элемента img идентификатором. Пример Все то же приложение The Evaluator поможет вам изучить свойство name изображения. Введите в верхнее текстовое поле такое выражение. document.mylMG.name Конечно, это излишне, поскольку имя входит в состав ссылки на объект. См. также: свойство id. name Prop Значение: строка имени файла Только для чтения Совместимость:, Winffi5+, МасШ-, NN-, Moz-, Safari- В отличие от свойства src, которое возвращает полный URL в Ш, свойство nameProp в Ш возвращает только имя файла и путь к нему. Если ваш сценарий замены изображения 634 Часть III. Объекты документа
нуждается в получении имени файла текущего изображения (чтобы определить, какое изображение отображать следующим), то свойство name Prop облегчит эту задачу, задав фактическое имя файла без необходимости проведения обширного синтаксического анализа URL. Пример Вы можете применить приложение The Evaluator для сравнения результатов, возвращаемых свойствами src и name Prop (пример приведен на прилагаемом к книге компакт-диске в Ш5+). Введите в верхнее текстовое поле следующие выражения. document.myIMG.src document.mylMG.nameProp См. также: свойство img. src. naturalHeight naturalWidth Значение: целое число Чтение/Запись Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Эти свойства возвращают исходную ширину и высоту изображения, выраженные в пикселях. Они часто применяются при масштабировании изображения в сценарии или с помощью атрибутов элемента img. Пример Приложение The Evaluator позволяет изучить и свойства naturalHeight, naturalWidth. Начните с получения значений по умолчанию, введя в верхнее текстовое поле следующее выражение. document.mylMG.width Увеличьте ширину изображения со значения 120 до 200. / document.myIMG.width = 200 Если вы прокрутите изображение, то увидите, что оно изменило свой размер. Чтобы ознакомиться с исходными размерами изображения, выполните такое выражение. document.mylMG.naturalWidth Как видите, The Evaluator возвращает значение 120, хотя текущая ширина равна 200. См. также: свойство img. height, img. width. protocol Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE5+, NN-, Moz-, Safari- Свойство protocol в BE содержит только часть полного URL, которое возвращается свойством src, описывающим протокол для передачи данных, что позволяет сценарию выяснить, например, где находится источник изображения: на локальном'жестком диске или на Web-сервере. Возвращенные значения не являются фактическими определителями протокола; они, скорее, описывают используемое средство — Hyper Text Transfer Protocol или File Protocol. Глава 20. Объекты изображения, области и карты изображений 635
Пример И вновь вам на помощь придет приложение The Evaluator. Введите в верхнее текстовое поле следующее выражение. document.mylMG.protocol См. также: свойства img. src, img. name Prop. src Значение: строка URL Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Свойство src — это шлюз к предварительной загрузке изображений (в объекты Image, которые хранятся в памяти) и выполнению замены изображений (в элементах img). Задайте URL свойству src объекта изображения в памяти, и вы заставите браузер загружать указанное изображение в свой собственный буфер (если пользователь разрешил кэширование). Задание URL свойству src объекта элемента img заставляет элемент отображать новое изображение. Чтобы воспользоваться преимуществом этой мощной комбинации средств, необходимо предварительно загрузить альтернативные версии заменяющих изображений в объекты изображений в памяти и затем приравнять свойство src объекта изображения к свойству src необходимого объекта элемента img. В NN3, NN4 (все OS платформы) и ШЗ для Мае размер изображения, определенного атрибутами элемента img (или, если они не заданы, то вычисленный браузером в соответствии с размером изображения), определяет прямоугольную область, резервируемую для этого изображения. Попытка назначить объекту элемента img изображения разного размера приводит к принудительному их масштабированию, что позволяет заполнить указанную ранее прямоугольную область (обычно приводит к искажению изображений). Во всех более поздних браузерах, тем не менее, объект элемента img изменяет свои размеры, чтобы расположить изображение на странице в неискаженном виде; остальное содержимое страницы перераспределяется таким образом, чтобы приспособиться к новому размеру изображения. Обратите внимание, что при считывании свойство src возвращает полный URL файла изображения, включая протокол и путь. Зачастую неудобно проводить замену одного изображения другим, указывая расположение файла последнего в сценарии. Некоторые другие способы (например, сохранение имени файла изображения в глобальной переменной) значительно повышают эффективность управления изображениями (см. свойство name Prop в WinIE5+). Пример В следующем примере (листинг 20.4) вы ознакомитесь со страницей, на которую добавлено несколько графических изображений. Его главное предназначение — это сравнение документов с предварительной загрузкой (кэшированием) изображений и без нее. Также вы научитесь через указанное время автоматически изменять изображения в объекте img. Чаще всего последняя возможность применяется при добавлении на Web-узлы баннеров. При загрузке страницы в глобальной переменной сохраняется массив объектов изображений. Элементы массива имеют строковые имена с числовыми индексами ("deskl", Hdesk2" и т.д.). Эти имена используются в ссылках на элементы массива. Каждый объект изображения в массиве имеет связанный с ним URL, соответственно которому выполняется предварительная загрузка изображения. Рассматриваемая страница (рис. 20.1) содержит два элемента img. Один из них отображает некэшируемое изображение, а второй — кэшируемое. Под каждым изображением располагается список (элемент select), который применяется для выбора одного из четырех графических 636 Часть III. Объекты документа
файлов. Обработчик onchange каждого списка вызывает отдельную функцию замены кэшируе- мого (loadCached ()) или некэщируемого файла (loadlndividual ()). Обе функции принимают в качестве единственного аргумента ссылку на форму, содержащую элементы select. Для циклического отображения изображений с пятисекундным интервалом в функции checkTimer () выполняется проверка установки флажка. Если флажок установлен, то свойство selectedlndex элемента select кэшированного изображения увеличивается (или обнуляется, если индекс принимает максимальное значение). Далее вызывается функция loadCached (), которая определяет текущий элемент и отображает соответствующее изображение. ГЕН. Edh yitw Favorttaa ТаоЬ ДО Ф| Image Object Individaally Loaded : ft-e-cached П Auto-cycle through pre-cached images Г?:1 -«-..«—и,.... ...»w^,.. ..,..,. .„,,, I..I...W.4.II. | in, I., I.I.L, IHIIIHIIH I- Uli II. ■»». I. I . Ш.Щ I .,.......■ '' ■ M »,l ■ .Vii HQDon» ''■:■■.-.• \ ЩШЯЩ&Ш . I Рис. 20.1. Страница документа с кэшируемыми изображениями С целью повышения удобства использования страницы в дескриптор <body> добавляется обработчик событий onunload, который вызывает функцию resetSelectsO. Эта функция общего назначения просматривает формы страницы и все элементы формы. Она устанавливает свойство selectedlndex всех элементов select в значение ноль. Таким образом, если пользователь перезагрузит страницу или возвратится к ней с помощью кнопки Назад (Back), то изображения начнут отображаться в исходной последовательности. <html> <head> <title>Image Object</title> <script type="text/javascript"> // объявление глобального массива изображений var iraageDB; // предварительное кэширование изображений Глава 20. Объекты изображения, области и карты изображений 637
if (document.images) { // установка индексных имен массива var desklmages = new Array("deski", "desk2", "desk3", "desk4"); // создание и предварительная загрузка массива изображений imageDB = new Array(4); for (var i = 0; i < imageDB.length ; i++) { imageDB[desklmages[i]] = new Image(120,90); imageDB[desklmages[i]].src = desklmages[i] + ".gif"; } } // изменение отдельных изображений function loadlndividual(form) { if (document.images) { var gifName = form.individual.options[form. individual.selectedlndex].value; document.getElementByldC'thumbnaill").src = gifName + ".gif"; } } // изменение кэшированных изображений function loadCached(form) { if (document.images) { var giflndex = form.cached.options[form.cached. selectedlndex].value; document.getElementByldC'thumbnai12").src = imageDB[giflndex].src; } } function checkTimerO { if (document.images && document.Timer.timerBox.checked) { var giflndex = document.selections.cached.selectedlndex; if (++gifIndex > imageDB.length - 1) { giflndex = 0; } document.selections.cached.selectedlndex = giflndex; loadCached(document.selections); var timeoutID = setTimeout("checkTimer()",5000); } } // восстановление при выгрузке function resetSelects() { for (var i = 0; i < document.forms.length; i++) { for (var j =0; j < document.forms[i].elements.length; j++) { if (document.forms[i].elements[j].type == "select-one") { document.forms[i].elements[j].selectedlndex = 0; } } } } // инициализация function init() { loadlndividual(document.selections); loadCached(document.selections); setTimeout("checkTimer()",5 0 0 0); } 638 Часть III. Объекты документа
</script> </head> <body onload="init()" onunload="resetSelects ()"> <hl>Image Object</hl> <hr /> <center> <table border="3" cellpadding="3"> <tr> <thx/th> <th>Individually Loaded</th> <th>Pre-cached</th> </tr> <tr> <td align="right,lxb>Image:</bx/td> <tdximg alt="image" src="cpul.gif" id="thumbnaill" height="90" width="120" /x/td> <tdximg alt="image" src= "deskl.gif" id="thumbnail2 height="90" width="120" /></td> </tr> <tr> <td align= "right"><b>Select image:</bx/td> <form name="selections'^ <tdxselect name="individual" onchange="loadIndividual(this.form)"> <option value="cpul">Wires</option> <option value="cpu2">Keyboard</option> <option value="cpu3">Disks</option> <option value="cpu4">Cables</option> </selectx/td> <tdxselect name="cached" onchange= "loadCached(this.form)"> <option value="deskl">Bands</option> <option value="desk2">Clips</option> <option value="desk3">Lamp</option> <option value="desk4">Erasers</option> </select x/td> </form> </tr> </table> <form name="Timer"> <input type="checkbox" name="timerBox" onclick="checkTimer()" />Auto-cycle through pre-cached images </form> </center> </body> </html> См. также: свойства img. lowsrc, img. nameProp. start Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Свойство start задается для файлов видеоклипов, воспроизводимых в области элементов img в Ш4+. По умолчанию видеоклип начинает воспроизводиться (не в Мае) тогда, когда файл Глава 20. Объекты изображения, области и карты изображений 639
изображения отображается на экране. Такое поведение следует из настройки по умолчанию свойства start — f ileopen. Другое распознаваемое значение — mouseover; оно указывает воспроизводить клип только в случае, когда пользователь наводит указатель на изображение. См. также: свойства img. dynsrc, img. loop. useMap Значение: идентификатор Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство useMap представляет атрибут usemap элемента img, указывая на имя, назначенное элементу area на странице (см. листинг 22.7). Этот элемент area содержит подробные сведения о клиентской карте изображения (см. далее в этой главе). Значение свойства useMap должно включать символ решетки, который определяет внутреннюю HTML-ссылку на странице. Если необходимо выбрать одну из двух или большего количества карт изображения для того же самого элемента img (например, изображение заменяется или пользователь находится в другом режиме), можно задать несколько map-элементов так, чтобы каждый из них имел собственное имя. Изменение свойства useMap объекта элемента img позволяет связать карту с изображением. См. также: свойство isMap. vspace См. hspace. width См. height. X У Значение: целочисленное Только для чтения Совместимость: Winffi-, МасГЕ-, NN4, Moz-, Safari- В NN4 сценарий может получать координаты х и у элемента img (верхний левый угол прямоугольной области, занятой изображением) с помощью свойств х и у. Эти свойства доступны только для чтения. Они вытеснены в NN6 свойствами offsetLeftn of f set Top, задаваемыми для любого элемента. Даже вне DHTML можно использовать значения этих свойств, чтобы прокручивать документ в NN4 в строго определенное место (методом window. scrollTo ()). Поскольку все операционные системы отображают страницы и задают размеры окон браузера по-разному, изображение можно динамически перемести в необходимое положение (другими словами, прокрутить документ) в зависимости от действий пользователя. Пример Для прокрутки документа таким образом, чтобы ссылка располагалась на несколько пикселей ниже верхнего края окна, выполните следующее выражение. window.scrollTo(document.images[0].x, (document.images[0].у - 3)); См. также:: свойства img. of f setLef t, img. Of f setTop; методы img. scrollIntoView (), window.scrollTo(). 640 Часть III. Объекты документа
Обработчики событий onabort onerror Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ Иногда ваши сценарии должны будут реагировать на ситуацию, когда пользователь щелкает на кнопке Stop во время загрузки изображения или возникновения сбоев в сетевых соединениях, что сводит на нет весь процесс загрузки изображения. Для этого используйте обработчик событий onabort, позволяющий активизировать определенную функцию в случае щелчка на кнопке Stop. Если возникает ошибка в передаче изображения, используйте обработчик onerror. Данные обработчики событий не позволяют решить всех проблем, с которыми вы можете столкнуться на практике. Например, они не позволяют получить имя файла загружаемого изображения. Если такая информация в сценарии необходима, ее нужно сохранить в отдельной переменной перед установкой свойства src изображения. У вас также нет возможности узнать природу ошибки, которая является причиной запуска соответствующего обработчика. С возникшими проблемами можно справиться, выполнив перезагрузку страницы либо переместившись в другое место Web-страницы. Пример В коде листинга 20.5 используется обработчик события onabort. Если изображение уже кэшировано, то необходимо завершить работу и загрузить браузер заново, чтобы предотвратить загрузку изображения. В данном случае перезагружается сразу вся страница. Вы при необходимости можете сделать исключения, несколько изменив код. onload Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Обработчик события onload объекта img активизируется, когда происходит одно из трех действий: файл lowsrс-изображения заканчивает загружаться; для изображения отсутствует lowsrc-копия, а изображение src заканчивает загружаться; при появлении каждого кадра анимационного GIF-изображения (GIF89a). Обратите внимание, что при определении lowsrc-файла внутри дескриптора <img> объект img не получает никакой информации о том, что изображение src закончило загружаться. Если эта информация применяется в сценарии, то специально проверьте текущий файл изображения, проанализировав свойство src объекта изображения. Остерегайтесь того, что обработчик события onload элемента img может активизироваться до завершения загрузки остальных элементов страницы. Если функция обработчика событий ссылается на другие элементы страницы, то она должна проверить существование других элементов до обращения к ним. Пример Чтобы в полной мере ознакомиться с листингом 20.5, перезагрузите браузер. При первой загрузке документа файл изображения lowsrc загружается вместо фотографии клавиатуры. После этого в текстовое поле выводится значение done (обработчиком onload), даже если основное изображение еще не загружено. Вы можете поэкспериментировать с другим изображением — фотографией причудливой скалы. Глава 20. Объекты изображения, области и карты изображений 641
<html> <head> <titlex/title> <script type="text/javascript"> function loadlt(thelmage,form) { if (document.images) { form.result.value = ""; document.images[0].lowsrc = "deskl.gif"; document.images[0].src = thelmage; } function checkLoad(form) { i f (document.images) { form.result.value * document.images[0].complete; function signal() { if(confirm("You have stopped the image from loading. Do you want to try again?")) { location.reload(); } } </script> </head> <body> <img alt="image" src="cpu2.gif" lowsrc="desk4.gif" width="120" height="90" onload="if (document.forms[0].result) document .forms [0] .result .value=*'done'" onabort= " signal () " /> <form> <input type="button" value="Load keyboard" onclick="loadlt('cpu2.gif',this.form)" /> <input type="button" value="Load arch" onclicks"loadlt('arch.gif■,this.form)" /> <pxinput type= "button" value-"Is it loaded yet?" onclick="checkLoad(this.form)" /> <input type«"text" name="result" /> <input type="hidden" /></p> </form> </body> </html> См. также: свойства img. src, img. lowsrc. Объект элемента area Свойства, методы, обработчики событий для этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий alt coords hash 642 Часть III. Объекты документа
Окончание таблицы Свойства Методы Обработчики событий host hostname href noHref pathname port protocol search shape target Синтаксис Доступ к свойствам элемента area. (NN3+/fE4-b) [window. ] document. links [индекс] . свойство (IE4+) [window. ] document. all. идентификатор. свойство \ метод( [параметры] ) (IE4+) [window. ] document. all. идентификатор. areas [индекс] . свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document. getElementByld ("MAPElemID) . areas [индекс] . свойство | метод ( [параметры] ) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ метод ( [параметры] ) Совместимость: WinDE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Описание объекта Объектные модели документа определяют объект области карты изображения как один из объектов ссылки в документе (см. объект анкера в главе 19). Такое поведение не лишено здравого смысла, поскольку щелчок мышью на области карты приводит пользователя к другому документу или анкеру в том же самом документе — создается гиперссылка внутри изображения. В HTML определение ссылок и областей карт изображения отличается довольно существенно; а вот в самых ранних версиях сценариев оба вида объектов имели почти одни и те же свойства и обработчики событий. Чтобы детально ознакомиться с объектом ссылки, обратитесь к главе 19. Единственное отличие состоит в том, что в NN3 и NN4 для объекта области карты не определено полного набора обработчиков событий мыши — можно рассчитывать только на использование onclick (NN4+), onmouseover и onmouseout. Начиная с ЕЕ4 и NN6, все атрибуты элемента area доступны как свойства, используемые при написании сценария. Кроме того, с помощью объекта элемента тар можно изменить структуру клиентских областей карты. Объект элемента тар содержит массив объектов элементов area. Существует возможность удалять, изменять или добавлять элементы area внутри элемента тар. Глава 20. Объекты изображения, области и карты изображений 643
Клиентские карты изображения использовать очень интересно. К тому же, они хорошо описаны в документации по HTML (с тех пор как впервые были представлены в NN2). По существу, вы определяете любое число прямоугольных областей в пределах изображения, задавая координаты их углов. Помочь правильно задать координаты областей изображений в атрибуте coords дескриптора <агеа> вам помогут графические средства. Существует одна деталь, которая вводит в заблуждение многих HTML-разра- CdiT ботчиков. Она заключается во взаимосвязи дескрипторов <тар> и <img>. Сначала назначьте имя дескриптору <тар>. В дескрипторах <img> атрибут usemap > должен содержать символ решетки (#) и имя карты изображения. Если вы забудете ввести символ решетки, то не сможете присоединить изображение к соответствующей карте. Листинг 20.6 содержит пример клиентской карты изображения, с помощью которой пользователь может перемещаться по Ближнему Востоку. При наведении указателя на отдельные части изображения его вид изменится, определив ссылки, на которых можно щелкнуть. Щелчок на графической области приводит к выводу сообщения с названием выбранного географического региона. Листинг 20.6. Простая клиентская карта изображения <html> <head> <title></title> <script type="text/javascript"> function show(msg) { window.status = msg; return true; } function go(where) { alert("We're going to " + where + "!"); } function clearltO { window.status = ""; return true; } </script> </head> <body> <hl>Sinai and Vicinity</hl> <img alt = "imageM src="nile.gif" width="320" height="240" usemap="#sinai" /> <map id="sinai" name="sinai"> <area href= "javascript:go('Cairo')" coords="12,152,26,161" shape="rect" onmouseover="return show('Cairo1)" onmouseout="return clearltO" /> <area href="javascript:go('the Nile River')" coords="1,155,6,162,0,175,3,201,61,232,109,227,167,238,274, 23 9,292,22 0,3 07,220,319,230,319,217,2 98,213,282,217,267,233, 198,228,154,22 7,107,221,71,22 5,21,199,19,165,0,149" shape="poly" onmouseover="return show('Nile River')" onmouseout= "return clearltO" /> <area href="javascript:go('Israel')" coords="95,69,201,91" shape="rect" onmouseover="return show('Israel')" onmouseout="return clearltO" /> <area href="javascript:go('Saudi Arabia')" 644 Часть III. Объекты документа
coords="256,57,319,121" shape="rect" onmouseover= "return show('Saudi Arabia')" onmouseout="return clearltO" /> <area href="javascript:go('the Mediterranean Sea')" coords="l,55,26,123" shape="rect" onmouseover="return show(•Mediterranean Sea')" onmouseout="return clearlt()" /> <area href="javascript:go('the Mediterranean Sea')" coords="27,56,104,103"' shape="rect" onmouseover="return show('Mediterranean Sea')" onmouseout="return clearlt()" /> </map> </body> </html>' Свойства alt Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство alt представляет атрибут alt элемента area. Будущие браузеры могут использовать этот атрибут, чтобы обработать дополнительную информацию о ссылке, связанной с элементом area. См. также: свойство title. coords shape Значение: строка Чтение/Запись Совместимость: WinlE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойства coords и shape управляют расположением, размером и формой изображения, заданными элементом area. Значения формы, которые вы можете использовать для этого свойства, определяют формат представления значений в свойстве coords. Форма circ circle poly polygon rect rectangle Координаты центр х, центр у, радиус центр х, центр у, радиус х1,у1,х2,у2,... х1,у1,х2,у2,... левая, верхняя, правая, нижняя левая, верхняя, правая, нижняя "30, "30, "0, "0, "10, "10, Пример 30, 20" 30, 20" 0, 0, 30, 0, 0, 30, 20, 60, 20, 60, г 15, г 15, 40" 40" 30, 30, 0, 0, 0" 0 м Заданная по умолчанию форма элемента area — rectangle. Глава 20. Объекты изображения, области и карты изображений 645
hash host hostname href pathname port protocol search target См. соответствующие свойства объекта ссылки (глава 19). shape См. coords. Объект элемента тар Свойства, методы, обработчики событий этого элемента HTML описаны в главе 15. Свойства Методы Обработчики событий areas[] onscroll name Синтаксис Доступ к свойствам объекта элемента тар. (IE4+) [window. ] document. all. идентификатор. свойство \метод( [параметры]) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ метод ( [параметры] ) Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safaril+ Описание объекта Объект элемента тар — невидимый HTML-контейнер всех элементов area, каждый из которых определяет активную область изображения. Клиентская карта изображения назначает ссылки для прямоугольных, круговых или многоугольных областей изображения. Намного более важные свойства объекта элемента тар — массив areas; в меньшей степени— его свойство name. Маловероятно, что вы будете изменять имя элемента тар. (Лучше определить имена отдельным элементам тар, а затем задать соответствующие имена в качестве значения свойства useMap элемента img.) Вы можете использовать массив areas, чтобы изменить структуру объектов area внутри карты изображения на стороне клиента. 646 Часть III. Объекты документ*
Свойства areas [] Значение: массив объектов area Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Используйте массив areas, чтобы просмотреть все объекты area в элементе тар. Если NN6 максимально точно поддерживает структуру узлов, принятую в W3C DOM, то Ш4+ обеспечивает более прямой доступ к объектам area, вложенным в тар. Если необходимо перераспределить элементы area внутри объекта тар, удалите старые элементы, установив свойства length массива areas в нуль, а затем заново заполните этот массив элементами area. Пример Листинг 20.7 демонстрирует принципы замены элементов area в элементе тар. Страница загружается с изображением клавиатуры. Это изображение связано с клиентской картой изображения keyboardMap, содержащей три активных области. Если впоследствии изменить изображение элемента img, то сценарий заменит его свойство useMap, соответствующее новой карте изображения. Наведите указатель мыши на каждое изображение и изучите URL-адреса их активных областей (отображаются в строке состояния). На странице также присутствует кнопка, которая вызывает функцию makeArea () (не поддерживается в МасШ5). Указанная функция создает четыре новых элемента area и настраивает их в контексте текущего изображения. На рис. 20.2 показана ссылка для четвертой активной области. Fll« Edit Vltw Favorite* Toolt Help & ©Bade . Q [«J И «ft pS-rch -&M» *»* ^ !£+■&. ivGlt* map Element Object [ low* toubomtiimaa*. ..: 1 I»«»g«^ Рис. 20.2. Создание клиентской карты изображения Глава 20. Объекты изображения, области и карты изображений 647
Листает 20 J. Изменен <html> <head> <title>map Element Object</title> <script type="text/javascript"> // генерирование элементов области function makeAreasO { document.getElementByld("mylMG").src = "desk3 .gif'; // создание объектов элементов области var areal = document.createElement("area"); areal.href = "Script-Made-Shade.html"; areal.shape = "polygon"; areal.coords = "52,28,108,35,119,29,119,8,63,0,52,28"; var area2 = document.createElement("area"); area2.href = "Script-Made-Base.html"; area2.shape = "rect"; area2.coords = "75,65,117,87"; var агеаЗ = document.createElement("area"); area3.href = "Script-Made-Chain.html";■ агеаЗ.shape = "polygon"; агеаЗ.coords = "68,51,73,51,69,32,68,51"; var area4 = document.createElement("area"); area4.href = "Script-Made-Emptyness.html"; area4.shape = "rect"; area4.coords = "0,0,50,120"; // включение новых элементов в дочерние узлы MAP var mapObj = document.getElementByld("lamp_map"); while (mapObj.childNodes.length) { mapObj.removeChild(mapObj.firstChild); } mapObj.appendChiId(areal); mapObj.appendChiId(area2); mapObj.appendChiId(агеаЗ); mapObj.appendChiId(area4); // обработка ошибки отображения в NN6 document.getElementByld("mylMG").style.display = "inline"; } function changeToKeyboard() { document.getElementByld("mylMG").src = "cpu2.gif"; document.getElementByld("mylMG").useMap = "#keyboardMap"; } function changeToLamp() { document.getElementByld("mylMG").src = "desk3.gif"; document.getElementByld("mylMG").useMap = "#lampMap"; } </script> </head> <body> <hl>map Element Object</hl> <hr /> <img alt="image" id="myIMG" src="cpu2.gif" width="12 0" height="90" usemap="#keyboardMap" /> <map id="keyboardMap" name="keyboardMap"> <area href="AlpaKeys.htm" shape="rect" 648 Часть III. Объекты документа
coords="0,0,26,42" /> <area href="ArrowKeys.htm" shape="polygon" coords="48,89,57,77,69,82,77,70,89,78,84,89,48, 89" /> <area href="PageKeys.htm" shape="circle" coords="104,51,14" /> </map> <map name="lampMap" id="lamp_map"> <area href="Shade.htm" shape="polygon" coords="52,28,108,35,119,29,119,8,63,0,52,28" /> <area href="Base.htm" shape="rect" coords="75,65,117,87" /> <area href="Chain.htm" shape="polygon" coords="68,51,73,51,69,32,68,51" /> </map> <form> <pxinput type= "button" value="Load Lamp Image" onclick="changeToLamp()" /> <input type="button" value="Write Map on the Fly" onclick="makeAreas()" /></p> <p><input type="button" value="Load Keyboard Image" onelick="changeToKeyboard()" /></p> </form> </body> </html> См. также: объект элемента area. Глава 20. Объекты изображения, области и карты изображений 649
Объект form и вложенные в него объекты До появления динамических объектных моделей и ав- l) томатического изменения содержимого страницы сценарии в HTML-документе, как правило, управляли исключительно формами. Несмотря на появление новых возможностей в DHTML, формы остаются первичными элементами пользовательского интерфейса HTML-документов, позволяющими вводить информацию и выбирать значения с помощью привычных элементов управления (кнопок, списков опций и т.п.). Использование форм в сценарии и элементов форм часто требует создания ссылок на объекты. Ссылки могут стать довольно длинными к тому моменту, когда вы начнете использовать свойство элемента управления формы (дочернего объекта формы, являющейся дочерним объектом документа, который выступает дочерним объектом окна или фрейма). Расширенные объектные модели W3C предоставляют доступ в сценарии к элементам управления формой элементы и их свойствам, описанным в спецификации HTML 4.O. Элементы fieldset и legend объединяют в сценарии все элементы управления формы текущего документа. Еще один элемент— label — представляет собой контейнер текстовых надписей, которые часто прикрепляются к элементам управления форм. Если в сценарии не всегда возникает потребность в этих объектах, браузеры предоставляют к ним доступ таким же образом, как к любому другому HTML- элементу, поддерживаемому браузером. Объект form в объектной модели Взгляните еще раз на иерархию объектов JavaScript в объектной модели; обратите внимание на самый низкий уровень (см. рис. 14.1), представленный на рисунке. Объект элемента form может содержать большое количество объектов
элементов формы (иногда их называют элементами управления формы) — см. главы 22-24. В этой главе речь пойдет о контейнерах. Хорошие новости для разработчика заключаются в том, что многие сценарии, выполняемые на стороне клиента и поддерживающие элементы управления форм, совместимы почти со всеми браузерами. Вполне вероятно, что вы будете использовать более новые способы обращения к формам и их вложенным элементам, предполагая, что большая часть посетителей ваших Web-страниц использует новые браузеры. Тем самым вы сможете избежать необходимости утомительной отладки "старого" синтаксиса в случае создания ссылок. Тем не менее, почти весь код примеров в этой и следующих трех главах использует синтаксис, который является совместимым с самыми ранними версиями браузеров. Обратите внимание, что большинство преобразований в характеристиках элементов форм (в новых браузерах) в первую очередь коснулось добавления свойств, общих для всех HTML-элементов. Элемент form Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий acceptCharset handleEvent() onreset action 'reset() onsubmit autocomplete submit() elements[] encoding enctype length method name target Синтаксис Доступ к свойствам и методам объекта form. (Все) [window. ] document. имяФормы. свойство \ метод ( [параметры] ) (Все) [window. ] document. forms [индекс] . свойство \ метод ( [параметры] ) (Все) [window. ] document. forms [ "имяФормы" ] . свойство \ метод([параметры]) (IE4+) [window. ] document.all.идентификатор, свойство\метод([параметры]) (IE5+/W3C) [window. ] document.getElementByld ("идентификатор") . свойство) \ метод ( [параметры] ) Совместимость: WinflE3+, Macffi3+, NN2+, Mozl+, Safaril+ Глава 21. Объект form и вложенные в него объекты 651
Описание объекта Формы и их элементы — наиболее общие двусторонние шлюзы между пользователями и сценариями JavaScript. Элемент управления формы — единственный способ предоставить пользователям возможность введения текстовой информации. Элементы управления формы также представляют максимально стандартизованные и знакомые опции пользовательского интерфейса, которыми посетитель может воспользоваться для выбора значений из предопределенного набора данных. Иногда этот выбор предоставляется в виде переключателя, флажка или элементов списка. Вы, очевидно, знаете, что форма — это пользовательское средство ввода информации, которая отправляется на сервер. Какие действия сервер выполняет с этой информацией, зависит от CGI-программы, запущенной на нем. Если ваша Web-страница выполняется на сервере непосредственно под вашим управлением, то вы можете определить все необходимые операции по сбору данных или программ поиска в базе данных, что позволит максимально эффективно взаимодействовать с пользователем. Но некоторые Internet-провайдеры (ISP) не ориентируются на предоставление серверных услуг и не обеспечивают поддержку CGI-программ — в лучшем случае вам предоставят ограниченный набор популярных, но малофункциональных CGI-программ, доступных всем клиентам. Клиентские базы данных или средства выполнения транзакций редко предусмотрены услугами Internet-провайдера. Независимо от статуса Internet-сервера, вы можете найти (}юрмам разное применение в JavaScript- сценариях. Например, рекомендуется не сразу приступать к обработке данных на стороне сервера и интенсивному обмену данными, а с помощью JavaScript предварительно проанализировать необработанные данные, полученные от пользователя, на стороне клиента, чтобы удостовериться, что используется формат данных, который конечная база данных или другие программы сможет обработать без фатальных последствий. Любое подобное взаимодействие с данными происходит в браузере без единого лишнего бита, отправленного по сети. Глава 43 будет посвящена эффективным методам проверки данных, собранных с помощью форм. От того, как определяется элемент form (независимо от пользовательских элементов интерфейса, описанных в следующих главах), во многом зависит, как вы будете использовать информацию, полученную от элементов управления формы. Если вы намереваетесь использовать форму исключительно для обработки полученных данных в JavaScript-сценарии (отсутствуют запросы или регистрация на стороне сервера), то нет необходимости использовать в нем атрибуты action, target и method. Но если ваша Web-страница будет отправлять информацию или запросы обратно, на сервер, то вы должны определить атрибуты action и method. Кроме того, необходимо определить атрибут target (если возвращенные с сервера данные нужно отобразить в окне, отличном от окна запроса) и атрибут enctype (если сценарий вашей формы отправляет на сервер данные в определенном формате MIME, а не в обычной кодировке ASCII). Ссылка на элементы управления формы Для большинства клиентских сценариев взаимодействие между пользователем и системой происходит с помощью элементов в пределах формы. Объект form — это обычный контейнер для различных элементов управления. Если ваши сценарии выполняют проверку корректности введенных пользователем данных до их отправки или обработки на сервере или клиенте, то многие операторы воспринимают объект формы как часть ссылки на элемент. Комплексный HTML-документ может содержать много объектов form. Каждая пара дескрипторов <form>. . .</form> определяет одну форму. Вы никогда не проиграете (мы не учитываем потенциальное замешательство со стороны того, кто прочитает ваш сценарий), 652 Часть III. Объекты документа
если многократно определите имена элементов в каждой из форм документа. Например, если каждая из трех форм имеет набор переключателей с именем choice, то задание ссылки на каждый из них гарантирует, что JavaScript точно их не перепутает. Ссылка на первый переключатель каждого из наборов задается следующим образом. document.forms[0].choice[0] document.forms[1].choice[0] document.forms[2].choice[0] Помните также, что можно создать формы (или любой объект HTML для описанного случая) "на лету", когда HTML-строки в процессе выполнения сценария записываются э другие окна или фреймы. В результате вы можете определить различные атрибуты формы на основе установок существующего документа. Передача форм и элементов в функции Если форма или элемент формы содержат обработчик события, который вызывает функцию, определенную в другой части документа, вы можете использовать дополнительные ключевые слова, чтобы упростить задачу обращения к объектам (в то время как функция выполняет свою работу). Непонимание этой концепции не только вынуждает создавать большее количество кода, чем необходимо, но также безнадежно запутывает при попытке анализа кода в JavaScript-документе другого разработчика. В параметрах обработчика событий часто встречается ключевое слово this, которое представляет ссылку на текущий объект, содержащий атрибут обработчика событий. Например, рассмотрите функцию и форму листинга 21.1. Полный пользовательский интерфейс состоит из элементов формы, показанных на рис. 21.1. Листинг 21.1. Передача объекта form в качестве параметра <html> <head> <title>Beatle Picker</title> <script type="text/javascript"> function processData(form) { for (var i = 0; i < form.Beatles.length; i++) { if (form.Beatles[i].checked) { break; } } var chosenBeatle = form.Beatles[i] .value; var chosenSong = form.song.value; alert("Looking to see if " + chosenSong + " was written by " + chosenBeatle + "..."); } function checkSong(songTitle) { var enteredSong = songTitle.value; alert("Making sure that " + enteredSong + " was recorded by the Beatles."); } </script> </head> <body> <form name="Abbey Road"> Choose your favorite Beatle: <input type="radio" name="Beatles" value="John Lennon" checked="true" />John Глава 21. Объект form и вложенные в него объекты 653
<input type="radio" name="Beatles" value="Paul McCartney" /> Paul <input type="radio" name="Beatles" value="George Harrison" />George <input type="radio" name="Beatles" value="Ringo Starr" />Ringo <p>Enter the name of your favorite Beatles song:<br /> <input type="text" name="song" value="Eleanor Rigby" onchange="checkSong(this)" /></p> <pxinput type= "button" name= "process" value="Process Request..." onclick="processData(this.form)" /></p> </form> </body> </html> Функция processDataO, которая считывает и записывает свойства многочисленных элементов управления формы, ссылается на элемент управления двумя способами. Первый способ состоит в том, чтобы определить обработчик событий onclick (кнопка в нижней части документа), вызвать функцию processData О и не передавать ей никаких параметров. Внутри этой функции все ссылки на объекты (переключатели или поля указания песни) должны быть представлены в полном виде, чтобы получить значение, введенное в поле song. document.forms[0].song.value К^^РРД^^^|^Ш1^^И^РЩШ1!Ш1ЩШШ1ЩШШШ|Ш1Ц|||1Ш11^ File E«t Vbw FayoritM Tool* Choose your favorite Beatie: ©John О Paul О George О Bingo Enter the name of your favorite Beatles song: ! Eleanor Rigby .^вюзанм^ S"" ■ '■ ■' "-■.'. ■" '■■.'" " ■ "^■■"■■>— ..г.щ..|....... i /■■"';«■■ *»* »." ..vtuM.,,^.,..,,^,,, ,,., ,,,., ,,..(r„.M..,.,r«,,.i..^.. ., ■ Рис. 21.1. Элементы управления передают различные ссылки в функцию, представленную в листинге 21.1 Более эффективный способ состоит в том, чтобы передать ссылку на объект form как параметр, в котором вызывается функция (см. листинг 21.1). Определив this . form как параметр, вы поручите JavaScript передать все, что он знает относительно формы, из которой вызывалась эта функция (form— это свойство каждого элемента управления формы; данное 654 Часть III. Объект документа
свойство— ссылка на форму, которая содержит текущий элемент управления; поэтому this. form передает значение свойства form элемента управления). В функции ссылка на объект form присваивается имени переменной (произвольно устанавливается дня значения form), которая задается в круглых Скобках после имени функции. Параметр имени переменной form в данном случае используется потому, что он представляет целую форму. Но вы можете применить любое достоверное имя переменной, которое вам нравится. Ссылка на форму содержит всю необходимую браузеру информацию, чтобы найти эту форму в пределах документа. Поэтому любые операторы в функции могут использовать значение данного параметра вместо более громоздкой ссылки на форму. Таким образом, можно использовать form, чтобы заменить document. forms [0] в любой ссылке на объект формы. Чтобы получить значение поля song, необходимо задать следующую ссылку. form.song.value Если бы был назначен объект формы переменной с именем Sylvester, ссылка выглядела бы так. Sylvester.song.value Если параметр функции — это ссылка на объект, операторы в функции могут получать или устанавливать свойства этого объекта так же, как вызываются его методы. Другой способ использования ключевого слова this заключается в передаче его как параметра. В отличие от this. form, которая задает ссылку на форму, содержащую элемент, this определяет ссылку исключительно на сам элемент. В листинге 21.1 вы можете добавить обработчик событий к полю song, чтобы сделать возможной проверку вводимых данных (и удостовериться, что введенный элемент присутствует в базе данных песен "Битлз", созданных в другой части документа). Поэтому в функцию анализа данных советуем отправить только объект field. <input type="text" name="song" onchange "checkSong(this)" /> Затем создайте функцию, которая будет выполнять запрос обработчика событий. function checkSong(songTitle) ( var enteredSong = songTitie.value alert("Making sure that " + enteredSong + " was recorded by the Beatles.") } В пределах этой функции вы можете идти прямо к основе — свойству value элемента, избежав более длинной ссылки. В дальнейшем как параметр передается только свойство элемента управления формы. В последнем примере функции checkSong () требуется только свойство value этого поля, поэтому обработчик событий может передавать this .value как параметр. Поскольку this ссылается на тот же объект, в котором появляется обработчик событий, синтаксис this. имяСвойства позволяет извлекать и передавать свойство. <input type="text" name="song" onchange="checkSong(this.value)м /> Преимущество этого способа передачи данных формы состоит в том, что функция не выполняет такого количества работы, как в предыдущем случае. function checkSong(songTitie) { alert("Making sure that " + songTitle + " was recorded by the Beatles.") } В отличие от передачи ссылок на объекты (подобно форме и текстовому полю, как показано выше), при передаче значения свойства (например this .value) последнее задается без ссылки на объект, который оно представляет. Это вполне приемлемо, когда функция нуждается Глава 21. Объект form и вложенные в него объекты 655
в значении, чтобы выполнить свою работу. Однако, если часть этой работы сострит в изменении свойства объекта (например, преобразовании текста к верхнему регистру и повторного отображения этого текста в поле), то значение, переданное в функцию, не обеспечивает "обратную связь" с породившим его объектом. Чтобы изменить свойство объекта, который вызывает функцию обработки событий, вам необходимо передать ссылку на определенный объект — и функция будет знать, где искать конечный объект. Многие разработчики с опытом написания программ на других языках ожидают, что параметры могут быть переданы либо по ссылке, либо по значению, но не обоими путями. Эмпирическое правило в JavaScript, однако, является довольно забавным исключением из написанных правил: ссылки на объекты передаются по ссылке, значения свойств — по значению. Ниже приведены принципы, которыми следует руководствоваться, чтобы правильно определить тип значения, передаваемого обработчику событий. ■ Элемент управления формы (this) передается в том случае, если функция должна получить последующий доступ к этому же элементу управления (возможно, с целью получения свойства value объекта, преобразования текста к верхнему регистру и последующей записи результата обратно в значение свойства этого же объекта). ■ Передается только одно свойство (this.propertyName), если функция нуждается в доступе исключительно для чтения к этому свойству. ■ Передается полный объект form элемента (this . form), если функция обращается ко многим элементам внутри формы (например, щелчок мышью на кнопке указывает на то, что функция должна восстановить содержимое поля). Не забывайте, что вы можете передать в функцию несколько параметров (например onclick="someFunction (this. form, this name) ") или даже несколько объектов этой же самой формы (например onclick="someFunction(this. form, emailAddr.value)"). Главное— задать входящие параметры в соответствии с типом данных, воспринимаемым функцией. (В главе 33 подробно описаны пользовательские функции.) Отправка форм по электронной почте У разработчиков сценариев часто возникает вопрос, связанный с тем, как отправить форму в виде почтового сообщения автору страницы. Эта задача предполагает возможность отправки "секретного" сообщения автору каждый раз, когда кто-то посещает его Web-страницу. Сначала мы узнаем, в чем же заключается "секретность" происходящего. Адрес электронной почты посетителя — ценная личная информация, к которой вы не получаете доступа без разрешения владельца. Это и есть та причина, по которой в NN устранена возможность отправки почтовых сообщений разработчику (она поддерживалась в NN2 и разрешала отправлять форму с помощью протокола mail to: без ведома владельца URL). Вы можете использовать средства NN3, но я не сторонник тайного использования адресов электронной почты и поэтому не буду в этой книге предавать огласке "грязные" методы работы. Кроме того, поскольку многие пользователи переходят к новым версиям браузера, рано или поздно они осознают невозможность того, что ранее было доступно. Microsoft, с другой стороны, пошла слишком далеко в вопросе недопустимости отправки форм по электронной еще в самых ранних версиях браузера. Если браузеры Nescape показывают пользователю предупреждение, что отправляемое электронное сообщение содержит адрес разработчика (сохраненный в установках браузера), в котором можно одобрить этот непродуманный поступок, ГЕЗ категорически отказывается отправлять содержимое формы в виде почтового сообщения. Ш4 отправляет содержимое формы как вложение к сообщению, Сомт 656 Часть III. Объекты документа
созданному в Microsoft Outlook, но только после отображения окна создания сообщения. Начиная с Ш5, этот процесс становится более гибким, а результирующий эффект — лучше, чем в случае использования Outlook в качестве почтового клиента по умолчанию. Многие поставщики Internet-услуг обеспечивают разработчиков CGI-программами, которые могут получать почтовые сообщения, содержащие формы с любыми адресам электронной почты. Этот способ управления данными формы, однако, не позволяет получить доступ к почтовому адресу посетителя (за исключением случая, когда ваша форма не содержит поля, где посетитель вводит такую информацию добровольно). Приведенное ниже описание методов отправки форм по электронной почте в первую очередь касается браузеров NN2+ и Ш5+. Вы должны знать, что формы, отправленные по почте, в определенной степени не поддерживаются официальными Web-стандартами. С момента ее создания HTML-спецификация от W3C официально не поддерживает эти методы. Однако последние версии браузеров, тем не менее, их поддерживают, причем весьма эффективно. Используйте эти средства предельно осторожно и только после тщательного тестирования во всех браузерах, которые будут использоваться для выполнения кода. Если вы будете создавать формы, отправляемые конечному получателю в виде почтовых сообщений, то вам придется ознакомиться с тремя атрибутами дескриптора <f orm>. Первый из них — method. Он инициализируется как POST. Следующий атрибут enctype. Если вы опустите его, то в почтовом сообщении данные формы будут содержаться в виде вложения, состоящего из закодированных пар имя-значения, как в следующем примере. name=Danny+Goodman&rank=Scripter+First+Class&serialNumber=042 Если вы устанавливаете атрибут enctype в значение text/plain, то пары имя- значения размещаются в теле сообщения в более простом и понятном формате. name=Danny Goodman rank=Scripter First Class serialNumber=042 Последний атрибут— action— это обычное место указания URL другого файла или сервера с CGI-программой. Замените URL на определенный адрес mailto:URL, указав после него необязателен параметр темы сообщения. action="mailto:prez@whitehouse.gov?subj ect=Opinion%20Poll" Чтобы подвести итог, в следующем примере будет показан полный дескриптор < f orm>, предназначенный для отправки формы по электронной почте в NN. <form name="entry" method="POST" enctype-"text/plain" action="mailto:prez@whitehouse.gov?subject=Option Poll"> Описанный выше способ не требует применения средств JavaScript. Рассмотрев варианты использования атрибутов и учтя тот факт, что эти атрибуты представлены как свойства объекта элемента form, можно найти расширенные возможности управления формами в сценариях. Изменение атрибутов формы За исключением ШЗ (где свойства объекта form доступны только для чтения), все браузеры, поддерживающие сценарии, представляют атрибуты элемента, form как свойства, которые поддаются изменению. Поэтому вы можете изменять, скажем, реакцию формы в сценарии в ответ на действия пользователя на вашей странице. Например, у вас может быть установлено две различных CGI-программы, которые будут вызываться на сервере в зависимости от того, выставлен или снят флажок на форме. Глава 21. Объект form и вложенные в него объекты 657
Лучшая возможность изменить свойства объекта form— воспользоваться функцией, вызванной обработчиком" события on submit формы. Изменения, выполненные в последний момент перед фактической отправкой данных, не оставляют никакой возможности проявиться сбоям, вызванным пользователем. Кнопки на формах Обычная ошибка, которую делают начинающие разработчики сценариев, — это определение в объекте input всех кнопок как submit (<input type=Msubmit">). Кнопка Submit отправляет форму. Если вы не установите атрибуты method или action в дескрипторе <f orm>, то браузер задаст их значения по умолчанию: method=GET и action= икьстраяицы. Когда вы отсылаете форму с этими атрибутами, страница перезагружается и устанавливает значения всех полей в их первоначальные значения. Используйте кнопку Submit только в том случае, когда необходимо, чтобы она отправляла форму. Если вы решили использовать кнопку для других целей, обратитесь к другому типу элемента (<input type= "button" >). Обычная кнопка может вызывать функцию, которая выполняет дополнительные действия и затем вызывает метод submit () объекта элемента form, чтобы отправить форму на сервер. Перенаправление данных после отправки Несомненно, после отправки формы на узел вы получаете страницу с названием Thank you, которую сервер возвращает, чтобы подтвердить, что ваша форма была принята. Это простая и понятная, а также вполне логичная обратная связь с сервером, принимающим данные. Не удивительно, что вы захотите, чтобы этот эффект сопровождал отправку данных с помощью протокола mailto:. К сожалению, это невозможно. Здравый смысл в данной ситуации требует, чтобы сценарий выполнил отправку данных (с помощью метода form, submit ()), а затем переместился к другой странице, которая выдает пользователю благодарность Thank you. Ниже приведен фрагмент сценария внутренней функции, запускаемой щелчком на графической кнопке Submit со ссылкой. function doSubmitO { document.forms[0].submit(); location.href = "thanks.html"; } Проблема состоит в следующем: если сразу после метода form, submit () выполняется другой оператор, то отправка данных отменяется. Другими словами, сценарий не ждет окончания отправки данных и не проверяет в браузере завершения действия (даже при том, что браузер знает, как сделать это — анализируя состояние строки состояния во время отправки формы). JavaScript не имеет события, которое активизируется после проведения успешной отправки данных. Поэтому надежного способа отобразить вашу собственную страницу Thank you после отправки данных нет. Не пользуйтесь методом window, set Timeout О, чтобы изменить документ в окне браузера после истечения определенного интервала, отсчитываемого сразу после выполнения метода form, submit (). Вы не можете предсказать, насколько быстро передаются данные в сетевом соединении пользователя. Если отправка данных не завершается до окончания интервала, то она отменяется (даже если уже завершена частично). Нет ничего положительного в том, что до сих пор не существует возможности управления подобными событиями. Вероятно, будущая версия объектной модели документа обеспечит нас средствами, которые позволят выполнять действия в случае успешной отправки данных. Сомт 658 Часть III. Объекты документа
Массивы элементов формы Начиная с NN2 и ВЕ4, объектные модели документов обеспечивают разработчиков средством, которое выгодно улучшает многие сценарии. Если вы создаете несколько одинаково названных объектов, они автоматически становятся массивом объектов, которые извлекаются с помощью синтаксиса, характерного для массивов (см. главу 7). Это особенно полезно, когда вы создаете формы со столбцами и строками (в форме заказа). Определяя то же самое имя всем ячейкам в столбце, вы можете использовать циклы for, чтобы по очереди просмотреть каждую строку, используя индекс цикла как индекс массива. Например, следующий код представляет типичную функцию, которая вычисляет сумму на форме заказа (при этом вызывается другая пользовательская функция, применяемая для форматирования полученного значения). function extendRows(form) { for (var i = 0; i < Qty.length; i++) { var rowSum = form.Qty[i].value * form.Price[i].value; form.Total[i].value = formatNum(rowSum.2); } } Все ячейки в столбце Qty названы Qty. Элемент в первой строке имеет значение индекса массива, равное нулю; он задан как form. Qty [i]. Описание объекта элемента input Данная глава описывает элемент form как контейнер элементов управления; следующие три главы посвящены различным типам элементов управления, которые содержатся на форме. Многие из этих элементов управления задаются с помощью одного и того же HTML- дескриптора: < input >. Только атрибут type дескриптора < input > определяет, отображает ли браузер кнопку, переключатель, текстовое поле и т.д. Тот факт, что один элемент имеет так много обликов, заставляет задуматься о нелогичности структуры элементов управления. Элемент input имеет атрибуты (и соответствующие свойства объекта), специфичные для каждого типа элемента управления формы. Например, если свойство maxLength текстового поля вполне логично задает количество символов, которые пользователь может ввести в нем, для другого элемента управления формы (например, кнопки), оно вообще не используется. Точно так же вы можете изменять состояние флажка или переключателя, изменяя его свойство checked; однако это свойство не задается при использовании текстового поля. Поскольку объектные модели документа все еще развиваются, они постепенно прогрессируют в объектно-ориентированном направлении. В результате все элементы управления, созданные с помощью дескриптора < input >, имеют длинный список свойств, которые являются общими для всех объектов элементов типа input. Они наследуют свойства и методы, которые определены для любого элемента input. В следующих главах этой книги будут рассмотрены элементы input и описаны объекты по функциональным признакам (кнопки в одной главе, текстовые поля — в другой). Далее речь будет идти только о тех свойствах и методах элемента input, которые имеют непосредственное отношение к применению элемента управления на практике. Тем временем в этой главе мы продолжаем описывать объект элемента form. Глава 21. Объект form и вложенные в него объекты 659
Свойства acceptCharset Значение: строка Чтение/Запись Совместимость: WinIE5+, MacIE5+, NN6+, Mozl+, Safari 1+ Свойство acceptCharset представляет собой атрибут acceptcharset элемента form в HTML 4.O. Его значение — это список одного или более наборов символов, которые сервер, принимающий форму, должен поддерживать. Для просмотра списка зарегистрированных имен наборов символов обратитесь по адресу http://www.iana.org/ assignments/character-sets. action Значение: строка URL Чтение/Запись (см. текст) Совместимость: WinIE3+, МасГ£3+, NN2+, Mozl+, Safari 1+ Свойство action (наряду со свойствами method и target) прежде всего представляет интерес для HTML-разработчиков, страницы которых связаны с серверными CGI-сцена- риями. Это свойство подобно значению, которое присваивается атрибуту action дескриптора <f orm>. Возвращаемое значение — это обычно URL сервера, на который отправляются запросы или обрабатываемые данные. Вводимые пользователем данные могут определять, как страница будет обращаться к серверу. Например, выставленный флажок в документе может изменить свойство action формы так, что CGI-сценарий на сервере будет обрабатывать все входные данные; наряду с этим неустановленный флажок означает, что данные формы будут обрабатываться другим CGI- сценарием или CGI-сценарием, расположенным на другом сервере. Также может быть, что один установленный флажок будет отправлять данные по одному адресу mailto:, а другой — по другому адресу mailto:. Технические требования для всех трех связанных свойств позволяют изменить их "на лету", однако подобные изменения эфемерны. Перезагрузка уничтожает любые установки, которые вы делаете для других выставленных свойств; поэтому следует изменять эти свойства только в той же самой функции сценария, которая отправляет форму (см. form. submit ()). См. также: свойства form.method, form, target, form, encoding. autocomplete Значение: строка Чтение/Запись Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Microsoft добавила в формы, отображаемые в IE5, свойство, которое позволяет браузеру давать подсказки пользователям, чтобы облегчить заполнение элементов управления формы (если их имена представляют собой набор однострочных текстовых полей, которые определяются с помощью дополнительных атрибутов, задаваемых в XML-структуре vCard). Подробнее поддержка этого свойства в браузере описана на странице http: //msdn. microsoft. com/workshop/ author/forms/autocomplete_ovr.asp. Значения свойства autoComplete— это одна из двух строк: on или off. В любом случае, объект form не сообщает о том, какое значение использовано, если не указать в дескрипторе формы атрибут autocomplete. elements [] Значение: массив элементов управления формы Только для чтения Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ 660 Часть III. Объекты документа
Свойство elements включают в себя все элементы пользовательского интерфейса, определенные на форме: текстовые поля, кнопки, переключатели, флажки, списки и т.д. Свойство elements — массив всех элементов управления формы, определенных в пределах текущей формы. Например, если на форме определены три элемента <input>, то свойство elements для той же формы — массив, состоящий из трех объектов (один для каждого элемента в порядке расположения на странице). Каждый член массива — достоверная ссылка на элемент управления; таким образом, чтобы извлечь свойства или методы элементов, ваш сценарий должен производить более глубокий поиск в массиве. Если первый элемент формы — текстовое поле, и вы хотите извлечь строку, находящуюся в поле этого элемента в данный момент (свойство value текстового поля), то ссылка должна выглядеть так. document.forms[0].elements[0].value Обратите внимание на то, что эта ссылка содержит два свойства элементов массива: одно для forms и одно для elements. На практике я рекомендую обращаться к элементам управления формы по их именам, что придаст документу гибкости и предоставит возможность перемещать элементы управления по всей странице, улучшая дизайн документа. При этом вы не должны волноваться о порядке отображения текста в элементах управления. Массив elements удобен при просмотре всех элементов управления в пределах формы. Если ваш сценарий нуждается в цикле просмотра всех элементов формы, производимом с целью поиска определенных типов элементов управления, используйте свойство type каждого объекта формы (NN3+ и IE4+), чтобы идентифицировать, каким видом объекта этот элемент является. Свойство type состоит из той же самой строки, которая задается в атрибуте type дескриптора < input >. Обычно я предпочитаю употреблять смысловые имена элементов управления формы и использовать их в ссылках, встречающихся в сценариях. Массив elements также позволяет использовать имена элементов управления формы. Вместо числового индекса в массиве elements, вы можете применить имя элемента управления. Таким образом, можно создать универсальную функцию, которая обработает любое количество элементов управления формы, и передать строку, содержащую имя элемента управления, как параметр функции. Используйте этот параметр как индекс массива elements. function putVal(controlName, val) { document.forms[0].elements[controlName].value = val; } Если вы хотите изменить число элементов управления на форме, используйте средства управления элементом и/или узлом в браузере (браузерах) по вашему выбору. Например, в Ш4+ и W3C вы можете создать HTML-строку для создания полностью нового набора элементов управления формы, а затем присвоить эту строку свойству innerHTML элемента form. Пример Документ листинга 21.2 демонстрирует принципы использования свойства elements. Его форма содержит четыре текстовых поля и несколько других элементов (рис. 21.2). Первая часть функции, управляющая этими элементами, просматривает форму для поиска текстовых полей и определения пустых элементов. Обратите внимание, как свойство type используется для выделения на форму текстовых полей среди других элементов. Если поле не содержит данных, то на экран выводится сообщение; при этом поле повторно активизируется методом focus (), чтобы пользователь мог немедленно приступить к вводу необходимой информации. Глава 21. Объект form и вложенные в него объекты 661
^3 Elements Array Microsoft Internet Explorer ' ' Q(UQ| : filfr Fdit View FftvoshfeB To«ls Hftlp jf Enter your first name::Theodore Enter your last name: Cleaver ©Male OFemale Enter your address:; Enter your city:! Mayfield □I am retired lyeriiy] VBHMMrlHHFS 1 -«к. 1 1 1 !".-..-■■ ■ >.'•_■■' ■_>: -.■•:■■.'•:•■•■*■--* •л-.А.-.---:-.-;..а 1Ь-.::..;.:..;. -.>.Х-.:Л^Ч* Л*^*Л>У^ Рис. 21.2. Массив элементов формы применяется для поиска только текстовых полей Листинг. 2f.2/1 <html> <head> <title>Elements Array</title> <script type="text/javascript"> function verifyltO { var form = document .forms [0] ; for (i = 0; i < form.elements.length; i++) if (form.elements[i].type == "text" && form.elements[i].value == "") { alert("Please fill out all fields."); form.elements [i] .fociisO ; break; } // другие тесты { } } // другие операторы </script> </head> <body> <form> Enter your first name:<input type="text" name="firstName" /> <p>Enter your last name:<input type="text" name="lastName" /></p> <p><input type="radio" name="gender" />Male <input type="radio" name="gender" />Female</p> <p>Enter your address:<input type="text" 662 Часть III. Объекты документа
name="address" /></p> <p>Enter your city:<input type="text" name="city" /></p> <p><input type="checkbox" name="retired" />I am retired</p> </form> <form> <input type="button" name="act" value="Verify" onclick="verifyIt()" /> </form> </body> </html> См. также: объекты text, textarea, button, radio, checkbox и select. encoding enctype Значение: строка типа MIME Чтение/Запись (см. текст) Совместимость: Winffi6+, MacIE5+, NN6+, Mozl+, Safari 1+ С помощью формы можно предупредить сервер, если отправляемые ему данные представлены в формате другого типа MIME, а свойство encoding содержит значение атрибута enctype, задаваемого при определении формы. Свойство enctype определено для объектов элемента form в W3C DOM (в ней отсутствует свойство encoding), но NN6 поддерживает оба свойства, обеспечивая двустороннюю совместимость. При отправке данных в формате mailto:URL рекомендуется установить это свойство (в дескрипторе или в сценарии) в значение text /plain, чтобы отобразить содержимое формы в теле почтового сообщения. Если определение формььне содержит атрибута enctype, то это свойство — пустая строка. См. также: свойства form.action, form.method. length Значение: целочисленное Только для чтения Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Свойство length объекта элемента form обеспечит вас той же информацией, что и свойство length массива elements формы. Свойство предлагает удобный способ определения количества элементов управления формы. См. также: свойство form. elements. method Значение: строка (GET или POST) Чтение/Запись (см. текст) Совместимость: WinIE3+, MacEE3+, NN2+, Mozl+, Safari 1+ Свойство method формы имеет значение GET или POST (независимо от регистра), назначенное атрибуту method дескриптора <f orm>. Терминология в обоих методах подобна, поэтому будьте внимательны и постарайтесь не перепутать атрибут формы передачи данных на сервер с объектно-ориентированным методом отправки формы, который используется во всех формах JavaScript. Свойство method имеет первостепенное значение важность для HTML-документов, которые представляют данные формы для обработки в серверной CGI-программе, поскольку именно оно определяет способ передачи этой информации. Например, чтобы отправить форму с помощью Глава 21. Объект form и вложенные в него объекты 663
mailto:URL, свойство method должно иметь значение POST. Подробное описание способов отправки форм и вопрос их обработки в CGI-программе выходят за рамки рассматриваемого в этой книге материала (см. документацию к HTML или CGI), где вы узнаете, какую установку необходимо задать для этого атрибута в среде вашего Web-сервера. Если форма не имеет явно определенного атрибута method, то устанавливается значение по умолчанию — GET. См. также: свойства form, action, form, target, form.encoding. name Значение: идентификатор Чтение/Запись Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Присвоение имени форме в атрибуте name проводить не обязательно, однако рекомендуем это сделать, если ваши сценарии ссылаются на форму или ее элементы. Значение такого атрибута можно получить как свойство name формы. Существует немного случаев, когда вам понадобится использовать это свойство. Обычно без него сложно обойтись, если вы обращаетесь к другому документу, содержащему необходимую форму. var formName = parent.frameName.document.forms[0].name; По причине того, что CGI-программы часто полагаются на имя формы при проверке данных, маловероятно, что вам необходимо будет изменить это свойство. target Значение: идентификатор Чтение/Запись (см. текст) Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Всегда, когда HTML-документ отправляет запрос на сервер для обработки, последний обычно возвращает назад HTML-страницу — это может быть стандартный ответ на полученные данные или, более вероятно, страница, содержащая результаты обработки данных. Вы часто сталкиваетесь с подобными ситуациями, выполняя поиск Web-страниц в сети. В многофреймовой или многооконной среде вы можете представить часть возвращаемой страницы в поле зрения пользователя, отобразив ее в отдельном фрейме или окне для просмотра. Цель атрибута target дескриптора <form> состоит в том, чтобы позволить указать, где должен быть отображен ответ, получаемый с сервера. Значение свойства target — это имя окна или фрейма. Например, если вы определяете набор фреймов и назначаете им имена Frame 1, Frame2 и Frame 3, то должны определить одно из этих имен в качестве параметра target дескриптора <f orm>. Браузеры также поддерживают четыре специальных имени целевых объектов, которые вы можете использовать в определении формы: _top, _j?arent, _self, и _blank. Чтобы определить target как отдельное подокно, открываемое с помощью сценария, используйте имя окна, заданное во втором параметре метода window. open (), а не ссылку на объект окна, возвращаемую этим методом. См. также: свойства form. action, form. method, form. encoding. Методы handleEvent (событие) Возвращаемое значение: отсутствует Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Смотрите описание метода window. handlerEvent () в главе 16. 664 Часть III. Объекты документа
reset () Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safaril+ В длинной форме часто добавляют кнопку, которая позволяет пользователю восстановить для всех элементов формы настройки по умолчанию. Стандартная кнопка reset (отдельный тип объекта, описанный в главе 22) отлично справляется с этой задачей. Но если вы хотите очистить форму, используя сценарий, то должны это сделать, вызвав метбд reset () для формы. Наверняка, такой запрос будет инициализироваться вне формы, возможно в результате использования графической кнопки. В последнем случае удостоверьтесь, что на метод reset () формы, для которой вы задаете восстановление значений, задана полная ссылка, даже если текущая страница содержит только одну форму. Пример В листинге 21.3 сброс формы выполняется с помощью атрибута href связанного объекта (присоединен к графическому объекту reset.jpg). В сценарии используется оператор javascript :URL для непосредственного вызова метода reset О (для этого не создается отдельная функция). В нашем примере данные формы передаются на несуществующий узел. Поэтому по щелчку на кнопке Submit вы получите сообщение об ошибке нахождения сервера. Лжт<нг 21.3. Методы f^^ Г ^ <html> <head> <title>Registration Form</title> </head> <body> <form name="entries" method="POST" action="http://www.u\edu/pub/cgi-bin/register"> Enter your first name:<input type="text" name="firstName" /> <p>Enter your last name:<input type="text" name="lastName" /></p> <p>Enter your address:<input type="text" name="address" /></p> <p>Enter your city:<input type="text" name="city" /></p> <p><input type="radio" name="gender" checked="checked" /> Male <input type="radio" name="gender" />Female</p> <pxinput type="checkbox" name="retired" />I am retired</p> </form> <p><a href =" javascript :document.forms [0] .submit () "ximg alt=,,image" src= "submit. jpg" height="25" width="100" border="0" /></a> <a href="javascript:document.forms[0]. reset () "ximg alt="image" src="reset.jpg" height="25" width="100" border="0" /></ax/p> </body> </html> См. также: обработчик события onreset; объект reset. submit () Возвращаемое значение: отсутствует Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Глава 21. Объект form и вложенные в него объекты 665
Наиболее популярный способ отправить данные формы на сервер для обработки в CGI- программе состоит в щелчке мышью на кнопке Submit. Стандартная кнопка Submit в HTML предназначена для того, чтобы отправлять данные всех определенных элементов формы в соответствии со спецификациями, указанными в атрибутах дескриптора <form>. Но если вы хотите отправлять данные формы на сервер автоматически или использовать для этого графическую кнопку, то вправе это сделать с помощью метода form. submit (). Вызов указанного метода — это почти то же, что щелчок на кнопке Submit формы (за исключением того, что onsubmit обработчик события в этом случае не запускается). Поэтому вы можете создать изображение на вашей странице, которое будет представлять графическую кнопку отправки данных на север. Если это изображение заключить в объект ссылки, то по щелчку можно запустить специальную функцию, содержимое которой включает и метод submit () (см. листинг 21.3). В HTML-документе с несколькими формами вы должны сослаться на надлежащую форму или по имени, или согласно ее расположению в массиве document. forms. Старайтесь удостовериться, что ссылка, которую вы определяете в своем сценарии, указывает на желаемую форму перед тем, как вы отправите с ее помощью данные на сервер. Соблюдая меры защиты от несанкционированных посягательств на данные пользователями, посещающими ваш узел, JavaScript игнорирует все методы submit (), действия которых представлены в формате mail :URL. Многие разработчики Web-страниц пожелали бы получить адреса посетителей их страниц. Но поскольку такая систематизация данных может рассматриваться как вторжение в личную жизнь любого человека, подобная возможность была устранена. Однако вы можете использовать кнопку Submit, чтобы получить форму в виде почтового сообщения от браузера. Поскольку метод form, submit () не запускает обработчик события onsubmit формы, проведите любую доступную обработку и проверку данных форм перед их отправкой на сервер в том же самом сценарии, который заканчивается оператором form, submit (). Но при этом не прерывайте процесс отправки данных, инициализированный вызовом метода form. submit (). Операторы сценария, которые следуют после вызова form. submit () — особенно те, которые перемещают пользователей к другим страницам или осуществляют попытку повторной отправки данных, — прерывают процесс первичной передачи данных. См. также: обработчик события onsubmit. Обработчики событий onreset Совместимость: WinIE4+, МасГ£4+, NN3+, Mozl+, Safari 1+ Прежде чем кнопка Reset возвратит форму к настройкам по умолчанюо, JavaScript генерирует в форме событие reset. Включив обработчик события onreset в определение формы, вы можете захватить это событие прежде, чем произойдет восстановление значений по умолчанию. Удачный вариант использования этой особенности состоит в том, чтобы подстраховать пользователя, который случайно щелкает на кнопке Reset после заполнения формы. Обработчик события может вызвать функцию, которая запросит пользователя подтвердить выполненное действие. Обработчик события onreset использует методику, представленную впервые в NN3: он должен содержать оператор return true, обеспечивающий продолжение выполнения функции в браузере. Это может напомнить вам обработчики событий onmouseover и onmouseout, заданные для ссылок и областей изображений. Данное требование гораздо важнее, потому что ваша функция может определить, будет операция обновления в конечном счете проведена или нет. 666 Часть III. Объекты документа
Пример В листинге 21.4 продемонстрирован пример предотвращения случайного сброса или отправки данных формы. Если использовать в форме стандартные кнопки Reset (Сброс) и Submit (Подача запроса), то в описание элемента <f orm> будет добавлено оба обработчика событий. Каждый обработчик будет вызывать собственную функцию, выводящую пользователю сообщение о выполняемых действиях. Обратите внимание на использование ключевого слова return и применение булевых значений. <html> <head> <title>Submit and Reset Confirmation</title> <script type="text/javascript"> function allowResetO { , return window.confirm("Go ahead and clear the form?"); } function allowSendO { return window.confirm("Go ahead and mail this info?"); } </script> </head> <body> <form method="POST" enctype="text/plain" action="mailto:trash4@dannyg.com" onreset="return allowResetO" onsubmit="return allowSendO"> Enter your first name:<input type="text" name="firstName" /> <p>Enter your last name:<input type="text" name="lastName" /></p> <p>Enter your address:<input type="text" name="address" /></p> <p>Enter your city:<input type="text" name="city" /></p> <p><input type="radio" name="gender" checked="checked" /> Male <input type="radio" name="gender" />Female</p> <pxinput type ="checkbox" name= "retired" />I am retired</p> <p><input type="reset" /> <input type="submit" /></p> </form> </body> </html> onsubmit Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Независимо от того, как данные формы переданы на сервер (пользователем, щелкнувшим на кнопке Submit, или сценарием, вызвавшим метод form.submit ()), вы можете пожелать, чтобы ваш HTML-документ, допускающий использование JavaScript, провел проверку данных, полученных от пользователя (особенно из текстовых полей), перед отсылкой этой информации на сервер. Вы имеете возможность выполнить подобную проверку данных непосредственно во время их введения пользователем (см. главу 43) или в пакетном режиме перед отправкой данных на сервер (а также обоими способами). Место, в котором можно запустить окончательную проверку данных,— обработчик события onsubmit. Обратите внимание, Глава 21. Объект form и вложенные в него объекты 667
что это событие генерируется только для исходного объекта Submit элемента типа <input>, а не благодаря методу submit () формы. Когда вы определяете обработчик события onsubmit как атрибут дескриптора <form>, JavaScript отправляет событие submit в форму непосредственно перед тем, как она передает свои данные на сервер. Поэтому любой сценарий или функция, которые являются параметром onsubmit, выполняются прежде, чем данные фактически передаются на обработку. Обратите внимание, что этот обработчик события активизируется только в ответ на использование кнопки Submit, а не в результате выполнения методом form, submit (). Любой код, выполненный из обработчика события onsubmit, должен содержать выражение, состоящее из слова return и булевого значения. Если булево значение равно true, передача данных выполняется, как обычно; если значение равно false, то отправка данных не выполняется. Поэтому, если ваш сценарий выполняет проверку данных перед их передачей на сервер, удостоверитесь, что обработчик события вызывает функцию проверки данных как часть оператора return (см. листинг 21.4). Даже после того, как обработчик события onsubmit перехватит передачу данных, система защиты данных JavaScript может отобразить дополнительные предупреждения пользователю (что зависит от расположения конечного сервера). Объекты элементов fieldset и legend Свойства, методы и обработчики событий этих элементов описаны в главе 15. Свойства Методы Обработчики событий align form Синтаксис Доступ к свойствам или методам объектов элементов fieldset и legend. (IE4+) [window. ] document. all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document. get Element By Id ("идентификатор") . свойство | метод ( [параметры] ) Совместимость: WinIE4+, MacEE4+, NN6+, Mozl+, Safari 1+ Описание объектов Элементы fieldset и legend используются совместно для обеспечения пользователя дополнительными контекстными данными о наборе элементов управления формы в пределах самой формы. Браузеры, которые поддерживают элемент fieldset, создают прямоугольник вокруг области документа, который содержит элементы управления формы, вложенные внутрь этого элемента. Прямоугольная область занимает всю ширину формы, если ширина не задается в соответствующих свойствах стилей (например width). К этой прямоугольной области добавляется текстовая надпись, которая определяется в элементе legend, вложенном внутрь элемента fieldset. Ни один из этих элементов группы не требуется, если в макете страницы уже содержатся графические элементы, которые позволяют группировать элементы управления формы. 668 Часть III. Объекты документа
Правильность вложения элементов имеет первостепенное значение для получения в браузере необходимого вида документа. Типичный HTML-код этих элементов выглядит следующим образом. <form> <fieldset> <legend>Legend Text</legend> Элементы управления и их подписи. </fieldset> </form> Вы можете иметь больше одного элемента fie Ids et внутри формы. Каждый набор имеет прямоугольник, добавленный вокруг него. Это помогает организовать длинную форму в четко разграниченные для пользователей разделы элементов управления — одна-единствен- ная форма сохраняет свою целостность для отправки на сервер. Элемент f ieldset управляется подобно любому другому HTML-контейнеру, в котором поддерживаются стили и принцип наследования. Например, если вы устанавливаете стиль color свойства элемента f ieldset, то цвет задается для текста элементов, расположенных внутри него; однако цвет границы, нарисованной браузером, остается неизменным. При изменении стиля color-border свойства элемента f ieldset в указанный цвет окрашивается только граница, а не текстовое содержимое вложенных элементов. Обратите внимание, что содержимым элемента legend может быть любой HTML-код. Вы можете задать любое правило таблицы стилей для элемента legend. Если в ваших сценариях необходимо изменить текст подписи, то это можно выполнить с помощью свойства innerText (Ш4+), innerHTML (Ш4+, NN6+) или node Value (IE5+, NN6+) объектов элементов. Только два действительно специфических свойства элементов имеет эта пара объектов. Первое— это align— свойство объекта legend. Это свойство соответствует атрибуту align этого элемента, как определено в описании HTML 4.0 (хотя свойство осуждается в пользу правил таблиц стилей). ГЕ5+ для Мае и ГЕ5.5+ для Windows позволяют изменить это свойство "на лету" (задавая выравнивание по правому или левому краю). В результате вы можете изменить расположение надписи в верхней части раздела элементов управления. Поскольку эти элементы — дочерние объекты элемента form, неудивительно, что в спецификации DOM 2 для них определяется доступное только для чтения свойство form. Это свойство возвращает ссылку на объект элемента form, который включает любой из указанных элементов. Свойство form для объектов f ieldset и legend реализовано только в МасШ5 и NN6. Объект элемента label Свойства, методы и обработчики событий этих элементов описаны в главе 15. Свойства Методы Обработчики событий form htmlFor Синтаксис Доступ к свойствам или методам объекта элемента label. (IE4+) [window. ] document. all. идентификатор. свойство \ метод [параметры] ) (IE5+/W3C) [window. ] document.getElementByld{"идентификатор") . свойство | метод ( [параметры] ) Глава 21. Объект form и вложенные в него объекты 669
Описание объекта Чтобы обеспечить контекстные дескрипторы для каждого бита содержимого страницы, рабочая группа W3C по развитию HTML заполнила пробел, который представлял текст, отображаемый на/или возле элементов управления input, select и textarea формы. Этот текстовый фрагмент используется в большинстве случаев как надпись, описывающая назначение элемента управления. Только элемент input, который имеет специальный атрибут для представления надписи, относится к кнопочному типу элементов ввода. Элемент label позволяет заключить текст надписи элемента управления в контекстный дескриптор. Кроме того, один из атрибутов элемента — for — позволяет связать надпись со специфическим элементом управления формы. В HTML атрибуту for назначен идентификатор элемента управления, с которым связана надпись. Элемент label связывается с элементом управления формы, если дескриптор элемента управления формы содержится между открывающим и закрывающим дескрипторами элемента label. На первый взгляд, браузеры не делают ничего специального (с точки зрения представления данных) для отображения элемента label. Но для некоторых типов элементов, особенно для переключателя и флажка, они помогают сохранить жизненно важное удобство пользовательского интерфейса: щелчок кнопкой мыши на надписи означает то же самое, что и щелчок на элементе управления. Для текстовых полей события активизации, которые добавляются к ним, также добавляются и для надписи. Фактически, все события, которые определены для надписи, передаются элементу управления формы, связанному с ней. Следующий фрагмент страницы демонстрирует, как элементы f ieldset, legend и label выглядят на форме, состоящей из двух переключателей. <form ...> <fieldset id="formlsetl"> <legend id="formlsetllegend">Choose the Desired Per£ormance</legend> <input type="radio" name="speed" id="speedl" /> <label for="speedl">Fastest (lower-quality) </labelxbr /> <input type="radio" name-"speed" id="speed2" /> <label for="speed2">Slower (best quality)</label> </fieldset> </form> Даже в этом случае label и связанный с ним элемент управления формы не обязательно должны быть смежными в исходном коде. Например, вы можете задать надпись в одной ячейке строки таблицы, а сам элемент управления формы — в другой (в той же самой или другой строке таблицы). Свойства html For Значение: ссылка на объект элемента Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство html For — сценарный эквивалент атрибута for элемента label. Допустимое значение — полная ссылка на элемент управления формы (объект элемента input, textarea или select). Маловероятно, что вы будете изменять это свойство для существующего элемента label. Однако, если ваш сценарий создает новый элемент label, используйте это свойство, чтобы связать надпись с элементом управления формы. 670 Часть III. Объекты документа
Объект кнопки та глава посвящена таким элементам, как кнопки, которые позволяют пользователям активизировать с помощью щелчка определенные действия. К этой категории относятся стандартные кнопки системы, содержащие надписи, а также переключатели и флажки. Однако словарь свойств, методов и обработчиков события для этих инструментов форм HTML является довольно ограниченным. Я сгруппировал вместе объекты button, submit и reset по одной важной причине: функционально они выгладят одинаково, хотя и предназначены для выполнения различных задач. Важно научиться правильно использовать кнопки, а особенно — понимать различия между объектами button и submit. Многие начинающие разработчики пугают эти два объекта и сталкиваются со множеством проблем. Этого не случится, если вы внимательно изучите материал данной главы. Объект элемента button, объекты button, submit и reset Свойства этого элемента, его методы и обработчики события описываются в главе 15. Свойства form name type value Методы click() Обработчики события onclick onmousedown onmouseup Синтаксис Доступ к свойствам и методам объекта button. (Все) [window.]document.имяФормы.имяКнопки. свойство | метод ( [параметры] ) (Все) [window.]document.имяФормы,elements [индекс] . свойство \ метод ( [параметры] )
(Все) [window. ] document. forms [индекс] . имяКнопки. свойство \ метод ( [параметры] ) (Все) [window.]document.forms["имяФормы"] .имяКнопки.свойство\метод ( [параметры] ) (Все) [window.]document.forms["имяФормы"] .elements[индекс] .свойство\ метод ( [параметры] ) (IE4+) [window. ] document. all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document. getElementBylD ("идентификатор" ) . свойство \ метод( [параметры] ) Описание объектов В зависимости от операционной системы, с которой запускается браузер, объекты button генерируют на странице стандартные элементы интерфейса в виде знакомых пользователю кнопок. Раньше для генерации этих стандартных элементов интерфейса браузер обращался к операционной системе. Предыдущие версии браузеров самостоятельно определяли внешний вид кнопок, хотя он и отличался в разных операционных системах. Сравнительно недавно на вид t кнопок стали влиять особенности настроек браузера, которые заложены в него разработчиками. Но несмотря на все это, любой пользователь компьютера легко узнает на странице кнопку. Начиная с ТЕЛ и NN6, существует два способа использования кнопок на странице. Первый, обеспечивающий полную обратную совместимость, заключается в использовании элементов input, вложенных в контейнер form. Новый элемент HTML, button, предоставляет несколько отличный способ задания на странице кнопки; он включает параметр, который позволяет использовать кнопку внутри контейнера form (возможно, для выполнения некоторых клиентских сценариев, не зависимых от операции отправки данных формы). С точки зрения HTML, различие между этими двумя подходами касается способа определения надписи кнопки. С помощью элемента input строка, присвоенная атрибуту value, становится надписью кнопки. Во втором случае элемент button является контейнером (имеющим закрывающий дескриптор), содержимое которого становится надписью кнопки. Тем не менее, в последнем случае вы можете задать атрибуту value определенное значение, которое (если форма содержит кнопку) впоследствии отправляется на сервер как часть данных и независимо от текста надписи. Прежде чем присвоить кнопке надпись, хорошо все продумайте. Поскольку использование кнопки подразумевает выполнение определенного действия, убедитесь, что термин, содержащийся в тексте надписи, четко определяет действие, совершаемое после щелчка на ней. Кроме того, прислушайтесь к советам профессиональных дизайнеров интерфейсов, которые разрабатывают операционные системы и коммерческое программное обеспечение: будьте лаконичны. Если надпись на кнопке содержит более двух-трех слов, пересмотрите дизайн своей страницы, чтобы посетитель мог четко уяснить назначение каждой кнопки из более краткого текста. Браузеры автоматически изменяют размер кнопки в соответствии с длиной текста надписи. Но только браузеры, которые поддерживают таблицы стилей (Ш4+ и NN6+), позволяют управлять другими параметрами внешнего вида кнопок (например, шрифтом надписи, его размером и цветом). Что касается положения кнопки на странице, то она, как и все внедренные на форму элементы, размещается там, где задается исходный код. Конечно, можно использовать свойство позиционирования, поддерживаемое последними версиями браузеров (глава 39), чтобы поместить кнопку там, где необходимо. Но если просмотреть ваши Web- страницы в различных операционных системах и в разных версиях браузеров, то можно легко убедиться, что вид (и размер) кнопки не будет одинаковым. Постарайтесь просмотреть результаты на максимально доступном количестве платформ. 672 Часть III. Объекты документа
Кнопки в среде Windows ведут себя стандартно, т.е. активизируются при выделении текста надписи (обычно заключаются в пунктирный прямоугольник). Некоторые новые версии браузеров, работающие в операционных системах, отличных от Windows, предлагают этот вид выделения и подсвечивания как пользовательский параметр. Ш5 поддерживает дополнительное средство элемента input, которое не позволяет кнопке при активизации выделяться пунктирным прямоугольником. Обработчик события для отдельной кнопки, который выполняется во всех версиях браузеров и запускает назначенное действие, когда пользователь щелкает на кнопке,— это onclick. Фактически все действия, относящиеся к объекту button, связаны с этим обработчиком события. Вряд ли вам придется задавать значения свойств или вызывать метод click (этот метод некорректно работает в браузере NN3) данного объекта. Браузеры NN4 и ТЕЛ поддерживают дополнительные события составляющих щелчка: mousedown и mouseup; а браузеры Ш4+ и NN6+ обеспечивают кнопки рядом других инициируемых пользователем событий. Два специальных варианта объекта button — это submit и reset. Появились они в ранних версиях HTML. Эти две кнопки предназначены для выполнения специальных операций. Кнопка submit автоматически отправляет данные из текущего объекта формы по адресу URL, указанному в атрибуте action дескриптора <form>. Атрибут method описывает формат, в котором данные отправляются с помощью кнопки. Следовательно, это действие не следует изменять, если вы предусматриваете обмен данными между HTML-страницей и CGI- программой, которая находится на сервере. Если для атрибута формы action задается значение mail to :URL, то на странице необходимо разместить кнопку Submit (Отправить), которая будет выполнять необходимое действие. Заданное для атрибута enctype значение plain/text также часто используется для отправки данных из формы в более доступной форме, чем обычные кодированные пары значений. Подробно об отправке данных из формы в виде почтового сообщения рассказывалось в предыдущей главе. Рядом с кнопкой Submit (Подача запроса) часто встречается кнопка Reset (Сброс). Эта кнопка также имеет специфическую функцию. Щелчок на ней восстанавливает заданные по умолчанию значения для всех элементов формы. Это действительно для текстовых объектов, групп переключателей, флажков и выделенных в списке элементов. Чаще всего такая кнопка используется для очистки введенных пользователем значений полей. Все три типа кнопок, используемых в дескрипторе < input > или <button>, отличаются друг от друга значением атрибута type. Для кнопок, которые не предназначены для отправки данных на сервер, используется тип button (задаваемое по умолчанию значение для элемента button). Значения submit и reset применяются для выполнения специальных задач. Если вы хотите, чтобы во всех поддерживаемых браузерах роль кнопки выполняло графическое изображение, свяжите с ним соответствующую ссылку (см. описание объекта link в главе 19) или создайте клиентскую карту изображения (см. описание объекта area в главе 20). Но в браузерах Ш4+ и NN6+ можно использовать элемент input, для атрибута type которого задано значение image (см. далее в этой главе). Вероятно, самая большая ошибка при написании сценариев с использованием этих кнопок— применение кнопки Submit для выполнения обычных задач, возлагаемых на пользовательскую кнопку. Поскольку эти две кнопки выглядят одинаково, а тип submit элемента input имеет более длинную историю, их очень легко перепугать между собой. Но если вы хотите разместить на странице кнопку, которая запускает на выполнение серверную часть сценария, используйте пользовательский вариант. Кнопка Submit предназначена исключительно для отправки данных формы. Если не задается атрибут action, то страница перезагружается, а все заданные значения полей очищаются. Обычная же кнопка выполняет возложенные на нее обязанности без перезагрузки страницы (если это специально не предусмотрено сценарием). Глава 22. Объект кнопки 673
Свойства form Значение: ссылка на объект form Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство каждого объекта элемента input является ссылкой на элемент form, который содержит элементы управления. Это свойство может быть очень удобным при написании сценария, в котором вы управляете одним элементом управления формы, передаваемым в качестве параметра функции, и хотите получить доступ к другому элементу управления в этой же форме или вызвать метод управления формой. Обработчик события любого элемента input может передавать в качестве параметра ключевое слово this, а функция получает доступ к форме без задания в сценарии полной формы именной ссылки. См. также: объект form. name Значение: идентификатор Чтение/Запись (см. текст) Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Имя кнопки фиксируется в атрибуте name элемента input или button и может быть изменено в сценарии только в новых версиях браузеров. Возможно, вам понадобится извлечь это свойство для использования в универсальной функции обработчика событий, которая вызывается в документе несколькими кнопками. Такая функция может проверить имя кнопки и выполнить для данной кнопки соответствующий оператор. Если изменить имя этого объекта, то перезагрузка страницы или задание нового целевого окна восстановит его исходное имя. См, также: свойство value текстового объекта. type Значение: строка Только для чтения Совместимость: WinIE4+, МасЮ4+, NN6+, Mozl+, Safari 1+ Значение свойства type аналогично значению атрибута type дескрипторов < input> и <button>, которое определяет тип элемента управления формы: button, submit или reset. value Значение: строка Чтение/Запись (см. текст) Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Оба объекта (input и button) имеют атрибут value, который представляет свойство value в объектной модели документа. Но назначение этого атрибута-свойства в каждом объекте разное. В элементе input свойство value представляет надпись, отображаемую на кнопке. В элементе button текст надписи представлен содержимым соответствующего дескриптора. В обоих случаях при задании элементу атрибута name пара имя-значение отправляется на сервер вместе с другими данными формы (предполагается, что элемент button расположен на форме). Если не задать значение атрибута value для кнопок отправки данных и обновления параметров формы, то этим кнопкам автоматически будут назначены надписи Reset и Submit. В качестве значения атрибута допускается использовать строку, состоящую из нескольких слов. 674 Часть III. Объекты документ»
Значение свойства value можно изменить "на лету" в ходе выполнения сценария. При этом будьте предельно внимательны. Браузеры, вышедшие ранее NN6 и Ш4, не позволяют изменить размер кнопки в соответствии с новым значением, определенным в сценарии. Тем не менее, перезагрузка документа или определение для него нового целевого окна обеспечивают необходимое изменение размеров элемента. NN6 и IE4+ изменяют размер кнопки при замене надписи без дополнительной перезагрузки формы. При этом размер страницы изменяется соответствующим образом. В Ш4 для Мае это свойство также поддерживается, но пользоваться им часто не приходится. См. также: свойство value текстового объекта. Методы clickO Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Метод click () кнопки с помощь сценария имитирует щелчок пользователя на кнопке. К сожалению, этот метод не выполняется в ранних версиях браузеров, вышедших до IE4 и NN4. См. также: обработчик события onclick. Обработчики события onclick Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Почти все действия кнопок выполняются в ответ на обработчик события onclick. Щелчок подразумевает нажатие и последующее отпускание кнопки мыши, когда указатель находится над кнопкой. Событие для кнопки наступает только после того, как пользователь отпустит кнопку мыши. Для кнопки Submit, вероятно, следует опустить обработчик события onclick и позволить обработчику события onsubmit позаботиться о проверке введенных данных перед отправкой их на сервер. При запуске процедуры проверки данных с помощью обработчика события onsubmit ваши сценарии могут отменить отправку данных формы, если данные формы введены некорректно (см. описание объекта form в главе 21). Пример В листинге 22.1 продемонстрировано не только использование обработчика onclick, но и свойств name и values кнопки. Обработка всех этих программных элементов выполняется в функции общего назначения, которая управляет сразу несколькими кнопками. В данном случае каждая кнопка передает в функцию displayTeamO собственное значение. Результат функция выводит в диалоговом окне сообщения. В примерах из реальной жизни используются более совершенные конструкции if. . . else, поскольку реакция на щелчок мышью на кнопке в них несколько сложнее. (В браузерах Ш4+ и W3C также применяется оператор switch по отношению к выражению btn. value.) Глава 22. Объект кнопки 875
<html> <head> <title>Button Click</title> <script type="text/javascript"> function displayTeam(btn) { if (btn.value == "Abbott") { alert("Abbott & Costello"); } if (btn.value == "Rowan") { alert("Rowan & Martin"); } if (btn.value == "Martin") { alert("Martin & Lewis"); </script> </head> <body> Click on your favorite half of a popular comedy team: <form> <input type="button" value="Abbott" onclick="displayTeam(this)" /> <input type="button" value="Rowan" onclick="displayTeam(this)" /> <input type="button" value="Martin" onclick="displayTeam(this)" /> </form> </body> </html> См. также: обработчики события button.onmousedown, button.onmouseup, form.onsubmit. onmousedown onmouseup Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Более современные версии браузеров поддерживают обработчики события для компонентов события click— onmousedown и onmouseup. Вместе они представляют единый обработчик события onclick. Системные кнопки, отображаемые операционной системой, при щелчке на них изменяют свой вид. Тем не менее, захват компонентов события щелчка не поможет вам изменить вид кнопки с помощью сценария. Запомните, что при нажатии кнопки пользователь может свести с нее указатель мыши. Когда указатель смещается за область кнопки, ее вид изменяется на исходный (в отжатом положении). Но далеко не все настройки, выполняемые в обработчике события onmousedown, будут восстанавливаться соответствующим обработчиком события onmouseup (даже после того, как пользователь отпустит кнопку мыши в произвольном месте документа). С другой стороны, если вы загрузите в кэш-память звуки, воспроизводимые при нажатии и отпускании кнопки, то использовать эти события для их воспроизведения в ответ на действия мыши вполне возможно. См. также: обработчики событий button, onclick. 676 Часть III. Объекты документа
Объект checkbox Свойства, методы и обработчики события этого HTML-элемента описываются в главе 15. Свойства Методы Обработчики события checked clickO* onclick* form* name* type value * См. объект Button Синтаксис Доступ к свойствам и методам объекта checkbox. (Все) [window. ] document. имяФормы. имяФлажка. свойство \ метод ( [параметры] ) (Все) [window.]document.имяФормы,elements[индекс].свойство\метод ( [параметры] ) (Все) [window. ] document. forms [индекс] . имяФлажка. свойство \ метод ( [параметры] ) (Все) [window. ] document. forms [" имяФормы" ] . имяФлажка . свойство | метод ( [параметры] ) (Все) [window. ] document. forms [ "имяФормы" ] . elements [индекс] . свойство | метод ( [параметры] ) (IE4+) [window. ] document. all. идентификатор♦ свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document.getElementByld ("идентификатор") . свойство| метод( [параметры] ) Описание объекта Элемент checkbox (флажок) выполняет особую задачу при разработке современного пользовательского интерфейса: он является переключателем между состояниями "включено" и "выключено". Как и флажок на стандартной анкете, галочка в квадратике указывает на то, что данный параметр верен или его следует включить для данного конкретного случая. Если флажок не установлен или квадратик пуст, соответствующий параметр не верен или этот параметр следует исключать. Если группируются два или более флажков, они не должны взаимодействовать: каждый из них задается независимо друг от друга (см. описание объекта radio для переключателей). Я применяю эти элементы пользовательского интерфейса в самом начале формы для того, чтобы обеспечить Web-страницу унифицированным'интерфейсом, к которому пользователь привык, работая с другими программами. Объекты checkbox необходимо использовать только для включения или выключения выбранных пользователем параметров. Например, не рекомендуется использовать флажки в качестве кнопок, которые загружают другой адрес URL. Как и в диалоговых окнах Windows или Мае, с помощью флажков или переключателей Глава 22. Объект кнопки 677
пользователи устанавливают параметры, а при щелчке на стандартной кнопке или карте изображения инициируют выполнение необходимых действий. Это не значит, что объект checkbox может выполнять только некоторые ограниченные действия в ответ на щелчок пользователя, но подобные действия обычно относятся к контексту самой формы. Например, в некоторых диалоговых окнах Windows и Мае установка флажка может активизировать несколько других неактивных параметров, указанных в этом же диалоговом окне. Браузеры ГЕ4+ и NN6+ позволяют сделать недоступными или скрыть элементы формы. В подобных случаях объект checkbox применяется для управления атрибутами отображения соответствующих элементов управления. Кроме того, в окне, состоящем из двух фреймов, объект checkbox одного фрейма может управлять представлением данных в другом. При этом содержимое другого фрейма может детализироваться до необходимого уровня сложности. Установка флажка изменяет уровень насыщенности данными документа другого фрейма (для каждого уровня сложности загружается свой документ с другого адреса URL). Таким образом, в нижней части окна можно использовать флажки для переключения между несколькими состояниями страницы. Для инициализации обработки заданных настроек добавьте на страницу обычные кнопки. В дескрипторе < input > для объекта checkbox можно указать выставлять флажок при загрузке страницы. Для этого в его определении укажите атрибут checked. Если по умолчанию опустить этот атрибут, то будут отображаться пустые квадратики флажков. Текст надписи задается содержимым дескриптора < input >. Если проанализировать поведение объекта checkbox в браузерах HTML, то такое положение вещей имеет определенный смысл: текст надписи не является активной частью объекта checkbox (как это обычно бывает в стандартном пользовательском интерфейсе Windows или Macintosh, где щелчок на тексте надписи равносилен выставлению флажка). Задание имени для объекта checkbox является важной частью определения объекта (в зависимости от того, как вы хотите использовать в сценарии или документе эту информацию). Для форм, содержимое которых используется в CGI-программе на сервере, имя объекта необходимо задать таким образом, чтобы программа могла проанализировать данные из формы и извлечь значение указанного объекта. Для использования в клиентском JavaScript- сценарии можно присвоить не только понятные имена, описывающие этот объект, но и указывать значения, которые используются в условных конструкциях if. . .else или включаются в строки, которые впоследствии будут отображаться в окне или фрейме. Свойства checked Значение: булево Чтение/Запись Совместимость: Winffi3+, МасГ£3+, NN2+, Moz 1 +, Safari l+ Простейшее свойство объекта checkbox указывает (или позволяет задать), установлен ли флажок. Для установленного флажка задается значение true, а для неустановленного — false. Для того чтобы установить флажок с помощью сценария, следует просто присвоить значение true для свойства checked объекта checkbox. document.forms[0].имяФлажка.checked = true; Задание свойства checked с помощью сценария не запускает событие click для объекта checkbox. Возможно, вам понадобится сделать так, чтобы установка одного флажка автоматически выставляла другой флажок в другой области этой же или другой формы определенного документа. 678 Часть III. Объекты документа
Для выполнения этой задачи следует задать обработчик события onclick для одного объекта checkbox и написать оператор обработки события одного флажка, в котором для другого задается значения true соответствующего свойства. Однако этим не следует увлекаться чрезмерно: для группы связанных, взаимно исключающих параметров лучшие использовать группу переключателей. Если дизайн вашей страницы подразумевает, что флажок будет установлен после загрузки страницы, не следует специально писать сценарий для выполнения этого действия. Просто добавьте к дескриптору < input > атрибут checked. Поскольку свойство checked является булевым значением, его результаты можно использовать в качестве аргумента оператора if, как показано в следующем примере. Пример Простой пример использования свойства checked приведен в листинге 22.2. В единственную функцию документа подставляется ссылка на объект формы. Функция же считывает свойства checked объекта флажка (checkThis. Checked) и использует полученное булево значение как условие в конструкции if . . .else. <html> <head> <title>Checkbox Inspectors/title> <script type="text/javascript"> function inspectBox(form) { if (form.checkThis.checked) { alert("The box is checked."); } else { alert("The box is not checked at the moment."); </script> , </head> <body> <form> <input type="checkbox" name="checkThis" />Check here <pxinput type= "button" name="boxChecker" value="Inspect Box" onclick="inspectBox(this.form)" /></p> </form> </body> </html> См. также: свойства def aultChecked, value. defaultChecked Значение: булево Только для чтения Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Если добавить в дескриптор < input > определения объекта checkbox атрибут checked, то свойство def aultChecked для данного объекта будет иметь значение true; в противном случае, для свойства будет использоваться значение false. Полученный доступ к этому свойству позволит сценарию изменить состояние флажков (или пользователем, если сценарий не задает этого свойства). Глава 22. Объект кнопки 679
Пример Функция в листинге 22.3 используется для сравнения текущего значения флажка со значением по умолчанию. Для этого была применена конструкция if. Оба сравниваемых значения имеют булев тип, поэтому в представленной операции нет ничего противоречивого. Если текущее значение и значение по умолчанию не совпадают, то функция изменяет свое поведение. 9ЩЩР(/^щ^!РЩ'^вШщ^щя ФШщ^РцЩЩ^^Ф Ф^ПфЧпКЯ'р^Р зч|ЧМ^Ч"^ИрЛ* m\*AA.4RV**VW^^ function compareBrowser(thisBox) { if (thisBox.checked 1= thisBox.defaultChecked) { // операторы разных HTML-страниц См. также: свойства checked, value. type Значение: строка (checkbox) Только для чтения Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Используйте свойство type для идентификации объекта checkbox в неизвестной группе элементов формы. См. также: свойство form, elements. value Значение: строка Чтение/Запись Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Свойство value объекта checkbox представляет собой строку произвольного текста, который можно связать с соответствующим флажком. Обратите внимание, что свойство value объекта checkbox является не надписью, как в случае использования обычной кнопки, а скрытым текстом, связанным с данным флажком. Например, надпись объекта checkbox не несет важной информации, которую можно использовать в сценарии. Но если присвоить нужные данные атрибуту value соответствующего дескриптора, то эту строку можно извлечь с Помощью свойства value. При отправке данных объекта checkbox в CGI-программу свойство value отправляется как часть пары имя-значение установленного флажка (если флажок не установлен, то никакая информация не передается). Если опустить атрибут value при задании объекта checkbox, то при установленном флажке это свойство всегда будет наследовать строку on, которая отправляется в программу CGI. При работе с JavaScript не следует путать эту строку с параметрами объекта checkbox: on и off; для определения состояния флажка используйте свойство checked. Пример Сценарий листинга 22.4, создающий основу HTML-страницы, отображает форму с единственным флажком, состояние которого определяет, какой из вариантов отправки данных на сервер реализуется в текущий момент. После щелчка на кнопке Подача запроса (Submit) функция JavaScript определяет значение свойства checked флажка. Если оно равно true (флажок установлен), то сценарий устанавливает свойство action всей формы в значение свойства value. Если вы протестируете этот листинг в локальном компьютере, то полученный результат будет зависеть от используемого браузера. В большинстве случаев на экран 680 Часть III. Объекты документа
(или в диалоговое окно) будет выведено сообщение о том, что имен primaryURL или alternativeURL не существует. Тем не менее, Ш5.5 не отображает имя файла, который невозможно открыть. По возможности не используйте этот браузер для изучения приводимого примера. Все сообщения и названия в ошибках выдуманы специально для данного примера. Листинг 22Л Настрой <html> <head> <title>Checkbox Submission</title> <script type="text/javascript"> function setAction(form) { if (form.checkThis.checked) { form.action = form. checkThis .value,- } else { form.action = "file://primaryURL"; } return true; } </script> </head> <body> <form method="POST" action=""> <input type="checkbox" name="checkThis" value="file://alternateURL" />Use alternate <p><input type="submit" name="boxChecker" onclick="return setAction(this.form)" /></p> </form> </body> </html> См. также: свойство checked. Методы click() Возвращаемое значение: отсутствует Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safaril+ Назначение метода click () состоит в выполнении с помощью сценария физического действия установки флажка (но без вызова обработчика события onclick). К сожалению, этот метод не выполняется должным образом в браузерах NN2 или NN3. Даже если описываемый метод работает безупречно, при написании сценария рекомендуется использовать свойство checked, чтобы абсолютно точно знать, какой параметр установлен для данного флажка. См. также: свойство checked, обработчик события onclick. Обработчики события onclick Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Поскольку пользователи регулярно устанавливают и снимают флажки, эти объекты обладают обработчиком события для события click. Используйте такой обработчик события Глава 22. Объект кнопки 681
только в том случае, если хотите, чтобы ваша страница (или скрытые значения переменной) тем или иным образом реагировала на установку флажка. Многие действия пользователя, как уже отмечалось ранее, инициируются не выставлением флажков, а щелчком на стандартных кнопках, поэтому будьте внимательны и не увлекайтесь использованием обработчиков событий для объектов checkbox. Пример Пример захвата события щелчка объекта флажка приведен в листинге 22.5. Обработчик данного события позволяет отображать и скрывать другие элементы формы. После установки флажка Monitor на странице появится список переключателей, которые указывают размер монитора. Подобным образом, флажок Communications позволяет ознакомиться с двумя переключателями используемого сетевого соединения. Выбор одного из двух последних вариантов приводит к дальнейшему расширению формы на четыре переключателя (рис. 22.1). Flit EdH Vtaw FflvtritM Toete H«tp ф Check яП accessories for your computer: I ! П Monitor i ! 0 Communications 0 Modem О Network О <56kbps О 56kbps OISDN (any speed) О Cable 1 Рис. 22.1. Щелчок на элементе управления приводит к отображению дополнительных элементов управления Обратите внимание на универсальность функции toggle (). Она принимает ссылку на любой объект флажка и любой связанный с ним элемент span. Если в таблице использовать не более пяти групп флажков, то вполне можно обойтись одной этой функцией. В функции swap () для преобразования булевого значения свойства checked в строковое значение (принимает свойство display) используются вложенные конструкции if. . .else. Вложенность конструкций обеспечивает соблюдение двух условий в одном операторе: обработка сразу двух элементов управления и вызов функции в свойстве checked. Эта функция далеко не универсальная, поскольку она содержит явные ссылки на объекты документа. Чтобы сделать ее универсальной, вам понадобится ввести много дополнительного кода в ссылках. 682 Часть III. Объекты документа
<html> <head> <title>Checkbox Event Handler</title> <style type="text/ess"> #monGroup (visibility:hidden! #comGroup {visibility:hidden} </style> <script type="text/javascript"> function toggle(chkbox, group) { var visSetting = (chkbox.checked) ? "visible" : "hidden"; document.getElementById(group).style.visibility = visSetting; } function swap(radBtn, group) { var modemsVisSetting = (group == "modems") ? ((radBtn.checked) ? "" : "none") : "none"; var netwksVisSetting = (group == "netwks") ? ((radBtn.checked) ? "" : "none") : "none"; document.getElementById("modems").style.display = modemsVisSetting; document.getElementById("netwks").style.display = netwksVisSetting; } </script> </head> <body> <form> <h3>Check all accessories for your computer:</h3> <table border="2" cellpadding="5"> <tr> <td><input type="checkbox" name="monitor" onclick="toggle(this, 'monGroup')" />Monitor</td> <tdxspan id="monGroup"><input type="radio" name="monitorType" />15" <input type="radio" name="monitorType" />17" <input type="radio" name="monitorType" />21" <input type="radio" name="monitorType" />&gt;21"</spanx/td> </tr> <tr> <td><input type="checkbox" name="comms" onclick="toggle(this, 'comGroup')" /> Communications</td> <tdxspan id="comGroup"xpxinput type ="radio" name="commType" onclick="swap(this, 'modems')" /> Modem <input type="radio" name="commType" onclick=" swap (this, 'netwks')" />Ne/twork</p> <pxspan id="modems" style="display:none"xinput type="radio" name="modemType" />&lt;56kbps <input type="radio" name="modemType" />56kbps <input type="radio" name="modemType" />ISDN (any speed) <input type="radio" name="modemType" />Cable</span> <span id="netwks" style="display:none"><input type="radio" name="netwkType" />Ethernet 10Mbps (10-Base T) <input type="radio" name="netwkType" /> Ethernet 100Mbps (10/100) <input type="radio" name="netwkType" />T1 or greater</span> &nbsp; </px/spanx/td> Глава 22. Объект кнопки 683
</tr> </table> </form> </body> </html> См. также: обработчики событий мыши. Объект radio Свойства Методы Обработчики события См. объект checkbox Синтаксис Доступ к свойствам или методам объекта radio. (Все) [window. ] document. имяФормы. имяГруппыПереключателей [индекс] . свойство | метод ( [параметры] ) (Все) [window.]document.имяФормы.elements[индекс].свойство\метод { [параметры] ) (Все) [window. ] document. forms [индекс] . имяГруппыПереключателей [индекс] . свойство | метод ( [параметры] ) (Все) [window.]document.forms["имяФормы"] .имяГруппыПереключателей [индекс] .свойство]метод([параметры] ) (Все) [window.]document.forms["имяФормы"] .elements[индекс] .свойство\ метод ( [параметры] ) (IE4+) [window. ] document. all. идентификатор [индекс] . свойство | метод ( [параметры] ) (IE5+/W3C) [window. ] document.getElementByld ( "идентификатор" ) [индекс] . свойство\метод( [параметры] ) Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Описание объекта Объект radio достаточно нестандартный в языке JavaScript. При использовании любого, другого элемента управления формы одному объекту на экране соответствует один графический элемент. Но объект radio состоит из группы элементов radio. Поскольку природа элементов radio — взаимно исключающие параметры в группе двух или более элементов, то группа всегда имеет несколько графически представленных в документе элементов. Все элементы в группе обладают одинаковым именем, чтобы браузер мог сгруппировать элементы вместе и обеспечить при выделении одного параметра отмену выделения других выделенных в данный момент параметров. Однако, помимо этого, каждый элемент группы может иметь уникальные свойства (например, значение свойства checked). Для получения информации об отдельных элементах группы используется синтаксис массива JavaScript. Рассмотрите приведенный ниже пример задания группы элементов и обратите 684 Часть III. Объекты документа
внимание на определение каждого элемента группы. Эта группа элементов позволяет пользователю выбрать один из трех заданных параметров. <form> <b>Select your favorite Stooge:</bxbr /> <input type="radio" name="stooges" value="Moe Howard" checked />Moe <input type="radio" name="stooges" value="Larry Fine" />Larry <input type="radio" name="stooges" value="Curly Howard" />Curly <input type="radio" name="stooges" value="Shemp Howard" />Shemp </form> После отображения группы элементов на странице первый элемент radio для пользователя будет выделенным. Для всех элементов группы применимо только одно общее свойство объекта radio— length. Однако другие свойства применяются к отдельным элементам группы. Для получения доступа к элементу группы воспользуйтесь значением индекса массива как частью имени группы элементов. firstBtnValue = document.forms[0].stooges[0].value // "Мое Howard" secondBtnValue = document.forms[0].stooges[1].value // "Larry Fine" При получении доступа к свойствам def aultChecked, type или value нужно указать специфический элемент группы, в соответствии с порядковым номером массива (в Ш4+ и NN6+ каждый элемент обладает уникальным ID). Порядок элементов в группе зависит от последовательности расположения отдельных элементов группы в указанном элементе HTML. Другими словами, для выявления текущего выделенного элемента группы ваш сценарий должен последовательно просмотреть все элементы radio в группе (см. далее). Задание атрибута value для элемента группы может стать очень важной задачей в сценарии. Несмотря на то, что текстовая надпись для элемента задается за пределами дескриптора < input >, только атрибут value позволяет хранить для использования в сценарии любую строку. В приведенном ранее примере надписи элементов radio содержали только имена, в то время как свойствам value были присвоены полные имена актеров. В качестве значений можно использовать любые данные, которые необходимо обработать в сценарии, например, даты рождения, размер обуви, адреса URL или просто имена (поскольку сценарий может извлекать надписи только с помощью свойства innerHTML илисвойства node в большинстве современных браузеров). Смысл заключается в том, что атрибут value может содержать любую строку, которая требуется сценарию для извлечения выбранного пользователем параметра. Содержимое атрибута value также отправляется в CGI-программу на сервер при передаче данных формы. Расположить группу переключателей в документе вы вправе по своему усмотрению. Можно расположить их в строке по горизонтали (как показано ранее); для того чтобы разместить их в одном столбце, добавьте дескриптор <br> после каждого элемента переключателя или после каждого следующего переключателя, чтобы создать двойной столбец. Индексы массива определяются только порядком расположения переключателей в исходном коде, а не способом их отображения на экране. Для того чтобы определить, какой переключатель из группы является выделенным перед началом обработки после выбора элемента пользователем, следует создать цикл просмотра переключателей в группе (см. следующий пример). Для каждого переключателя в сценарии следует проверить свойство checked. Свойства checked Значение: булево Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Глава 22. Объект кнопки 685
Только один переключатель в группе может быть выделен (checked) — за выделение переключателя в группе отвечает браузер. При этом для одного свойства checked переключателя будет установлено значение true, в то время как для всех остальных элементов в группе устанавливается значение false. Начиная с NN3 (и ШЗ), можно спокойно использовать для переключателей свойство checked. При задании для одного переключателя группы свойства checked со значением true все остальные переключатели автоматически перестанут быть активными. Пример В листинге 22.6 в одной из функций циклически просматриваются все установленные элементы управления формы. Как только функция найдет переключатель, свойство которого имеет значение true, она возвратит его индекс. Далее значение индекса используется для определения значения value, которое впоследствии отображается в диалоговом окне. Кроме того, индекс необходим для определения следующего устанавливаемого элемента управления. <html> <head> <title>Extracting Highlighted Radio Button</title> <script type="text/javascript"> function,getSelectedButton(buttonGroup){ for (var i = 0; i < buttonGroup.length; i++) { if (buttonGroup[i].checked) { return i; return 0; } function fullName(fprm) { var i = getSelectedButton(fc/rm. stooges) ; alert ("You chose " + form, stooges [i] .value + '■ .'■); } function cycle(form) { var i = getSelectedButton(form.stooges); if (i+1 == form.stooges.length) { form.stopges[0].checked = true; } else { form.stooges[i+1].checked = true; </script> </head> <body> <form> <b>Select your favorite Stooge:</b> <p><input type="radio" name="stooges" value="Moe Howard" checked="checked" />Moe <input type="radio" name="stooges" value="Larry Fine" />Larry <input type="radio" name="stooges" value="Curly Howard" /> Curly <input type="radio" name="stooges" value="Shemp Howard" />Shemp</p> <p><input type«"button" name="Viewer" value="View Full Name..." onclick="fullName(this.form)" 686 Часть III. Объекты документа
/></р> <pxinput type =" but ton" name= "Cycler" value= "Cycle Buttons" onelick="cycle(this.form)" /></p> </form> </body> </html> См. также: свойство* default Che eked. default Checked Значение: булево Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Если при задании переключателей к дескриптору < input > добавить атрибут checked, то для этого объекта свойство def aultChecked будет иметь значение true; в противном случае ему будет присвоено значение false. Предоставьте доступ к этому свойству, и вы позволите сценариям проанализировать отдельные переключатели, чтобы просмотреть, были ли изменены их значения (предположительно пользователем, если ваш сценарий не выполняет автоматическую проверку). Пример В коде, показанном в листинге 22.7, функция устанавливает ссылку на форму, содержащую переключатели. Задача очень проста — определить (группа переключателей имеет собственное имя), изменил ли пользователь настройки по умолчанию. Функция просматривает в цикле все переключатели и определяет, какой из них имеет атрибут checked в дескрипторе <input>. Получив соответствующий индекс (i), можно легко проверить, установлен ли переключатель до сих пор. Если нет (обратите внимание на оператор отрицания !), то на экране появится сообщение о внесенных изменениях. function groupChanged(form) { for (var i = 0; i < form.stooges.length; i++) { if (form.stooges[i].defaultChecked) { if (!form.stooges[i].checked) { alert("This radio group has been changed."); См. также: свойства checked, value. length Значение: целочисленное Только для чтения Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Группа переключателей имеет длину — количество отдельных переключателей, заданных для данной группы. Попытка извлечь значение длины отдельных переключателей приводит к возвращению значения null. Свойство length используется для задания максимального количества значений в цикле, который выполняет проверку каждого переключателя в данной Глава 22 Объект кнопки 687
группе. Если задать свойство length вручную (а не с помощью сценария), то управлять циклом будет намного проще. Также будет упрощено решение других насущных задач, например, изменение количества элементов группы (в процессе выполнения пользователем действий). name Значение: идентификатор строки Только для чтения Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ При использовании для переключателей свойство name задается только для отдельного переключателя в группе. btnGroupName = document.forms[0].groupName[2].name; В данном представлении каждый переключатель в группе наследует имя всей группы. Как правило, для сценария не требуется извлекать свойство name отдельного элемента группы. Чаще придется использовать в сценарии имя группы переключателей, чтобы извлечь другие свойства отдельных элементов. Очевидно, что извлекать свойство name объекта, имя которого вам известно, — это лишняя трата времени. Но понять, какое место занимает имя группы переключателей в структуре объектов JavaScript, важно для всех программистов. См. также: свойство value. type Значение: строка (radio) Только для чтения Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Свойство type используется для идентификации объекта radio в незнакомой группе элементов формы. См. также: свойство form. elements. value Значение: строка Чтение/Запись Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Как отмечалось ранее в этой главе, для объекта checkbox свойство value содержит произвольную информацию, которую вы присваиваете при задании дескриптора < input > для отдельного элемента radio. Это свойство используется для установки соотношения между надписью переключателя и полной или относительной информацией, отправляемой в сценарий или CGI-программу на сервере. Свойству value можно присвоить тот же текст, что и надписи. См. также: свойство name. Методы clickO Возвращаемое значение: отсутствует Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Назначение метода click () — с помощью сценария имитировать физическое действие выбора переключателя. К сожалению, этот метод не выполняется в браузере NN2 или NN3. Даже если описываемый метод работает безупречно, при написании сценария рекомендуется использовать свойство checked для всех элементов в группе, чтобы абсолютно точно знать, какой параметр установлен для данного флажка. См. также: свойство checked, обработчик события onclick. 688 Часть III. Объекты документа
Обработчики события onclick Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Переключатели предназначены для предоставления возможности выбора (в отличие от остальных объектов, например, кнопки Submit или стандартной пользовательской кнопки). Возможно, вам приходилось работать с программами Windows или Мае, где выбор переключателя активизирует или отображает дополнительные, связанные с ним параметры (см. листинг 22.5). Настойчиво рекомендуем не использовать обработчики событий, которые при выборе переключателя выполняют действия в сценарии. Возможно, вам захочется использовать знания об изменении глобальной переменной или параметра document. cookie, который влияет на последующую обработку (что выполняется при выборе пользователем переключателя). Однако будьте внимательны: если вы примените для одного элемента из группы такое действие, вам придется применить подобные действия и для других элементов группы. Пример При щелчке на одном из переключателей, создаваемых в листинге 22.8, глобальная переменная примет значение true или false. Это действие не зависит от действий, выполняемых при щелчке на кнопке View Full Name. Обработчик onunload в дескрипторе <body> вызывает функцию, которая отображает сообщение перед удалением страницы с экрана. В данном примере используется функция инициализации, которая вызывается в обработчике onload. Листинг 22.8. Обработчик onclick ^ <html> <head> <title>Radio Button onclick Handler</title> <script type="text/javascript"> var ShempOPhile = false function initValueO { ShempOPhile = document.forms[0].stooges[3].checked; } function fullName(form) { for (var i = 0; i < form.stooges.length; i++) { if (form.stooges[i].checked) { break; ч alertC'You chose " + form, stooges [i] .value + "."); } function setShemp(setting) { ShempOPhile = setting; } function exitMsgO { if (ShempOPhile) { alertC'You like SHEMP?"); </script> </head> <body onload="initValue()" onunload="exitMsgO"> <form> <b>Select your favorite Stooge:</b> Глава 22. Объект кнопки 689
<pxinput type="radio" name ="stooges" value="Moe Howard" checked="checked" onclick="setShemp(false)" />Moe <input type="radio" name="stooges" value=MLarry Fine" onclick="setShemp(false)" />Larry <input type="radio" name="stooges" value="Curly Howard" onclick=MsetShemp(false)" />Curly <input type="radio" name="stooges" value="Shemp Howard" onclick="setShemp(true)" />Shemp</p> <p><input type="button" name="Viewer" value="View Full Name..." onclick="fullName(this.form)" /></p> </form> </body> </html> Объект image Свойства, методы и обработчики события этого элемента описываются в главе 15. Свойства Методы Обработчики события complete form* name* src type * См. объект button Синтаксис Доступ к свойствам или методам объекта image. (Все) [window. ] document. имяФормы. имяИзображения. свойство \ метод{ [параметры] ) (Все) [window.]document.имяФормы.elements[индекс] .свойство|метод{[параметры] ) (Все) [window. ] document. forms [индекс] . имяИзображения. свойство \ метод ( [параметры] ) (Все) [window. ] document. forms [" имяФормы" ] . имяИзображения. свойство | ме - тод{ [параметры] ) (Все) [window.]document.forms["имяФормы"].elements[индекс].свойство\ метод{ [параметры] ) (IE4+) [window. ] document .all. идентификатор. свойство \ метод ([параметры]) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ метод { [параметры] ) Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ 690 Часть ///. Объекты документа
Описание объекта Браузеры с полной объектной моделью документа предоставляют для использования в сценарии элемент image. Объект image напоминает объект button, но для него свойство value (которое определяет надпись кнопки) заменяется свойством src. Это свойство задает адрес URL изображения, которое должно быть отображено на форме. Это более простой способ задания изображения, реагирующего на щелчок, чем, например, способ, используемый при обеспечении совместимости со браузерами старых версий (речь идет о заключении элемента img внутрь элемента а, что позволяет воспользоваться обработчиками события последнего). Этот элемент загружает в документ обычное Web-изображение, однако вы не сможете управлять им, что позволяет сделать элемент IMG. Убедитесь, что отображение выполняется именно так, как вы рассчитывали. Свойства complete Значение: булево Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Mozl+, Safari 1+ Свойство complete выполняется так же, как и для элемента img; значение true присваивается только после окончания загрузки. В противном случае свойство возвращает значение false. Интересно, что для этого объекта не существует обработчика события onload. См. также: свойство image. complete. src Значение: строка URL Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Подобно объекту элемента img, свойство src элемента image управляет адресом URL изображения, отображаемого в элементе. Это свойство можно использовать для замены изображения в элементе управления формы так же, как и для обычного элемента img. Поскольку элемент image обладает всеми необходимыми и доступными (например onmouseover, onmouseout, onmousedown) обработчиками события мыши, вы можете использовать в своем сценарии изображения, реагирующие на перемещения указателя мыши, щелчки, нажатия кнопки мыши или любой другой метод управления элементами пользовательского интерфейса. Для того чтобы адаптировать исходный код, который написан для ссылок, содержащих изображения, переместите обработчик события из элемента а в элемент image, и убедитесь, что имя элемента image является таким же, как и у старого элемента img. Более ранние версии браузеров загружают изображения в элемент image, но обработчики события для них не распознаются. См. также: свойство image .src. type Значение: строка (image) Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Используйте свойство type для идентификации объекта image в неизвестной группе элементов. См. также: свойство form, elements. Глава 22. Объект кнопки 691
Текстовые объекты формы бъектная модель документа для форм включает четыре объекта пользовательского интерфейса, связанных с управлением текстом,— текстовое поле, поле пароля, скрытый объект элемента input и элемент text area. Все четыре объекта используются для ввода, отображения или временного хранения текстовых данных. Все эти объекты по умолчанию содержат текст при загрузке страницы, однако сценарии в процессе выполнения также могут изменить их содержимое. Важно отметить, что все объекты, кроме скрытых полей, сохраняют содержимое, измененное пользователем или сценарием при перезагрузке (например, при щелчке на кнопке Reload), кроме браузера ШЗ. Скрытые объекты при перезагрузке во всех браузерах возвращаются к параметрам, заданным по умолчанию. Очевидная разница между скрытыми объектами и всеми остальными заключается в невозможности обработки их событий и управления ими пользователями. Таким образом, возможностей по, управлению скрытыми объектами в сценарии несколько меньше. Постоянство текста и данных в объекте textarea при перезагрузке (и изменении размеров окна) способствует тому, что они являются превосходными хранилищами (неотображаемых) данных, которые, помимо этого, можно сохранять в файлах cookie. При создании фрейма без определенного размера (например, параметры cols или rows в дескрипторе <frameset> для всех видимых фреймов задаются равными 100%, а для другого, скрытого фрейма,— равными *) его полям можно определить поведение, аналогичное заполнителям или таблицам на коммерческих узлах, которые расширяются по мере заполнения данными. В случае, когда пользователи пренебрегают использованием cookie или не отвечают утвердительно на предложение использовать файлы cookie, ваше приложение может воспользоваться временно сохраненными пользовательскими данными. Содержимое поля иногда остается прежним при перезагрузке страницы, но произойдет ли это, зависит от того, насколько эффективно пользователь о
использует кэш-память браузера для сохранения временных данных (если используется браузер ГЕЗ, то в этом случае данные не сохраняются при перезагрузке). Если пользователь закроет браузер или окно браузера, то данные поля будут безвозвратно потеряны. Объект text Свойства этого НТМГ^элемента, его методы и обработчики события описываются в главе 15. Свойства Методы Обработчики события defaultValue select() onafterupdate form onbeforeupdate maxLength onchange name onerrorupdate readonly onselect size . type value Синтаксис . Доступ к свойствам или методом объекта text. (Все) [window. ] document. имяФормы. имяПоля. свойство \ метод ( [параметры] ) (Все) [window.]document.имяФормы.elements[индекс] .свойство\метод ( [параметры] ) (Все) [window.]document.forms[индекс] .имяПоля.свойство\метод([пара - метры] ) (Все) [window.]document.forms["имяФормы"].имяПоля.свойство\метод ( [параметры] ) (Все) [window.]document. forms["имяФормы"] .elements[индекс] .свойство\ метод( [параметры] ) (IE4+) [window. ] document. all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document.getElementBylD ( "идентификатор" ) . свойство \ метод ( [параметры] ) Описание объекта Объект text является основным инструментом получения введенного пользователем текста, состоящего из одной строки. По умолчанию браузеры отображают введенный текст моноширинным шрифтом (как правило, Courier или производными от него), поэтому вы обязательно должны задать ширину (атрибут size) поля, указав максимальное количество символов, которые пользователь может ввести в поле. Если вы не разрабатываете страницу специально для браузеров IE3+ или NN6+, то у вас шрифт будет иметь фиксированный размер, а строка выравнивается по левому краю. В более поздних версиях браузеров каскадные Глава 23. Текстовые объекты формы 693
таблицы стилей могут изменять параметры шрифта текстового поля. Если вы собираетесь использовать текстовое поле, состоящее из нескольких строк, воспользуйтесь объектом text area, о котором рассказывается далее в этой главе. До того, как объектные модели документов браузеров W3C позволили динамически изменять содержимое поля, текстовые объекты использовались для отображения результатов вычислений, выполняемых сценарием, или другого вида обработки данных. Подобные поля могут использоваться на странице отдельно или входить в состав таблицы. Также до появления браузеров W3C эти поля нельзя было полностью защитить от записи, поэтому легко представить, в какое неловкое положение попадали неопытные пользователи, активизировавшие (с помощью указателя мыши или клавиши <ТаЬ>) поля, использовавшиеся исключительно для вывода информации. Для методов текстовых объектов и обработчиков событий применяется терминология, с которой, возможно, знакомы пользователи Windows, но не Macintosh. Считается, что поле становится активным, если пользователь щелкнул на нем или перешел в него с помощью клавиши <ТаЬ>. Когда поле активизируется, в нем либо мерцает курсор, либо находящийся в данном поле произвольный текст оказывается выделенным. Противоположное действие пользователя — щелчок за пределами поля или переход от этого поля к другому элементу таблицы с помощью клавиши <ТаЬ> — называется деактивизацией. Щелчок на другом объекте (другом поле или любой кнопке) приводит к тому, что поле становится неактивным. Если вы не хотите, чтобы пользователь изменил содержимое поля, у вас есть три возможности (в зависимости от типа поддерживаемого браузера): сделать поле неактивным; сделать поле недоступным; задать для поля свойство readonly. Для достижения полной обратной совместимости в поле, которое следует защитить, используется следующий обработчик события. onFocus="this.blur()"; Начиная с IE4 и NN6, объектная модель содержит свойство disabled для элементов управления формы. Установка этого свойства в значение true оставляет элемент отображенным на странице, но пользователь не сможет получить к нему доступ. В этих же браузерах задано свойство readonly, которое не блокирует поле, но и не позволяет ввести в него информацию. Текстовые поля и события События focus и blur также соответствуют дополнительным действиям пользователя, выполняемым по отношению к текстовому объекту: выделение и изменение. Выделение происходит, когда пользователь щелкает мышью вначале поля и перетаскивает указатель вдоль текста поля; изменение происходит, когда пользователь вносит изменения в содержимое поля, а затем уходит от этого поля, щелкнув на любом другом элементе или нажав клавишу <ТаЬ>. При использовании обработчиков события для поля учтите, что взаимодействие пользователя с полем может привести к генерированию более одного события. Например, щелчок на поле для выделения текста может запустить оба события: focus и select. Если у вас возникают проблемы при использовании обработчиков событий onf ocus и onselect, то ваши сценарии, скорее всего, будут выполнять непонятные для посетителя страницы действия. Например, отображение диалоговых окон с предупреждениями также запускает событие blur, поэтому поле, для которого заданы обработчики событий onselect (отображающее предупреждение) и onblur, взаимодействуют самым необъяснимым образом. Будьте внимательны, задавая для текстового объекта несколько обработчиков событий. По возможности выберите одно действие пользователя, которое хотите использовать для выполнения определенного фрагмента исходного кода JavaScript, и последовательно используйте его на странице. Не для всех полей необходимо задавать обработчики событий, — только 694 Часть III. Объекты документа
для тех", которые будут выполнять определенные операции в результате воздействия пользователя на данное поле. Многие неопытные разработчики не понимают поведения события change. Любые изменения в поле считаются выполненными только после того, как поле будет деактивизировано, т.е. пользователь щелкнет за пределами поля или уйдет от него с помощью клавиши <ТаЬ>. Таким образом событие не передается после ввода в поле каждого следующего символа одного слова. При этом вместо события blur используется событие change, которое при изменении значения поля вызывает обработчик события onchange. Необходимое действие (щелчок за пределами поля или использование клавиши <ТаЬ>) вызывает соблазн присвоить обработчик события onchange отдельной кнопке, на которой пользователь должен щелкнуть, чтобы инициировать определенное действие над содержимым поля. Начиная с браузеров NN4 и Ш4, текстовым полям также свойственны обработчики событий клавиатуры — onkeydown, onkeypress и onkeyup. С помощью этих обработчиков событий можно перехватывать нажатие клавиши до того, как символ отобразится в текстовом поле. Следовательно, события для работы с клавиатурой можно использовать, чтобы при вводе информации в текстовое поле, например, не допустить ввода чисел. Для извлечения текущего содержимого текстового объекта вызовите свойство document. имяФормы. имяОбъекта. value. После извлечения значения строки можно использовать строковый объект JavaScript для анализа или другого вида обработки данного текста, предусмотренного в сценарии. Если поле содержит числовое значение, а вам нужно передать это значение в методы, использующие числовые данные, следует преобразовать текст в число с помощью глобальных функций parselnt () или parseFloat (). Текстовые поля и клавиша <Enter> В ранних версиях браузеров использовались общепринятые соглашения, которые действуют и по сей день. Если форма состоит только из одного текстового поля, нажатие клавиши <Enter> действует точно так же, как и щелчок на кнопке Submit для формы. Возможно, вы неоднократно убедились в этом при вводе значения в простое поле формы, используемое для проведения поиска. Стоит нажать клавишу <Enter>, и запрос отправится на сервер. С другой стороны, если форма содержит более одного текстового поля, то при нажатии клавиши <Enter> (<Retum>) данные ни из одного текстового поля отправлены не будут (исключением является браузер IE4 для Мае: он отправляет данные независимо от того, сколько текстовых полей содержит форма). Но при наступлении событий, связанных с клавишами, можно запрограммировать это действие (или инициировать серверную часть сценария) для любых текстовых полей формы. Чтобы они выполнялись во всех браузерах, различающих события клавиатуры, необходимо использовать небольшую функцию ветвления, которая при нажатии клавиши будет выполнять соответствующий фрагмент исходного кода, свойственный для данной объектной модели документа. Приведенный ниже код представляет фрагмент страницы, в которой применяется функция, анализирующая каждое нажатие клавиш в текстовом поле, и запускающая обработку данных при нажатии клавиши <Enter>. <html> <head> <title>Enter/Return Event Trigger</title> <script type="text/javascript"> // Обрабатывает объекты событий в NN4, IE4+, NN6 function isEnterKey(evt) { evt = (evt) ? evt : (window.event) ? window.event : ""; var theKey; if (evt) { theKey = (evt.which) ? evt.which : evt.keyCode; } return (theKey == 13) ; Глава 23. Текстовые объекты формы 695
} function processOnEnter(fId, evt) { if (isEnterKey(evt)) { alert ("Ready to do some work with the form."); return false; } return true; } </script> </head> <body> <hl>Enter/Return Event Trigger</hl> <hr /> <form onsubmit="return false"> Field 1: <input type="text" name="fieldl" onkeydown="return processOnEnter(this, event)" /> Field 2: <input type="text" name=,,field2,, onkeydown="return processOnEnter(this, event)" /> Field 3: <input type="text" name="field3u onkeydown="return processOnEnter(this, event)" /> </form> </body> </html> Обратите внимание на то, что для удобства работы с моделями событий в браузерах NN4+ и W3C ссылка на объект event передает в качестве параметра в обрабатывающую функцию (см. главу 25). Свойства defaultValue Значение: строка ' Только для чтения Совместимость: WinIE3+, MacEE3+, NN2+, Mozl-f, Safari 1+ Пользователи и сценарии могут свободно управлять содержимым объекта text, присваивая свойство value строкам, однако вы всегда сможете извлечь (и, следовательно, при необходимости восстановить) строку, присвоенную текстовому объекту при задании дескриптора < input >. Свойство defaultValue извлекает строковый параметр атрибута value. Листинги 23.1-23.3 описывают форму, содержащую всего один элемент input. Правила управления формами на HTML-страницах гласят, что данные формы отправляются на сервер при нажатии клавиши <Enter> даже при активном текстовом поле или текстовой области. Такое поведение формы предполагает перезагрузку страницы, в форму которой не введены данные, что вызывает прекращение выполнения текущего сценария. В текущем примере элементы form содержат обработчик onsubmit, который в подобных ситуациях блокирует отправку данных и вызывает обработчик onchange текстового поля, выполняющий демонстрационный сценарий. В отдельных браузерах, например MaclE5, чтобы вызвать обработчик onchange, вам придется щелкнуть за пределами поля или нажать <ТаЬ>. Листинг 23.1 содержит простую форму с единственным полем, в которое введено значение по умолчанию. Функция resetFieldO восстанавливает содержимое этого поля до значения по умолчанию (задается в дескрипторе < input >) после того, как оно было изменено. В странице с одним текстовым полем, подобной этой, определение кнопки type="reset" / HtSMMTKy 696 Часть III. Объекты документа
и вызов метода form. reset () приводят к одинаковым результатам, поскольку подобная кнопка восстанавливает значения по умолчанию всех элементов управления формы. Если же вам необходимо восстановить значения только отдельного набора полей, то рассмотрите пример функции в листинге 23.1. Листанг 23.1. Восстано^ <html> <head> <title>Text Object DefaultValue</title> <script type="text/javascript"> function upperMe(field) { field.value = field.value.toUpperCase(); } function resetField(form) { form.converter.value = form.converter.defaultValue; } </script> </head> <body> <form onsubmit="window,focus(); return false"> Enter lowercase letters for conversion to uppercase: <input type="text" name="converter" value="sample" onchange="upperMe(this)" /> <input type="button" value="Reset Field" onclick="resetField(this.form)" /> </form> </body> </html> См. также: свойство value. form Значение: ссылка на объект form Только для чтения Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ Свойство каждого объекта элемента input представляет собой ссылку на элемент form, который содержит элемент управления. Это свойство удобно использовать в сценарии при работе с одним элементом управления формой, которое передается функции в качестве параметра, из которого вам нужно получить доступ к другому элементу управления той же формы или вызвать метод формы. Обработчик события элемента input может принимать в качестве параметра ключевое слово this, а функция получает доступ к форме без дополнительного обращения к именованным объектам и громоздким иерархическим ссылкам в пределах документа. Следующая функция получает в качестве аргумента ссылку на текстовый объект. Эта ссылка определяет, какая из ветвей функции будет в дальнейшем выполняться (в данном случае определяется способ отправки данных формы). function setAction(fId) { if (fid.value.indexOf("@") != -1) { fid.form.action = "mailto:" + fid.value; } else { fid.form.action = "cgi-bin/normal.pi"; } fid.form.submit(); } Глава 23. Текстовые объекты формы 697
Обратите внимание, что сама функция не привязывается к конкретной форме, поскольку в данном случае форма определяется как контейнер текстового поля, вызвавшего функцию. См. также: объект form. maxLength Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство maxLength определяет максимальное количество символов, которые можно ввести в поле. Свойства maxLength и size не зависят друг от друга. Это значение обычно задается с помощью атрибута maxlength элемента input. Пример Приложение The Evaluator (глава 13) позволяет экспериментировать со свойством maxLength. Верхнее текстовое поле приложения не имеет значения по умолчанию, но вы можете временно назначить его равным неким символам, чтобы узнать, как следующее выражение скажется на нем. document.forms[0].input.maxLength = 3; Введя это выражение в верхнее поле, вы увидите, что результат изменился. Чтобы восстановить значение по умолчанию, перезагрузите страницу. См. также: свойство size. паше Значение: идентификатор Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ Имена текстовых объектов имеют важное значение по двум причинам. Во-первых, если ваша HTML-страница отправляет информацию в CGI-сценарии, то устройство ввода передает имя текстового объекта вместе с данными, чтобы помочь программе на сервере идентифицировать информацию, полученную из формы. Во-вторых, имя текстового объекта можно использовать в ссылках в сценарии JavaScript.^E^H вы присвоите для ваших полей понятные имена, то они помогут вам разобраться (а другим пользователям понять структуру сценария) в выполняемых действиях и отладить листинги JavaScript. Задавая имена для текстовых объектов, постарайтесь использовать понятные имена. Копирование текста надписи поля, отображаемой на странице, поможет вам найти в сценарии ссылку на его физическое расположение. Подобно всем именам объектов в JavaScript, имена текстовых объектов должны начинаться с буквы, за которой может следовать любое количество символов или чисел. Избегайте использования в именах знаков пунктуации, за исключением безопасного символа подчеркивания. Рекомендуется использовать понятные имена для всех объектов, которые задаются в документе, однако может оказаться так, что вы присвоите одно и то же имя для набора взаимосвязанных полей, — и здесь JavaScript придет вам на помощь. В пределах одной формы любое повторно использованное имя для объекта того же типа помещается в индексированный массив, созданный для этого имени. Например, при задании трех полей с одинаковым именем для каждого поля свойство value можно извлечь с помощью следующих инструкций. data = document.forms[0].entry[0].value; data = document.forms[0].entry[1].value; data = document.forms[0].entry[2].value; Такую конструкцию удобно использовать, если вы хотите задать цикл просмотра всех полей формы для поиска пустого элемента. Кроме того, в процессе выполнения сценария, возможно, понадобится узнать, какой тип информации содержит каждое поле (чтобы выполнить 698 Часть III. Объекты документа
соответствующую обработку данных). Я не рекомендую повторно использовать одни и те же имена объектов, но вам следует знать, как представлено объектная модель в этом случае. К сожалению, ШЗ не поддерживает использования подобных объектов text в массивах. Более подробная информация по этому вопросу приведена в главе 21. Пример Изучите листинг 23.2 далее в этой главе, в котором использовался текстовый объект convertor. Имя этого объекта применялось в операторе присвоения полю значения. Чтобы извлечь имя текстового поля, использовалась ссылка на свойство name. var objectName = document.forms[0].elements[0].name; См. также: свойство form, elements, свойства name других элементов объектов формы. readonly Значение: булево Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Для отображения текста в текстовом поле без предоставления пользователю возможности его изменения новые версии браузеров предлагают свойство readonly (и атрибут дескриптора). При задании параметра true это свойство не позволяет пользователю изменять или удалять содержимое текстового поля. В отличие от недоступных текстовых полей, эти поля, предназначенные только для чтения, выглядят точно так же, как и редактируемые. В браузерах старых версий можно частично сымитировать такое поведение, добавив в элемент input следующий обработчик события. onfocus="this.blur()" Однако добавление этого обработчика события нельзя считать полноценным заменителем (некоторые пользователи могут намеренно изменить содержимое поля еще до того, как обработчик события завершит свою работу). Для NN можно заблокировать события, связанные с клавиатурой, и предотвратить ввод символов в поле. Пример Приложение The Evaluator позволяет сделать нижнее текстовое поле доступным только для чтения. Сначала введите в него произвольный текст. Затем введите в верхнее поле следующее выражение. document.forms[0].inspector.readonly = true; Теперь вы можете выделить текст в нижнем поле, однако изменить его не представляется возможным. См. также: свойство disabled. size Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Если размер текстового поля не указан при создании этого элемента, то оно будет отображать около 20 символов для шрифта с размером, указанным в таблице стилей элемента. Вы можете дополнительно указать максимальное количество символов, всего вводимого в поле текста (если атрибута size дескриптора не достаточно). Однако помните, что браузеры не всегда корректно оценивают пространство, необходимое для отображения определенного количества символов. Если вы задаете для текстового поля атрибут maxlength, то укажите для атрибута size размер на один-два символа больше. Глава 23. Текстовые объекты формы 699
Пример Измените размер нижнего текстового поля приложения The Evaluator, введя в верхнее поле следующие выражения. document.forms[0].inspector.size = 20; document.forms[0].inspector.size = 400; Перезагрузите страницу, чтобы вернуться к исходным размерам поля (80). См. также: свойство maxLength. type Значение: строка (text) Только для чтения Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Используйте свойство type для идентификации объекта text в неизвестной группе элементов формы. См. также: свойство form, elements. value Значение: строка Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ Свойство value текстового объекта является двузначным по отношению к содержимому поля. Ссылка на свойство value объекта возвращает строку, отображаемую в данный момент в поле. Обратите внимание на то, что все значения, извлекаемые из объекта text, являются строковыми. Если пользователю предлагается ввести в поле число, возможно, вашему сценарию следует преобразовать данные в текстовое значение, в котором числа воспринимаются как строки ("42" вместо старого доброго 42), чтобы сценарий смог выполнить операцию сравнения. JavaScript пытается по возможности сделать это автоматически, соблюдая некоторые внутренние правила (см. главу 27). Если выводится сообщение об ошибке, в котором говорится, что некоторое значение не является числовыми (в математических операциях), то это значение точно является строковым. Ваш сценарий помещает в поле текст, который отображается для пользователя в результате присвоения строки свойству value текстового объекта. Для этого используется обычный оператор присвоения. document.forms[0].ZIP.value = "90210"; При присвоении значений текстовому объекту JavaScript является более снисходительным. JavaScript делает все возможное для преобразования значения в строковое при отображении текстового объекта. Даже булевы значения преобразуются в свои строковые эквиваленты true или false. Сценарии могут без проблем помещать числовые значения в поля. Но помните: если позже сценарий извлечет эти значения из текстового объекта, они будут иметь строковый тип. Единственными значениями, которые не преобразуются, являются объекты. Обычно они отображаются в текстовых полях как [object], или — в некоторых браузерах — более описательную надпись объекта. Хранение массивов в поле требует дополнительной обработки данных. Для преобразования массива в строку следует использовать метод array. j о in (). Каждый элемент массива отделяется символом, заданным в методе array. join (). Позднее для преобразования этой разделенной строки в массив можно использовать обратный метод string.split (). 700 Часть III. Объекты документа
Пример Демонстрация принципов назначения и получения значения в текстовом поле приведена в листинге 23.2, в котором действия выполняются в обработчике onchange. Введите любой строчный символ в поле и щелкните за пределами поля. В обработчик события подставляется ссылка на объект формы. Функция извлекает значение, преобразует его символы в прописные (для этого используются методы управления строчными данными JavaScript) и обратно назначает его в качестве значения поля. Листинг 2Э.2. Получение и нш»ц^аюШ Шаиийши iri^pri^wt»lio|tei " <html> <head> <title>Text Object DefaultValue</title> <script type="text/javascript"> function upperMe(field) { field.value = field.value.toUpperCase0; } function resetField(form) { form.converter.value = form.converter.defaultValue; } </script> </head> <body> <form onsubmit= "window, focus.() ; return false"> Enter lowercase letters for conversion to uppercase: <input type=Mtext" name="converter" value="sample" onchange="upperMe(this)" /> <input type="button" value="Reset Field" onclick="resetField(this.form)" /> </form> </body> </html> Ниже показано еще два способа выполнения этой же задачи, каждый из которых эффективнее предыдущего. В обоих применяется сокращенная ссылка на текстовый объект. В листинге 23.3 текстовый объект определяется ссылкой, содержащей всего одно ключевое слово this. Поскольку текстовый объект полностью описывается этим ключевым словом (хотя это и не очевидно на первый взгляд), вы можете получить доступ к его свойству value и назначить ему строковое значение, воспользовавшись оператором присвоения. Листинг 23,3. Подстановка Tet(CTOwro обшста « фунщмю <html> <head> <title>Text Object Value</title> <script type="text/javascript"> function upperMe(field) { field.value = field.value.toUpperCase(); } </script> </head> <body> <form onsubmit="window.focus(); return false"> Enter lowercase letters for conversion to uppercase: Глава 23. Текстовые объекты формы 701
<input type="text" name="converter" value="sample" onchange="upperMe(this)" /> </form> </body> </html> Еще один способ управления значением в поле заключается в использовании внедренного обработчика событий (вместо вызова внешней функции). Подобный подход проще реализовать, поскольку сценарии обычно содержатся в заголовке HTML-страницы. Если в документе не использовать функцию, то обработчик события элемента < input > примет следующий вид. <input type="text" name="converter" value="sample" onchange="this.value = this.value.toUpperCase()" /> Правая часть оператора присвоения извлекает текущее содержимое поля и (с помощью метода toUpperCase () строкового объекта) преобразует исходную строку в символы верхнего регистра. В результате выполнения этой операции свойство value принимает измененное исходное значение. Ключевое слово this в предыдущем примере в данном случае может вас ввести в заблуждение, хотя в его применении нет ничего удивительного. Это ключевое слово может применяться в качестве аргумента обработчика событий, представляя текущий объект (см. листинг 23.3). Если вы хотите обратиться к объектам, содержащимся в текущем объекте, то введите их имена наряду с ключевым словом this. В листинге 23.2 ссылка на всю форму была представлена ссылкой this. form. В результате сценарий получал доступ к форме, содержащей текущий объект. С другой стороны, вы можете подобный синтаксис для получения свойств объекта this. В последнем примере я использовал только свойство value текущего объекта— this .value. Выражения this .value и this. form выглядят похожими, однако необходимо четко различать, что первое— это значение, подставляемое в функцию, а второе— ссылка на объект (вызывающий функции). Когда вы создаете ссылку на объект, функции могут получать и изменять свойства этого объекта. Если вы подставите в функцию значение свойства, то вы не сможете изменить его, пока не создадите полную ссылку на объект и его значение. См. также: свойство default Value. Методы blur () Возвращаемое Значение: отсутствует Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Когда пользователь щелкает на другом объекте или с помощью клавиши <ТаЬ> переходит к другому полю, текущее поле становится неактивным. Под управлением сценария метод blur () отменяет выделение любого фрагмента содержимого поля, и из поля исчезает мерцающий курсор. При этом курсор не переходит к следующему полю, как это происходит при нажатии клавиши <ТаЬ>. Пример Следующий оператор вызывает метод blur () текстового поля vanishText. document.forms[0].vanishText.blur(); См. также: метод focus (), обработчик события onblur. 702 Часть III. Объекты документ
focus () Возвращаемое Значение: отсутствует Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Для текстового объекта быть активным означает заключать в себе мерцающий курсор, готовый к вводу текста (для кнопок в среде Windows активизация имеет несколько другое значение). Активизировать текстовое поле — означает предоставить его для редактирования. При активизации поля, содержащего некоторую информацию, курсор не обязательно помещается в любое заданное место поля. Как правило, курсор отображается в начале текста (хотя в браузерах ВЕ4+ для размещения курсора в определенной точке поля можно использовать объект textRange — см. главу 35). В случае, когда при вводе информации существующий текст удаляется, используются оба метода — focus О nselectO. Пример В листинге 23.4 приведен пример совместного использования методов focus () и select (). См. также: метод select (), обработчик события onf ocus. select() Возвращаемое Значение: отсутствует Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Выделение поля под управлением сценария означает выделение всего текста данного текстового объекта. В обычном приложении, как правило, содержится сценарий, предназначенный для проверки введенных пользователем данных на предмет наличия ошибок. После предупреждения пользователя о найденной ошибке (в диалоговом окне window.alert О) сценарий завершает свою работу, выделяя в поле фрагмент текста, вызывающий сомнения. Это не только привлекает внимание пользователя (что особенно важно, если подобный сценарий выполняет проверку нескольких полей), но также и сохраняет исходный текст, позволяя пользователю приступить к поиску возможной ошибки. Когда текст выделен, при нажатии любой клавиши он удаляется, замещаясь вводимыми символами. Выделить содержимое текстового объекта с помощью щелчка на нем не всегда удается. Одна из проблем заключается в том, что щелчок на поле приводит к его активизации, а процесс выделения при этом не инициализируется. Для корректного выполнения этого процесса необходимо для поля использовать в сценарии оба метода (focus () и select ()) в указанном порядке. Использовать одновременно оба метода не запрещается, а дополнительная подстраховка вторым методом предоставляет пользователю более широкие возможности при работе со страницей. В Internet Explorer для Windows после отображения диалогового окна с предупреждением выполнение обоих методов текстового поля проходит аномально. Эту ситуацию можно исправить: с помощью метода setTimeout () вставьте искусственную задержку перед тем, как запускать отдельную функцию, отвечающую за активизацию поля и выделение его содержимого. Другие браузеры, не имеющие подобного дефекта, выполняют описанную выше задачу без особых проблем. Выделение текстового объекта с помощью сценария не вызывает тот же обработчик события onselect для данного объекта (как это происходит при выделении текста в поле самим пользователем). Следовательно, когда пользователь вызывает метод select О, обработчик события в сценарии не запускается. Пример Щелчок на кнопке Verify (листинг 25.4) вызывает проверку содержимого текстового поля. Введенное значение должно содержать только цифры. Все необходимые действия выполняются в функции checkNumeric (), которая получает в качестве аргумента ссылку на прове- Глава 23. Текстовые объекты формы 703
ряемое поле. Поскольку функция doSelectionO вызывается с задержкой, различные части ссылки на форму получаются из свойств поля и формы. Если проверка данных приводит к получению негативного результата, то doSelectionO вызывается с нулевой задержкой. Поскольку первый аргумент метода setTimeout () строковый, то в данном примере выражение вызова функции doSelection () представлено в строковом формате. Задача последней функции сводится к активизации и выделению поля, ссылка на которое указана как аргумент. <html> <head> <title>Text Object Select/Focus</title> <script type="text/javascript"> // общая функция проверки введенного значение //на принадлежность к числам function isNumber(inputStr) { for (var i = 0; i < inputStr.length; i++) { var oneChar = inputStr.charAt(i); if (oneChar < "0" || oneChar > "9") { alert("Please make sure entries are numbers only."); return false; } } return true; } function checkNumeric(fId) { var inputStr = fId.value; var fldName = fid.name; var formName = fId.form.name; if (isNumber(inputStr)) { // операторы, выполняемые в случае true } else { setTimeout("deselection(document." + formName + ". " + fldName + ")", 0) ; } } function doSelection(fid) { fid.focus(); fid.select (); } </script> </head> <body> <form name="entryForm" onsubmit="return false"> Enter any positive integer: <input type="text" name="numeric" /> <pxinput type= "button" value="Verify" onclick="checkNumeric(this.form.numeric)" /></p> </form> </body> </html> См. также: метод focus (), обработчик события onselect. 704 Часть III. Объекты документа
Обработчики событий onafterupdate onbeforeupdate onerrorupdate Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Если в WinlE вы проводите объединение данных в текстовом элементе, то его объект становится целью для трех событий, связанных с обновлением данных в поле. События onbeforeupdate и onaf terupdate вызываются немедленно (соответственно) перед и после обновления данных. Если при извлечении информации из базы данных возникает ошибка, то вызывается событие onerrorupdate. Все три события можно использовать в целях обучения. Например, обработчик события onaf terupdate может временно изменять характеристики шрифта элемента, чтобы обозначить обновленные данные. Обработчик события onerrorupdate может заполнить поле символами дефиса, если для данного поля отсутствует корректно заданное значение. Эти события применяются только для элементов input текстового поля (не для password или hidden). См. также: свойства dataFld, dataSrc (глава 15). onblur onfocus onselect Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Все три этих обработчика события следует использовать только после того, как вы четко уясните взаимодействие событий, которые связаны с текстовыми объектами. Перед тем как применять для текстового объекта более одного из этих событий, следует выполнить предварительное тестирование и проанализировать все возможные ситуации. Поскольку некоторые события не выполняются без непосредственного наступления других событий перед или после текущих (например, событие onfocus наступает непосредственно перед событием onselect, если, конечно, поле исходно не было активизировано), то любое действие вашего сценария для данных событий должно быть максимально явным, чтобы избежать возможного конфликта. # Обработчик события onselect не поддерживается в NN для Windows до версии 4. /На заметку В частности, будьте предельно внимательны при отображении модального диалогового окна (например диалоговые окна window. alert ()) в ответ на обработчик события onfocus. Поскольку текстовое поле при отображении диалогового окна становится неактивным, а затем снова активизируется при закрытии окна, то легко запустить циклическое действие, которое трудно разорвать. Если вы оказались в подобной ситуации, воспользуйтесь специальной комбинацией клавиш для перезагрузки страницы (<Ctrl+R>) при закрытии диалогового окна. Часто возникает вопрос, каким обработчиком событий (onblur или onchange) следует запускать проверку введенных данных. Проверку данных нельзя выполнить в обработчике события onblur, а вот onchange позволяет это сделать (пользователь не изменяет неправильно введенные данные, а переходит к другому полю с помощью клавиши <ТаЬ>). Что мне не нравится при управлении событием onblur — это вероятность возникновения проблемы Глава 23. Текстовые объекты формы 70S
у пользователя, который, вероятно, захочет перейти к другому полю с помощью клавиши <ТаЬ>, а затем вернуться к исходному полю (предполагается, что перед отправкой данных из формы требуется ввести их в поле). Как описывается в главе 43, при отправке данных из формы рекомендуется использовать событие onchange для немедленной проверки данных, а затем применить обработчик события onsubmit для вызова функции отправки данных. Пример В листинге 23.5 продемонстрирован пример использования обработчиков onblur, onf ocus, onselect. С их помощью строка состояния окна преобразуется в область вывода информационных сообщений. Как только пользователь переходит к полю (по щелчку или в результате нажатия клавиши <ТаЬ>), в строке состояние отображается сообщение, связанное с текущим полем. На рис. 23.1 показано, что пользователь перешел к первому полю. ЕЕ FH» Edit Vim Fittritw ТюЬ H«lp шщ ©*** © а \р*ш*&!*+*;+шф ЪШ'&ш'-О'Щ'щ* Enter your firrt name:; Huckleberry Enter your last name:: Enter your address:: Enter your city:: Рис. 23.1. Обработчик onfосиз изменяет содержимое строки состояния <html> <head> <title>onfocus Event Handler</title> <script type="text/javascript"> function prompt(msg) { window.status = "Please enter your " + msg + "."; } </script> </head> <body> <form> Enter your first name:<input type="text" name="firstName" onfocus="prompt(•first name')" /> <p>Enter your last name:<input type="text" name="lastName" onfocus="prompt('last name■)" /></p> 70S Часть III. Объекты документа
<p>Enter your address:<input type="text" name="address" onfocus=Mprompt(■address')" /></p> <p>Enter your city:<input type="text" name="city" onfocus="prompt('city')" /></p> </form> </body> </html> onchange Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Из всех обработчиков событий, предназначенных для работы с текстовым объектом, вы чаще всего будете использовать onchange (см. листинг 23.6). Я предпочитаю применять это Событие для немедленной проверки введенных пользователем данных в поле. Дело в том, что при выполнении единой проверки всех данных перед отправкой информации из формы внимание пользователя сосредоточено уже не на данном поле. При проверке данных сразу после введения информации в поле пользователь не отвлекается от вводимых данных. Более подробно о выполнении проверки при введении данных рассказывается в главе 43. f В браузере NN4 (только в нем) при задании для текстового поля и обработчика /назашгау события onchange, и обработчика события клавиатуры, первый игнорируется. I .+^* Этого не происходит в браузере IE4+, NN6+ и W3C, где поддерживаются любые события. <html> <head> <title>Text Object Select/Focus</title> <script type="text/javascript"> // общая функция проверки введенного значения //на принадлежность к числам function isNumber(inputStr) { for (var i = 0; i < inputStr.length; i++) { var oneChar = inputStr.substring(i, i + 1); if (oneChar < "0" || oneChar > "9") { alert("Please make sure entries are numbers only."); return false; } return true; function checklt(form) { inputStr = form.numeric.value; if (isNumber(inputStr)) { // операторы, выполняемые в случае true } else { form.numeric.focus(); form.numeric.select(); } r </script> </head> <body onsubmit="checklt(this); return false"> Глава 23. Текстовые объекты формы 707
<form> Enter any positive integer: <input type="text" name="numeric" onchange="checkIt(this.form)" /> </form> </body> </html> Объект password Свойства Методы Обработчики события См. объект text Синтаксис См. объект text Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1 + Описание объекта Поле для пароля выглядит так же, как и текстовое поле, но когда пользователь вводит в него данные, то в этом поле отображаются только звездочки или маркеры (в зависимости от вашей операционной системы). В целях безопасности любой обмен паролями следует обрабатывать серверной частью CGI-программы. Сценарии могут рассматривать объект password как текстовый объект input. При этом создатель сценария может сохранить пароль посетителя Web-страницы в свойстве document. cookie на компьютере пользователя. Свойство value объекта password возвращается в текстовом формате, поэтому подобные пароли можно также хранить в файле cookie. Поскольку файл cookie пользователя можно просмотреть на локальном компьютере (например, слишком любопытным коллегой в обеденный перерыв), то хранение пароля в обычном виде представляет собой потенциальную опасность. Вместо этого вам следует разработать для вашей страницы закодированный алгоритм чтения и записи паролей в файл cookie. На большинстве Web-узлов, защищающих пароли, обычно имеется специальная программа CGI, которая кодирует пароль перед его отправкой в файл cookie. Свойства, методы и обработчики объекта password совпадают с объектом text. Свойство type для данного объекта возвращает password. Скрытый объект input Свойства Методы Обработчики события См. объект text Синтаксис См. объект text Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ 709 Часть III. Объекты документа
Описание объекта Объект скрытого поля представляет собой простой контейнер строки объекта формы на Web-странице, содержимое которого скрыто от пользователя. Несмотря на длинный список свойств, методов и обработчиков событий, которыми обладает этот тип элемента, для скрытого элемента обычно применяют только операции чтения и записи свойства value. Скрытый объект играет важную роль в приложениях, которые работают с CGI-програм- мами, выполняемыми на сервере. Очень часто сервер получает данные, которые ему необходимо передать самому себе при следующей отправке данных формы (например, ГО пользователя, сохраненного на регистрационной форме приложения). CGI-программа может генерировать HTML-страницу, содержащую необходимые данные, скрытые от пользователя, но передаваемые на сервер при отправке остальной информации. Наряду с этими строками, страница, предназначенная для приложения на сервере, может содержать дружественный для пользователя интерфейс, который упрощает ввод данных. Но для базы данных или другого серверного приложения необходимо, чтобы данные представлялись в более удобном формате. В сценарии, добавленном на клиентскую страницу для преобразования введенной в скрытом поле информации в требуемый для базы данных формат можно использовать обработчик события onsubmit. Когда CGI-программа получает запрос от клиента, она передает его вместе со значением скрытого поля в базу данных. » Я не являюсь сторонником использования скрытых полей в полностью клиентских приложениях JavaScript. Если вместе со страницами, на которых используются сценарии JavaScript, нужно отправить некоторые предварительно заданные наборы данных или значений, я делаю это с помощью переменных и массивов, которые обрабатываются в сценарии. Поскольку изменение содержимого скрытого поля с помощью сценария является ненадежной операцией (например, мягкая перезагрузка удаляет проведенные изменения), то безбоязненно вносить подобные изменения можно только в сценарии, который отправляет данные из формы в CGI-программу, или в функции, запускаемой обработчиком события onsubmit. На самом деле вы используете скрытые поля как хранилища данных сценария, которые впоследствии будут отправлены на сервер. Для более надежного хранения данных используйте свойство document. cookie или уникальные текстовые поля, содержащиеся в скрытых фреймах, даже если это увеличивает продолжительность загрузки страницы. Свойства, методы и обработчики скрытого объекта совпадают с характеристиками объекта text. Свойство type данного объекта возвращает значение hidden. Объект textarea Свойства элемента HTML, его методы и обработчики события описываются в главе 15. Свойства Методы Обработчики события cols < createTextRange() onafterupdate* form* select()* onbeforeupdate* name* onchange readonly* onerrorupdate* rows type* wrap * См, объект text Глава 23. Текстовые объекты формы 709
Синтаксис Доступ к свойствам или методам объекта textarea. (Все) [window. ] document. имяФормы. имяОбласти. свойство \ метод ( [параметры]) (Все) [window.]document.имяФормы.elements[индекс].свойство\метод ( [параметры] ) (Все) [window. ] document. forms [индекс] . имяОбласти. свойство \ метод ( [параметры] ) (Все) [window.]document.forms["имяФормып].имяОбласти.свойство\метод ( [параметры] ) (Все) [window.]document.forms["имяФормы"].elements[индекс] .свойство\ метод ( [параметры] ) (IE4+) [window. ] document .all. идентификатор. свойство \ метод ( [параметры]) (IE5+/W3C) [window. ] document.getElementBylD ("идентификатор") . свойство\ метод ( [параметры] ) Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Описание объекта Несмотря на то, что объект textarea не входит в тот же синтаксический раздел HTML, что и другие элементы < input >, он является элементом формы, предоставляя возможности ввода текста, состоящего из многих строк. Некоторые браузеры позволяют использовать элемент textarea в любой части документа, однако старайтесь применять его исключительно в элементе form. Объект textarea напоминает текстовый объект, за исключением атрибутов, которые задают его физический вид на странице. Поскольку объект textarea предназначен для ввода текста, состоящего из многих строк, его атрибуты отвечают за определение высоты (количество строк) и ширины (количество символов моноширинного текста) объекта на экране. Какой размер вы зададите, не имеет значения: в старых браузерах отображается текстовая область, содержащая горизонтальную и вертикальную полосу прокрутки; более современные браузеры стараются отображать полосы прокрутки только, когда это необходимо (хотя это все еще исключение, а не правило). Если задать для атрибута wrap значение virtual или physical в NN и soft или hard в Ш, то текст, введенный в текстовую область, будет перенесен в пределах видимого прямоугольного поля элемента; в противном случае текст прокручивается на значительное расстояние по горизонтали (горизонтальная полоса прокрутки появляется, когда перенос строк не задан). Конечно, это поле является примитивным текстовым элементом по стандартам графического интерфейса, поскольку в современных версиях браузеров параметры шрифта обладают большими возможностями благодаря таблицам стилей, задаваемым для всего текста в поле. Используйте приложение The Evaluator (глава 13) для изучения свойств cols и rows области вывода результатов. Измените ширину области, введя следующее выражение в верхнее текстовое поле. document.forms[0].output.cols = 30; Затем сделайте область выше на строку. document.forms[0].output.rows++ 710 Часть III. Объекты документа
Все свойства, методы и обработчики события текстовых полей применимы к объекту text area. Они действуют точно так же (конечно, кроме свойства type, значением которого является textarea). Следовательно, подробно о написании сценариев с использованием этого объекта можно узнать из описанных выше листингов. Далее рассматривается набор дополнительных свойств, которые являются уникальными для объекта textarea. Возврат каретки в текстовых областях Три класса операционных систем, поддерживаемых браузером Netscape Navigator — Windows, Macintosh и UNIX — не однозначно интерпретируют символ возврата каретки в текстовой строке. Это разногласие платформ касается объекта textarea и его содержимого. После того, как пользователь введет текст и воспользуется клавишей <Enter> (<Return>), в строку добавляется один или более скрытых символов. В соответствии со строковыми символами языка JavaScript символ возврата каретки состоит из комбинации символов новой строки (\п) и возврата (\г). В приведенной ниже таблице показаны символы, вставляемые в строку, для каждой из операционных систем. Операционная система Windows Macintosh Unix Символ строки \r\n \г \п Этот вопрос становится чрезвычайно важным, если вам необходимо удалить из текстовой области символы возврата каретки, чтобы обрабатывать данные в CGI-программе или в локальном сценарии. Проблема заключается в том, что для каждой платформы вам придется выполнить отдельную операцию. В случае, когда вам необходимо сохранить символы возврата каретки, но база данных на сервере не может принять этих значений, рекомендуется использовать метод string. escape () для кодирования строки (он применяется при задании URL). Символ возврата каретки преобразуется в значение %0D, а символ новой строки — в %0А. Конечно, эти символы занимают дополнительное место в базе данных, что также следует учитывать при разработке документов (и баз данных). Когда проблема символа возврата каретки рассматривается исключительно в пределах текстовой области, ситуация значительно упрощается. Начиная с NN3 и Ш4, при задании любой из комбинаций, указанных в предыдущей таблице, все платформы могут автоматически преобразовывать данные в формат, свойственный для текущей операционной системы. Следовательно, для объекта textarea на всех платформах можно задать значения 1\г\п2\г\пЗ, ив этих полях появится список столбцов 1, 2 и 3. Если кодированный текст предназначен для хранения в базе данных, то вы можете преобразовать соответствующий символ перед формированием значения текстовой области, отправляемого на сервер. Независимо от того, на какой платформе работает пользователь, символ возврата каретки будет преобразовываться корректно. При получении этих значений сценарием вы также можете наблюдать в форме символы возврата каретки, которые преобразуются корректно для указанной платформы (показаны в предыдущей таблице). Глава 23. Текстовые объекты формы 711
Свойства cols rows Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Отображаемый размер элемента text area определяется атрибутами COLS и ROWS, которые представлены в объектной модели документа, соответственно, свойствами cols и rows. Значениями для данных свойств являются целые числа. Для свойства cols число представляет количество символов, которые отображаются без применения горизонтальной полосы прокрутки; для свойства rows — количество строк текста, который отображается без применения вертикальной полосы прокрутки. См. также: свойство wrap. wrap Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство wrap представляет атрибут wrap, который не входит в стандарт HTML 4.0, разработанный консорциумом W3C. В любом случае, браузер Ш4+ позволяет задать это свойство с помощью сценария. Допустимые строковые значения — soft, hard и off. Браузер задает мягкий перенос (по умолчанию в Ш) для содержимого текста, но на самом деле в текст не добавляются символы возврата каретки. Второй параметр, hard, отвечает за добавление к тексту символов возврата каретки (которые будут отправлены на сервер в CGI- программу вместе со значением). При задании параметра off текст вводится в одну строку, распространяющуюся в правую сторону текстовой области до тех пор, пока пользователь самостоятельно не нажмет клавишу <Enter>. См. также: свойство cols. Методы createTextRange() Возвращаемое Значение: объект createTextRange Совместимость: WinIE4+, MacEE-, NN-, Moz-, Safari- Метод createTextRange () для объекта textarea действует точно так же, как и метод document'. createTextRange (), за исключением того, что данный диапазон состоит из текста, содержащегося в элементе textarea, помимо обычного содержимого. Эту версию объекта createTextRange удобно использовать, когда требуется, чтобы сценарий управлял положением курсора внутри элемента textarea вместо пользователя. См. также: объект createTextRange (глава 35). 712 Часть III. Объекты документа
Объекты select, option и fileupload IV /7 писки отображаются на форме в виде всплывающих ^в^ меню или прокручивающихся перечней. Это самые информативные и экономные элементы HTML-страницы. Они позволяют дизайнерам представить достаточный объем информации, занимающей сравнительно немного места. Пользователи хорошо знакомы с этими элементами интерфейса по работе с диалоговыми окнами операционных систем и различных приложений. Однако программировать списки достаточно тяжело, особенно в ранних версиях браузеров, поскольку сами по себе они являются сложными конструкциями. Все данные, связанные с элементами списков, представлены в элементах option, вложенных в элементы select. Как будет видно из этой главы, ссылки, поддерживающие совместимость снизу вверх, для получения информации из объекта элемента select и его объектов option могут быть достаточно длинными. Тем не менее, старания, приложенные для создания списков, стоят затраченных усилий. Кроме того, в этой главе рассматривается объект элемента ввода fileupload, возможности которого зачастую преувеличены. К сожалению, он не обеспечивает отдельного способа отправки файлов, о котором мечтают многие разработчики Web-страниц. Объект элемента select Свойства, методы и обработчики событий этого HTML- элемента описаны в главе 15.
Свойства Методы Обработчики событий form* add() onchange length options[i].add() multiple item() name* namedltem() optiond remove() selectedlndex options[i].remove() size type value * См. объект текстового поля (предыдущая глава). Синтаксис Доступ к свойствам объекта элемента select. (Все) [window. ] document. имяФормы. имяСписка. свойство \ метод { [параметры]) (Все) [window. ] document.имяФормы. elements [индекс] . свойство \метод( [параметры] ) (Все) [window.. ] document. forms [индекс] . имяСписка. свойство \ метод ( [пара- метры] ) (Все) [window.]document.forms["имяФормы"] .имяСписка.свойство\метод ( [параметры] ) (Все) [window.]document.forms["имяФормы"] .elements[индекс] .свойство\ метод ( [параметры] ) (IE4+) [window. ] document .all. идентификатор. свойство \ метод ( [параметры]) (IE5+/W3C) [window. ] document. get Element By Id ("идентификатор") . свойство \ метод ( [параметры] ) Описание объекта Объекты элементов select представляют собой, возможно, самые интересные элементы пользовательского интерфейса среди стандартных объектов. В одном формате они принимают вид всплывающих, а в другом — прокручивающихся списков. Всплывающие списки, в частности, позволяют эффективно использовать рабочую площадь страницы. Более того, только элемент, выбранный пользователем, отображается на странице, что позволяет избежать пустого заполнения страницы ненужными данными. По сравнению с другими объектами JavaScript, элементы select трудно программировать, в основном, из-за сложности представления данных, включенных в список элементов. То, что пользователь видит на странице как элемент select, состоит из самого элемента, а также элементов option, которые содержат конечные данные, выбираемые пользователями. Одни свойства, задаваемые программистам, принадлежат объекту select, другие —г- объектам option. Например, индекс текущей выбранной опции в списке является свойством объекта select. Однако, чтобы получить отображаемый текст, необходимо обратиться к свойству text объекта выбранного элемента option. 714 Часть ///. Объекты документа
При определении объекта select в форме следует внимательно задать конструкцию, состоящую из пары дескрипторов <select>. . .</select >. Прежде всего, большинство атрибутов, определяющих объект целиком (name, size, а также обработчики событий), принадлежат открывающему дескриптору <select>. Между ним и закрывающим дескриптором </select> находятся дополнительные дескрипторы, задающие каждую опцию списка. Приведенное ниже определение объекта создает всплывающий список с тремя опциями выбора цвета. <form> <select name="RGBColors" onchange="changeColor(this)"> <option selected="selected">Red</option> <option>Green</option> <option>Blue</option> </select> </form> Форматирование дескрипторов в документе HTML не является важной операцией. Я сделал отступ в строках с опциями списка лишь для повышения читаемости кода. По умолчанию элемент select отображается как всплывающий список. Чтобы он отображался как прокручивающийся список, атрибуту size необходимо присвоить значение, большее 1. Это значение определяет, сколько строк будет отображаться в списке без прокрутки (попросту говоря, это высота списка, выраженная в строках). Поскольку полосы прокрутки в графическом интерфейсе занимают определенную площадь (при отображении различных областей для щелчка мышью), не следует делать высоту таких списков меньше 4. Если это слишком много для текущей страницы, то воспользуйтесь всплывающим меню. Способы отображения всплывающих меню на различных графических платформах разные. Поскольку каждый браузер при выводе всплывающего меню практически всецело полагается на операционную систему (иногда, правда, разработчики браузеров идут своим путем), между размером всплывающего меню в ОС и браузерах существует большая разница. То, что отлично помещается в окне стандартной ширины в одной ОС, может отображаться совсем по-другому в ином браузере в другой ОС. Другими словами, на точные размеры объекта select полагаться нельзя (если вы, например, пытаетесь выровнять объект select и расположенное рядом с ним изображение). На форме объект select позволяет выбрать одновременно несколько расположенных рядом опций. Обычно этого можно достичь, одновременно нажав клавиши-модификаторы (<Shift>, <Ctrl> в зависимости от операционной системы) и щелкнув мышью на нужных опциях. Для предоставления этой возможности в элемент select необходимо добавить атрибут multiple. Для каждой записи в списке дескриптор <select> должен содержать дескриптор <option>, а также текст, представленный в качестве надписи элемента. Если при загрузке страницы необходимо, чтобы в списке отображался элемент по умолчанию, в соответствующем дескрипторе <option> задайте атрибут selected. Без этого атрибута элемент по умолчанию будет или пустым, или первым в списке, что зависит от браузера (см. описание объекта option далее в этой главе). Кроме того, в каждом дескрипторе option атрибуту value можно присвоить строковое значение. Как и в случае переключателей, им это строковое значение может отличаться от приведенного в списке текста. Таким образом, сценарий работает со "скрытым" значением, а не с отображаемым текстом, что позволяет заменить сложный URL простой строкой. Это строковое значение пересылается CGI-программе (как часть пары имя-значение), когда пользователь отправляет форму с объектом select. Одна из характеристик объекта select существенно влияет на дизайн страницы. Обработчик события onchange запускается сразу же после того, как пользователь выбирает новый элемент из всплывающего списка (за исключением ситуации, когда в браузере NN2 для Windows возникает ошибка). Если вы предпочитаете, чтобы действия выполнялись после Глава 24. Объекты select, option и fileupload 715
того, как пользователь проведет все установки в форме, опустите обработчик события on change в объекте select, но обязательно создайте кнопку, которая позволит пользователю выполнить действие на основании проведенных настроек. Изменение опций объекта select (NN3+, IE4+) Средства JavaScript обладают достаточной гибкостью для изменения содержимого объекта select. Однако они доступны лишь в браузерах NN3+ и Ш4+. Причем некоторые из них вполне прямолинейны: например, изменение свойства selectObj .options [i] .text, отвечающего за отображение отдельной записи в списке. Ситуация усложняется, когда изменяется количество опций в объекте select. В данном случае сценарий имеет следующие возможности. ■ Удаление отдельной опции (приводит к сжатию списка). ■ Изменение элементов списка в меньшую сторону. ■ Удаление всех опций. ■ Добавление новых опций к объекту. Для удаления опции из списка следует установить соответствующий элемент массива в значение null. Например, если в списке содержится пять элементов и третий необходимо удалить (сократив, таким образом, список до четырех элементов), используется следующий синтаксис (со ссылкой на объект select). selectObj.options[2] = null; После выполнения этого оператора свойство selectObj . options . length становится равным 4. Предположим, что в сценарии объект select имеет пять опций, и его нужно заменить другим объектом с тремя опциями. Вначале свойству length необходимо присвоить значение 3. selectObj.options.length = 3; Затем установите свойства text и value для каждой опции с индексом от 0 до 2. Можно начать строить новый список, полностью удалив предыдущий (однако не изменять сам объект select). Для этого достаточно установить его свойство length в значение 0. selectObj .options, length = О,- Теперь можно создать новые опции (как при расширении списка, скажем, от трех до семи элементов). Механизм создания новых опций состоит в использовании конструктора объекта: new Option (). Он имеет четыре аргумента, эквивалентных атрибутам дескриптора <option>. ■ Текст, отображаемый в списке. ■ Значение свойства value опции. ■ Опция def aultSelected (булевого типа) элемента. ■ Параметр выделения элемента в списке (булевого типа). Часть параметров можно установить в конструкторе, а часть — отдельно в других операторах (конструктор можно вызывать и без аргументов). Рекомендуем установить два первых параметра (оставив другие пустыми), а свойству selected присвоить значение отдельно. Ниже приведен пример оператора, создающего новый (пятый) элемент в списке объекта select. Этот оператор устанавливает свойства text и value. selectObj.options[4] = new Option("Yahoo","http://www.yahoo.com"); Все представленные методы демонстрируются в листинге 24.1, позволяющем изменить текст объекта select (вначале корректируя его при фиксированном числе опций, а затем 716 Часть III. Объекты документа
создавая новый набор элементов). Обработчики события onclick переключателей вызывают функции, выполняющие нужные операции, — редкий пример, когда переключатели логически инициируют какое-либо видимое действие! Листинг 24.1. Изменение < V* ^ <html> <head> <title>Changing Options On The Fly</title> <script type="text/javascript" language="JavaScript"> // флаг перезагрузки страницы в старых браузерах NN var isPreNN6 = (navigator.appName == "Netscape" && parselnt(navigator.appVersion) <= 4); // инициализация массива цветов plainList = new Array(6); hardList = new Array(6); plainList[0] = "cyan"; hardList[0] = "#00FFFFM; plainList[1] = "magenta"; hardList[1] = "#FF00FF"; plainList[2] = "yellow"; hardList[2] = "#FFFF00"; plainList[3] = "lightgoldenrodyellow"; hardList[3] = "#FAFAD2"; plainList[4] = "salmon"; hardList[4] = "#FA8072"; plainList[5] = "dodgerblue"; hardList[5] = "#1E90FFH; // изменение набора цветов function setLang(which) { var listObj = document.forms to] .colors; // фильтрация старых браузеров if (listObj.type) { // проверка количества элементов: 3 или б var listLength = listObj.length; // сохранение выбранного индекса var currSelected = listObj.selectedlndex; // замена отдельных записей for (var i = 0; i < listLength; i++) { if (which == "plain") { listObj.options[i].text = plainListti]; } else { listObj.optionsti]-text = hardListti]; } } . if (isPreNN6) { history.go(0); } else { listObj.selectedlndex = currSelected; } } } // создания нового списка опций function setCount(choice) { Глава 24. Объекты select, option и fileupload 717
var listObj = document.forms[0].colors; // фильтрация старых браузеров if (listObj.type) { // получение настроек названий цветов var lang = (document.forms[0].geekLevel[0].checked) ? "plain" : "hard"; // очистка списка listObj.length = 0; // создания новых объектов для опций списка for (var i = 0; i < choice.value; i++) { if (lang == "plain") { listObj.options [i] = new Option(plainList[i]); } else { listObj.options[i] = new Option(hardList[i]); } } listObj.options[0].selected = true; if (isPreNN6) { history.go(O); } } } </script> </head> <body> <hl>Flying Select Options</hl> <form> Choose a palette size: <input type="radio" name="paletteSizeM value="3" onclick="setCount(this) " checked="checked" />Three <input type="radio" name="paletteSize" value="6" onclick="setCount(this)" />Six <p>Choose geek level: <input type="radio" name="geekLevel" value="" onclick="setLang('plain')" checked="checked" /> Plain-language <input type="radio" name="geekLevel" value="" onclick="setLang('hard')" />Gimme hex-triplets! </p> <p>Select a color: <select name="colors"> <option selected="selected">cyan</option> <option>magenta</option> <option>yellow</option> </selectx/p> </form> </body> </html> Чтобы упростить поддержку этого кода, списки для выбора цветов (названия и шестна- дцатеричные триплеты) выделены в два отдельных массива. Циклы в обеих функциях обрабатывают эти массивы, независимо от их длины. Два первых переключателя (см. рис 24.1) запускают функцию set Lang (). Ее первичной задачей является получение ссылки на объект select для сокращения выражения обращения к объектам (просто listObj). С помощью свойства length она определяет, сколько элементов будет отображаться в списке. После этого в цикле свойству text каждой опции объекта select присваивается значение, взятое из одного массива. Во второй паре переключателей каждый из них указывает количество отображаемых элементов, когда пользователь раскрывает список. Это количество передается функции setCount () и используется как число итераций цикла. Функция определяет выбранный переключатель, 718 Часть III. Объекты документа
с помощью которого задается формат опций списка, и полностью обнуляет объект select. Опции создаются заново с помощью конструктора new Option (). Его параметрами являются строки текста, взятые из массивов. Новые опции не имеют других свойств, поэтому выбираемая по умолчанию функция устанавливает первый элемент списка. Filt EdH View Favorites T*«fc Help ф Flying Select Options Choose a palette sire: О Three <*>Six Choose geek level: 0Plain-language С Gimme hex-triplets! Select a color: j magenta cyan |yellow "* lightgoldenrodyellow salmon dodgerblue ■'.-■fa^ >№(&?• JtttUvr. mrai&r*:)iibii.if** ,,1*^иЖШЗ*Ш£££2и**-:. Рис24.1. Выбор переключателя динамически изменяет содержимое объекта select Обратите внимание, что обе функции после установки свойств объекта select в браузерах NN3 и NN4 вызывают метод history.go(0). Это дает возможность ранним версиям NN изменить размер объекта select, чтобы правильно отобразить содержимое списка. Разница хорошо заметна при переключении от списка с шестью цветами к любому другому списку. Если не изменить размер объекта, некоторые длинные названия не поместятся в отведенной области. Браузеры IE4+ и NN6 перерисовывают страницу автоматически после изменения элемента формы. Изменение опций объекта select (IE4+) Браузеры компании Microsoft Ш4+ поддерживают и другой способ изменения опций элемента select, использующий два собственных метода свойства-массива options объекта select. Они называются add () и remove (). Метод add () имеет один обязательный и один дополнительный параметр. Обязательным параметром является ссылка на объект элемента option, который сценарий создает в другом операторе (с помощью метода document. createElement ()). Если опустить второй параметр метода add(), то новый элемент option будет добавлен к текущему набору элементов. Если же во втором аргументе указан индекс, новый массив опций будет вставлен в указанную позицию. Листинг 24.2 показывает, как можно изменить функции из листинга 24.1, воспользовавшись средствами исключительно IE (изменения и дополнения выделены полужирным шрифтом). Глава 24. Объекты select, option и fileupload 719
В сценарии подразумевается, что страница будет загружаться только в браузерах Ш (другими словами, сценарий не осуществляет проверки имени браузера). При замене одного набора опций другим демонстрируются два подхода. В первом (функция set Lang ()) заменяется то же количество элементов, поэтому длина существующего массива используется в качестве счетчика и индексного значения в методах remove () и add (). Если количество элементов изменяется (как в функции set Count ()), то сначала в цикле удаляются все опции, и только после этого с помощью метода add () без второго параметра (т.е. в конец списка) добавляются новые опции. Способ, приведенный на листинге 24.2, не имеет никаких преимуществ по сравнению с тем, который применялся в листинге 24.1. Листинг 24-2. Изменение от** объекта **lect (Ш4+) function setLang(which) { var listObj = document.forms[0].colors; var newOpt; // проверка ранних версий браузеров IE if (listObj.type) { // проверка числа элементов массива: 3 или 6 var listLength = listObj.length; // сохранение выбранного индекса var currSelected = listObj.selectedlndex; // замена отдельных элементов for (var i = 0; i < listLength; i++) { newOpt = document.createElement("option"); newOpt.text - (which == "plain")?plainList[i]:hardList[i]; listObj .options.removed) ; listObj.options.add(newOpt, i); } listObj.selectedlndex = currSelected; } } // создание нового списка опций function setCount(choice) { var listObj = document.forms[0].colors; var newOpt; // проверка ранних версий браузеров if (listObj.type) { // получение настроек названий цветов var lang = (document.forms[0].geekLevel[0].checked) ? "plain" : "hard"; // очистка опций while (listObj.options.length) { listObj.options.remove(0); } // создание нового объекта опции для элементов списка for (var i = 0; i < choice.value; i++) { newOpt - document.createElement("option"); newOpt.text « (lang «« "plain")?plainList[i]:hardList[i]; listObj.options.add(newOpt); } listObj.options[0].selected = true; } } 720 Часть III. Объекты документа
Изменение опций объекта select (W3C DOM) Еще один подход возможен в браузерах, поддерживающих стандарт W3C DOM 2. В NN6, например, также можно воспользоваться методами add () и remove () объекта элемента select. Они напоминают методы массива options в ГЕ4+, однако принадлежат непосредственно объекту элемента select. Другое отличие — в синтаксисе: в NN6 метод add О в качестве второго аргумента использует не индекс, а ссылку на объект элемента option, перед которым нужно вставить новый элемент. Этот аргумент является обязательным. Для добавления элемента в конец текущего списка необходимо указать значение null. Сценарий, измененный для поддержки объектной модели W3C, приведен на листинге 24.3. Полужирным шрифтом выделены отличия между версиями Ш4+ и W3C DOM. felt!■■■■■ ЬА * i*^.^»^-,v«дд«а^»ы;^%^ ******* h& i /■ „ дрршянг 24.3. изменение щщт отнрю* йм^ , ■ ; /;^ function setLang(which) { var listObj = document.forms[0].colors; var newOpt; // проверка ранних версий браузеров IE if (listObj.type) { // проверка количества элементов: 3 или б var listLength = listObj.length; // сохранение выбранного индекса var currSelected = listObj.selectedlndex; // замена отдельных элементов for (var i = 0; i < listLength; i++) { newOpt = document.createElement("option"); newOpt.text = (which == "plain")?plainList[i]:hardList[i] ; listObj .removed) ; listObj.add(newOpt, listObj.options[i]); } listObj . selectedlndex - currSelected; } } // создание нового списка опций function setCount(choice) { var listObj = document.forms[0].colors; var newOpt; // проверка ранних версий браузеров if (listObj.type) { // получение настроек названий цветов var lang = (document.forms[0].geekLevel[0].checked) ? "plain" : "hard"; // очистка списка while (listObj.options.length) { listObj.remove(0); } // создание объектов опции для элементов списка for (var i = 0; i < choice.value; i++) { newOpt = document.createElement("option"); newOpt.text = (lang == "plain")?plainList[i]ihardList[i]; listObj.add(newOpt, null); } ' ' ' i ' ■■ ' ■■" Глава 24. Объекты select, option и fileupload 721
listObj.options[0].selected = true; Как и в случае с Ш4, версия для W3C не имеет никаких преимуществ по сравнению с исходной. Свойства length Значение: целочисленное Чтение/Запись (см. текст) Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Как и все массивы в JavaScript, options имеет свойство length. Однако вместо него используется свойство length самого объекта select. Его значение представляет собой число опций в объекте. Свойство length объекта select с тремя опциями равно 3. В браузерах NN3+ и ГЕ4+ это свойство можно уменьшать после загрузки документа для сокращения количества элементов в списке. Задание значения 0 делает объект Select пустым, однако не заставляет его исчезнуть. Пример В листинге 24.1 приведен пример использования свойства length. С его помощью в цикле просматриваются все элементы списка. Поскольку счетчик (i) в качестве начального значения принимает число 0, то цикл выполняется до тех пор, пока счетчик не станет равен значению свойства length. См. также: свойство options. multiple Значение: булево Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Свойство multiple соответствует значению атрибута multiple объекта элемента select. Если оно равно true, элемент позволяет выделить несколько опций списка одновременно (в Windows, например, для этого используется комбинация <Сп*1+щелчок>). Если требуется преобразовать всплывающий список в список select с подцержкой выделения нескольких элементов, измените свойство size для отображения максимального набора опций в списке. Пример Следующее выражение изменяет значение свойства multiple на противоположное, но только в тех списках, свойство size которых установлено в значение, большее 1. document.forms[0].mySelect.multiple = !document.forms[0].mySelect.multiple; См. также: свойство size. options[индекс] Значение: массив элементов opt ion Только для чтения Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ 722 Часть III. Объекты документа
Как правило, это свойство не используется само по себе. Чаще оно является частью ссылки на свойства (или метода в современных версиях браузеров) определенной опции в составе объекта select. Другими словами, свойство options — это шлюз к другим свойствам, например, значениям в списке. В ранних версиях браузера NN, в предупреждении, выводимом на экран в результате ссылки на массив options, отображался HTML-код опции. Современные версии просто сообщают, что значение является объектом. В последних версиях браузеров (IE4+ и NN6+) на опции можно ссылаться как на отдельные объекты элементов HTML. Такие ссылки не требуют префикса объекта элемента form или select. Но для обеспечения совместимости снизу вверх рекомендуется использовать длинные ссылки, содержащие объект select. Несколько следующих опций включены в описание объекта select, так как они совместимы даже с теми версиями браузеров, в которых элемент option не выделен в отдельный объект. Помните, что все перечисленные свойства, включающие и префикс options [индекс], в браузерах IE4+ и NN6+ являются также свойствами объекта элемента option. Пример В листингах 24.1-24.3 приведен пример использования массива options. С его помощью сценарий получает информацию об элементах списка См. также: все элементы options [index] .property. options[индекс].defaultSelected Значение: булево Только для чтения Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Если определение объекта select включает опцию с атрибутом selected, ее свойство def aultSelected содержит значение true. Для всех остальных опций свойство def aultSelected равно false. Если объект select поддерживает выделение нескольких опций (причем его атрибут size больше 1), то атрибут selected может быть задан для нескольких опций. После загрузки страницы все элементы с этим атрибутом будут предварительно выделены (включая даже несмежные позиции). Пример Следующее выражение сохраняет в переменной булево значение, указывающее на выбор в качестве элемента по умолчанию первого элемента списка. var zeroIsDefault = document.forms[0].listName.options[0]. defaultSelected; См. также: свойство options [индекс] . selected. options[индекс].index Значение: целочисленное Только для чтения Совместимость: WinIE3+, Macffi3+, NN6+, Mozl+, Safaril+ Значение index любой опции объекта select, скорее всего, окажется лишним в сценарии. Поскольку к опции можно обратиться без индекса (используя как часть ссылки options [индекс]), в его использовании нет необходимости. Глава 24. Объекты select, option и fileupload 723
Пример Приведенное ниже выражение назначает целочисленный индекс первого элемента списка listName переменной itemlndex. var itemlndex = document.forms[0].listName.options[0].index; См. также: свойство options. options[индекс].selected Значение: булево Чтение/Запись Совместимость: WinEE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Как уже отмечалось, существуют более удобные методы поиска опции, которую выбрал пользователь, чем просмотр в цикле всех опций и проверка их свойств selected. Исключением является список с поддержкой нескольких выделений. В этой ситуации свойство selectedlndex возвращает индекс самой первой выбранной опции в списке. Поэтому сценарию необходимо проверить значение свойства selected (true или false) каждой опции. Пример Для учета выбранных в списке опций функция seeList () листинга 24.4 анализирует свойство option [индекс] .selected каждого элемента. Текст выбранного элемента добавляется в переменную result после символа \п, указывающего на возврат каретки в строке. Эта переменная выводится в отдельном диалоговом окне. <html> <head> <title>Accessories List</title> <script type="text/javascript"> function seeList(form) { var result = ""; for (var i = 0; i < form.accList.length; i++) { if (form.accList.options[i].selected) { result += "\n " + form.accList.options[i].text; } } alert("You have selected:" + result); } </script> </head> <body> <form> <p>Control/Command-click on all accessories you use: <select name="accList" size="9" multiple="multiple"> <option selected="selected">Color Monitor</option> <option>Modem</option> <option>Scanner</option> <option>Laser Printer</option> <option>Tape Backup</option> <option>MO Drive</option> <option>Video Gamera</option> </select></p> <pxinput type-"button" value="View Summary..." 724 Часть III. Объекты документа
onclick="seeList(this.form)" /></p> </form> </body> с /html > См. также: свойства options [индекс] .text, options [индекс] .value, selected- Index. options[индекс] .text Значение: строка Чтение/Запись Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Свойство text содержит текст, отображаемый в опции списка. Если этот текст применяется для выполнения определенных задач, то вам нужно извлечь его с помощью данного свойства. Однако, если сценарию требуется не текст опции, а сама опция, то в сценарии лучше воспользоваться атрибутом value, а потому и свойством options [индекс] .value (см. листинг 26.6). Пример Чтобы продемонстрировать практическую ценность свойства text, в листинге 24.5 текст выделенного элемента списка назначается свойству document .bgColor документа в окне браузера. Поскольку значения последнего свойства чувствительны к регистру символов, то имена цветов перед присвоением необходимо преобразовать в прописные символы. <html> <head> <title>Color Changer l</title> <script type=Mtext/javascript"> function seeColor(form) { var newColor = (form.colorsList.options [form.colorsList.selectedlndex].text); document.bgColor = newColor; } </script> </head> <body> <form> <p>Choose a background color: <select name="colorsList"> <option selected="selected">Gray</option> <option>Lime</option> <option>Ivory</option> <option>Red</option> </selectx/p> <p><input type="button" value="Change It" onclick="seeColor(this.form)" /></p> </form> </body> </html> См. также: свойство options [index] .value. Глава 24. Объекты select, option и fileupload 725
options[индекс] .value Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Во многих случаях, названия опций в списке представляются в удобной для пользователей форме, но неудобной для управления в сценариях. Вы можете либо создать процедуру поиска, сверяющую значения свойств selectedlndex или options [индекс] .text с теми значениями, которые требуются сценарию, либо просто сохранить значения в атрибутах value элементов <option> объекта select. Затем при необходимости к ним можно легко обратиться. Атрибуту value допускается присваивать любое строковое выражение, включая URL, свойства объекта или даже описание страницы целиком, задаваемое, например, в методе parent.frames[индекс].document.write(). Начиная с браузеров IE4 и NN6, объект элемента select имеет свойство value, которое возвращает значение свойства value выбранной опции. Для совместимости снизу вверх рекомендуется, все же, использовать подход, приведенный в примере. Пример В листинге 24.6 текст элементов списка представлен простыми описательными выражениями, а не стандартными названиями цветов. Чтобы корректно назначить цвет фона страницы, необходимо использовать одно слово, а не все выражение. Это слово сохраняется в атрибуте value дескриптора <option>. Единственная функция сценария считывает значение этого атрибута и назначает его свойству bgColor текущего документа. Если вы предпочитаете работать с шестнадцатеричными числовыми идентификаторами цветов, то можете также использовать их в коде дескрипторов <option>. Например, <option value= "#e9967an >Dark Salmon. <html> <head> <title>Color Changer 2</title> <script type="text/javascript"> function seeColor(form) { var newColor = (form.colorsList.options [form.colorsList.selectedlndex].value); document.bgColor = newColor; } </script> </head> <body> <form> <p>Choose a background color: <select name="colorsList"> <option selected="selected" value="cornflowerblue"> Cornflower Blue</option> <option value="darksalmon">Dark Salmon</option> <option value="lightgoldenrodyellowM>Light Goldenrod Yellow</option> <option value="seagreen">Sea Green</option> </selectx/p> <p><input type="button" value="Change It" onclick="seeColor(this.form)" /></p> </form> </body> </html> См. также: свойство options [индекс] . text. 726 Часть III. Объекты документа
selectedlndex Значение: целочисленное Чтение/Запись Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ Когда пользователь выбирает элемент из списка, свойство selectedlndex изменяет свое значение на индекс этого элемента. Индекс первого элемента равен 0. Он необходим сценарию для извлечения информации о выбранной опции из списка. Индексом можно воспользоваться для доступа к свойствам выбранной опции. Чтобы проверить свойство selected объекта select, вместо циклического прохождения по всем опциям нужно воспользоваться свойством selectedlndex и создать ссылку на выбранный элемент. Ссылка получится длинной, однако, с точки зрения выполнения, такая методика является наиболее эффективной. Если объект select поддерживает выделение нескольких опций, свойство selectedlndex содержит индекс первого выбранного элемента. Чтобы запрограммировать выбор определенной опции, необходимо присвоить целочисленное значение свойству selectedlndex объекта элемента select, как показано в листингах 24.1-24.3. Пример В функции inspect (), приведенной в листинге 24.7, значение в квадратных скобках, которое определяет индекс, задано свойством selectedlndex. Поскольку это свойство всегда возвращает целочисленное значение, оно полностью удовлетворяет требования к индексу свойства options. Таким образом, если вы выберете в списке опцию Green, то выражение form.colorsList .selectedlndex возвратит значение 1. В результате ссылка form. color sLi s t. opt ions [ 1 ] . text будет соответствовать текстовому значению Green. <html> <head> <title>Select Inspector</title> <script type="text/javascript"> function inspect(form) { alert(form.colorsList.options[form.colorsList. selectedlndex].text); } </script> </head> <body> <form> <pxselect name="colorsList"> <option selected="selected">Red</option> <option value="Plants">Green</option> <option>Blue</option> </selectx/p> <pxinput type= "button" value="Show Selection" onclick="inspect(this.form)" /></p> </form> </body> </html> См. также: свойство options. Глава 24. Объекты select, option и fileupload 727
size Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство size соответствует значению атрибута size объекта элемента select. Это целочисленное значение показывает, сколько опций отображено в списке без прокрутки. Пример В следующем выражении свойство size задает количество отображаемых элементов равным 5. document.forms[0].mySelect.size = 5; См. также: свойство multiple. type Значение: строка Только для чтения Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1 + Свойство type позволяет идентифицировать объект select среди группы неизвестных элементов формы. Значение строки зависит от того, как был определен объект select: выбирается один элемент (select-one) или несколько (select-multiple). См. также: свойство form, elements. value Значение: строка Чтение/Запись (см. текст) Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Последние версии браузеров (и W3C DOM) поддерживают свойство value объекта элемента select. Оно содержит строку, присвоенную атрибуту value (или свойству value) текущего выбранного элемента option. Если атрибуту не присвоено значение, это свойство возвращает пустую строку. В браузерах нового поколения свойство value объекта элемента select используется вместо более длинной версии, требующей ссылки на свойство selectedlndex и массив options. Если этому свойству присвоить новую строку (причем, если она не совпадает с существующим значением опции), Ш создаст пустую опцию в списке. Несмотря на то, что формально в NN6 это свойство предназначено для чтения/записи, присвоение новой строки не вызывает изменения значения свойства. Пример Функция seeColor () в листинге 24.6 получает доступ к значению выбранного элемента. Используемую в ней ссылку можно упростить, если сценарий выполняется в новых версиях браузеров. function seeColor(form) { document.bgColor = form.colorsList.value; } См. также: свойство options [индекс] .value. 728 Часть III. Объекты документа
Методы add (ссылкаНаНовыйЭлемент [, индекс]) add (ссылкаНаНовыйЭлемент, ссылкаНаЭлемент) remove{индекс) Возвращаемое Значение: отсутствует Совместимость: WinIE5+, MacIE5+, NN6+, Mozl+, Safari 1+ Эти методы используются в W3C для вставки и удаления элементов списка. Первый атрибут метода add О — это новый элемент option, добавляемый в список. Второй аргумент зависит от используемого браузера. В ТЕ второй атрибут метода add () представляет собой индекс добавляемого элемента в списке. Элемент будет вставлен перед элементом с указанным индексом или в конец списка, если второй аргумент метода не указан. В W3C второй аргумент представляет ссылку на элемент списка, перед которым вставляется новый элемент. Если второй аргумент метода add () равен null, то новый элемент вставляется в конец списка. options[индекс] .add(ссылкаНаЭлемент[, индекс]) options[индекс].remove() Возвращаемое Значение: отсутствует Совместимость: WinIE4+, МасГЕ4+, NN-, Moz-, Safari- Оба поддерживаемых в IE метода принадлежат свойству-массиву options объекта элемента select (см. описание этого объекта ранее в этой главе, где рассказано, как нужно использовать эти и эквивалентные им методы в других браузерах и объектных моделях). item (индекс) О namedl tem (" идентификатор") () Возвращаемое Значение: ссылка на элемент option Совместимость: WinIE5+, МасГ£5+, NN-, Moz-, Safari- Методы item () и namedltem () поддерживаются только в браузерах компании Netscape. Они предназначены для быстрого доступа к объектам элементов option, вложенных в объект select (вместо массива options с индексацией элементов). Аргументом метода item О является целочисленный индекс. Например, два следующих оператора указывают на один и тот же объект элемента option. document.forms[0].mySelect.options[2] document.forms[0].mySelect.item(2) Если в сценарии известен идентификатор элемента option (являющийся строкой), им можно воспользоваться как аргументом метода namedl tern (). Пример В следующем выражении ссылка на элемент опции сохраняется в переменной. var oneOption = document.forms[0].mySelect. namedl t em (" opt ion3_2"); См. также: свойство options. Глава 24. Объекты select, option и fileupload 729
Обработчики событий onchange Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safaril+ Когда пользователь выбирает новый элемент в списке объекта select, происходит событие onchange. В примерах, приведенных ранее в этом разделе (в частности, листинги 24.6 и 24.7), действие связано с отдельной кнопкой. Такой подход оказывается удобным при определенных обстоятельствах, особенно в списках select, поддерживающих групповое выделение, или любых всплывающих списках. (Обычно щелчок на опции во всплывающем списке не производит никакого видимого для пользователя действия.) Однако в большинстве всплывающих меню желательно, чтобы действие осуществлялось при выборе элемента. Для этого в определение объекта <select> необходимо включить обработчик события onchange. Если пользователь вторично выберет один и тот же элемент, событие onchange не запустит. В этом случае действие все равно можно выполнить, воспользовавшись обработчиком события onclick, которое, однако, доступно для объекта select лишь в браузерах Ш4+ и W3C. Пример Листинг 24.8 представляет собой измененный листинг 24.6. Сценарий этого документа выполняет все свои действия после выбора пользователем элементов в раскрывающемся списке. В данном случае обработчик события onchange дескриптора <select> заменяет кнопку выполнения действий. Рассматриваемое приложение позволяет выполнить все необходимые операции "немедленно", не прибегая к услугам командных кнопок. Обратите внимание на некоторые изменения. Теперь элемент select в качестве первой опции содержит пустую строку. Таким образом, когда пользователь открывает страницу, ничего не происходит. Функция в обязательном порядке проверяет, что выбрал пользователь перед тем, как изменить фоновый цвет. Второе изменение касается элемента body. Теперь он содержит обработчик onunload, восстанавливающий форму. Его назначение очень простое — когда пользователь откроет в текущем окне новую страницу, а затем возвратится обратно с помощью кнопки Back (Назад), он не увидит цветной заливки — форма возвратится к исходному состоянию. В связи с внутренней ошибкой в браузерах Ш4 и Ш5 восстановление не выполняется. В качестве альтернативного варианта можно предложить запускать функцию seeColor () в обработчике onload, подставив в нее ссылку на элемент select в качестве аргумента. Листик Й^ Й1^1^»жй тюти (Ьона шшмыб^^ еашш -ч t^f^t <html> <head> <title>Color Changer 2</title> <script type="text/javascript"> function seeColor(list) { var newColor = (list.options[list.selectedlndex].value); if (newColor) { document.bgCo1or = newColor; } } . </script> </head> <body onunload="document.forms[0].reset()M> <form> 730 Часть III. Объекты документа
<p>Choose a background color: <select name="colorsList" onchange="seeColor(this)n> <option selected="selected" value=""></option> <option value^'cornflowerblue">Cornflower Blue</option> <option value="darksalmon">Dark Salmon</option> <option value="lightgoldenrodyellow">Light Goldenrod Yellow</option> <option value="seagreen">Sea Green</option> </selectx/p> </form> </body> </html> Объект элемента option Свойства, методы и обработчики событий этого элемента описаны в главе 15. Свойства Методы Обработчики событий defaultSelected form* label selected text value * См. объект текстового поля (глава 23). Синтаксис Доступ к свойствам объекта option. (All) [window. ] document. имяФормы. имяСписка. options [индекс] . свойство | метод ( [параметры] ) (Все) [window.]document.имяФормы.elements[индекс].options[индекс]. ев ойс тво\ме тод ( [ параме тры] ) (Все) [window. ] document. forms [индекс] . имяСписка. options [индекс] . ев ойс тв о | метод ( [ параме тры] ) (Все) [window.]document.forms["имяФормы"].имяСписка.options[индекс]. свойство]метод( [параметры] ) (Все) [window.]document.forms["имяФормы"].elements[индекс] .options [индекс] . свойство]метод( [параметры] ) (IE4+) [window. ] document .all. идентификатор. евойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document.getElementByld ("идентификатор") . свойство \ метод ( [параметры] ) Глава 24. Объекты select, option и fileupload 731
(W3C) [window. ] document. forms [индекс] . имяСписка. item {индекс) . свойство \ метод ( [параметры] ) (W3C) [window. ] document. forms [" имяФормы" ] . имяСписка. namedltern (идентификатор) . свойство I метод ( [параметры] ) ' Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Описание объекта Элементы option являются вложенными в элементы select. Каждая опция представляет собой элемент в списке, отображаемом элементом select. Свойства объекта option позволяют проверить, является ли данная опция выбранной в текущий момент или по умолчанию. Кроме видимого текста, объекту можно присвоить и скрытое значение. Подробная информация о взаимодействии объектов элементов select и option, а также о свойствах и методах массива options была изложена ранее при описании объекта select. Все свойства объекта option, совместимые снизу вверх (def aultSelected, selected, text и value), были рассмотрены в разделе, посвященном объекту select. Далее мы назовем уникальные свойства, поддерживаемые только в современных версиях браузеров. В браузерах NN3+ и IE4+ для создания нового объекта option предназначена функция- конструктор Option, поддерживающая следующий синтаксис. var newOption = new Option("текст","значение"); В данном случае текст является надписью, отображаемой в списке, а значение— строкой, присваиваемой свойству value новой опции. Новый объект option не добавляется к объекту select. Для этого его необходимо включить в массив options. Пример того, как можно изменять опции, приведен в листинге 24.1. Свойства label Значение: строка » Чтение/Запись Совместимость: WinIE6+, МасШ5+, NN6+, Mozl+, Safari 1+ Свойство label соответствует атрибуту label элемента option (стандарт HTML 4.0). Этот атрибут (и свойство) позволяет присвоить опции новый текст. Свойство поддерживается в браузерах МасПЕ5 и NN6. В МасШ5 любая строка, присваиваемая атрибуту label или соответствующему свойству, заменяет текст, находящийся между открывающим и закрывающим дескрипторами элемента option. Поэтому определенное содержимое можно присвоить и атрибуту, и дескриптору, но только браузеры, поддерживающие стандарт HTML 4.01, будут отображать значение свойства label. Несмотря на то, что это свойство поддерживается в NN6, браузер не изменит отображаемого текста после изменения значения свойства. Пример Следующее выражение изменяет текст, отображаемый в списке элементов. document.forms[0].mySelect.options[3].label = "Widget 9000"; Если текущая опция выбрана, то ее текст принимает указанный в подписи вид. См. также: свойство text. 732 Часть III. Объект документа
Объект элемента optgroup Свойства, методы и обработчики событий этого элемента описаны в главе 15. Свойства Методы Обработчики событий '- '"■■■' ' ' ' ■ ■ ■ i ■ i .I-. .I. i ii i» form* label * См. объект текстового поля (глава 23). Синтаксис Доступ к свойствам объекта optgroup. (IE) [window. ] document. all. "идентификатор" . свойство] метод( [параметры] ) (NN6) [window. ] document .getElementByld ("идентификатор") Мвойство\ме- тод{ [параметры] ) Совместимость: WinIE6+, MacIE5+, NN6+, Mozl+, Safari 1+ Описание объекта Элемент optgroup (стандарт HTML 4.0) позволяет разработчикам группировать опции в списке select. Надпись, присваиваемая элементу optgroup, отображается в списке как невыбираемая опция. В NN6 элементы optgroup по умолчанию отображаются полужирным курсивным шрифтом. Обычные элементы option внутри группы отображаются обычным шрифтом и начертанием. Объект элемента optgroup имеет гораздо меньше свойств, методов и обработчиков событий, чем другие элементы, поскольку (на момент написания этой книги) он не был включен в объектную модель документа браузера WinlE, хотя и поддерживался в браузере МасГ£5, позволяя создавать иерархически правильно форматированные меню. Браузеры, не распознающие этот элемент, попросту игнорируют его. Опции отображаются так, будто элементы optgroup отсутствуют. Свойства label Значение: строка Чтение/Запись Совместимость: Winffi6+, МасГЕ5+, NN6+, Mozl+, Safari 1+ Свойство label соответствует атрибуту label элемента optgroup (стандарт HTML 4.0). Этот атрибут (и свойство) позволяет присвоить текст надписи, выделяющей группу вложенных элементов option во всплывающем списке. I В Мас1Е5 присвоить значения последнему элементу optgroup внутри элемента /Назаметку select невозможно из-за внутренней ошибки программы. Глава 24. Объекты select, option и fileupload 733
Пример Приводя листинг 24.9, мы надеемся, что Microsoft и Netscape, наконец-то, исправят все ошибки, связанные с использованием в сценариях свойства label. При правильном выполнении этого кода в списке цветов отображаются имена групп элементов. Будьте готовы к тому, что далеко не все браузеры справятся с выполнением этого сценария. Щ^§^Ш&Шг^ЩЩ2^^ <html> <head> <title>Color Changer 3</title> <script type="text/javascript"> var regularLabels = ["Reds","Greens","Blues"]; var naturalLabels = ["Apples","Leaves","Sea"]; function setRegularLabels(list) { var optGrps = list.getElementsByTagName("optgroup"); for (var i = 0; i < optGrps.length; i++) { optGrps[i].label = regularLabels[i]; } } function setNaturalLabels(list) { var optGrps = list.getElementsByTagName("optgroup"); for (var i = 0; i < optGrps.length; i++) { optGrps[i].label = naturalLabels[i]; } } function seeColor(list) { var newColor = (list.options[list.selectedlndex].value) if (newColor) { document.bgColor = newColor; } } </script> </head> <body onunload="document.forms[0].reset()"> <form> <p>Choose a background color: <select name="colorsList" onchange="seeColor(this)"> <opt$roup id="optGrpl" label="Reds"> <option value="#ff9999">Light Red</option> <option value="#ff3366">Medium Red</option> <option value="#ff0000">Bright Red</option> <option value="#660000">Dark Red</option> </optgroup> <optgroup id="optGrp2" label="Greens"> <option value="#ccff66">Light Green</option> <option value="#99ff33">Medium Green</option> <option value="#00ff00">Bright Green</option> <option value="#006600">Dark Green</option> </optgroup> <optgroup id="optGrp3" label="Blues"> <option value="#ccffff">Light Blue</option> <option value="#66ccff">Medium Blue</option> <option value="#0000ff">Bright Blue</option> <option value="#000066">Dark Blue</option> </optgroup> 734 Часть III. Объекты документа
</selectx/p> <p><input type="radio" name="labels" checked="checked" onclick="setRegularLabels(this.form.colorsList)" />Regular Label Names <input type="radio" name="labels" onclick="setNaturalLabels(this.form.colorsList)" /> Label Names from Nature</p> </form> </body> </html> См. также: свойство option. label. Объект элемента ввода файла Свойства, методы и обработчики событий этого элемента описаны в главе 15. Свойства Методы Обработчики событий defaultValue* form* name* readonly* size* type* value* select ()* onchange* * См. объект текстового поля (глава 23). Синтаксис Доступ к свойствам файлового объекта input. (NN3+/IE4+) [window. ] document. имяФормы. имяПоля. свойство \метод ([параметры] ) (NN3+/IE4+) [window. ] document. имяФормы. elements [индекс] . свойство \ метод ([параметры] ) (NN3+/IE44-) [window. ] document. forms [индекс] . имяПоля. свойство \ метод ( [пара - метры] ) (NN3+/IE4+) [window. ] document. forms ["имяФормы" ] . имяПоля. свойство \ метод {[параметры] ) (NN3+/IE4+) [window. ] document. forms [ "имяФормы" ] . elements [индекс] . свойство | метод ( [параметры] ) (IE4+) [window. ] document .all. идентифика тор. евойство \ метод ([ параметры]) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ метод ([параметры] ) Глава 24. Объекты select, option и fileupload 735
Описание объекта Некоторые Web-узлы позволяют выгружать файлы с клиентской стороны на серверную. Для этого, как правило, используется форма, пересылающая файл CGI-программе на сервере. Элемент input, тип которого определен как file (известный также как объект fileUpload), представляет собой пользовательский интерфейс, необходимый для указания выгружаемого файла. Без сервера, принимающего файл, этот элемент не осуществляет никаких действий. Кроме того^ два атрибута элемента form необходимо установить следующим образом. method="POST" enctype="multipart/form-data" Этот элемент отображает поле и кнопку Browse (Обзор). С ее помощью вызывается стандартное диалоговое окно открытия файла (его вид зависит от операционной системы), в котором пользователь указывает файл. После этого в поле ввода появляется имя файла (или путь к нему, в зависимости от операционной системы). При этом имя файла содержится в свойстве value объекта. С клиентской стороны для этого объекта не требуется дополнительного программирования. Свойство value, например, в ранних версиях браузеров предназначено Только для чтения. Кроме того, форма не может выгрузить файл на сервер без согласия пользователя. Пример Увидеть, как выглядит данный элемент, позволяет листинг 24.10. <html> <head> <title>FileUpload Object</title> </head> <body> <form method="POST" action="yourCGIURL" enctype="multipart/form-data">File to be uploaded: <input type*"file" size="40" name=MfileToGo" /> <p><input type="button" value="View Value" onclick="alert(this.form.fileToGo.value)" /></p> </form> </body> </html> Для использования этого кода в реальных проектах в атрибуте action дескриптора <f orm> необходимо обозначить кнопку Submit и указать реальный URL. 736 Часть ///. Объекты документа
Объекты событий ■Г"1*) браузерах Ш4+ и NN4+ любое действие пользовате- 1щ& ля или системы — событие — передается обработчику событий, описанному в виде атрибута внутри дескриптора HTML. Например, когда пользователь щелкает мышкой, событие щелчка запускает обработчик события onclick. При этом выполняется* отдельная функция или встроенный сценарий JavaScript (т.е. само событие ничего не делает: оно или происходит, или нет). Событие (например, изменение координаты указателя в тот момент, когда пользователь щелкнул кнопкой мыши) и связанное с ним действие (например, нажатие клавиши-модификатора в момент запуска события) — это не одно и то же (хотя до четвертой версии браузеров эти понятия были эквивалентны). Сохранив полную обратную совместимость со старыми обработчиками событий, браузеры четвертой версии поддерживают первую модель событий, согласно которой каждому событию соответствует объект определенного класса. Когда происходит событие свойства этого объекта, они автоматически получают всю информацию о нем. Такие свойства полностью доступны сценарию, что позволяет страницам более "интеллектуально" реагировать на действия пользователя с самой страницей и ее элементами. Другое новшество модели событий четвертого поколения браузеров— возможность передачи событий. Таким образом, стала возможной обработка события несколькими объектами, расположенными на разных уровнях иерархии; в результате обеспечивается обработка событий многими объектами. То, что обрабатываемое событие содержит информацию о целевом объекте и другие полезные данные, гарантирует высокую интеллектуальность функций, которые могут обрабатывать событие, не ссылаясь на дополнительные источники информации. Как бы то ни было, наибольшее преимущество указанного нововведения заключается в урегулировании несовместимости между различными моделями событий. На сегодняшний день существует три модели объектов событий: NN4 (значимость которой с каждым днем уменьшается, поскольку пользователи переходят на более новые браузеры), модель событий Ш4+ и стандартизованная модель W3C DOM, pea-
лизованная в браузере NN6+. Многие отличия между разными моделями событий были описаны во вступлении к описанию модели событий в главе 15. В этой главе вы найдете исчерпывающие сведения о моделях событий и о большинстве объектов событий. Там, где это возможно, описываются межбраузерные решения. Понятие события Создать графический пользовательский интерфейс гораздо труднее, чем "старомодный" интерфейс с использованием командной строки. При использовании командной строки или системы управляющих меню набор действий, которые могут выполнятся в каждый момент времени, весьма ограничен. Эта возможность часто применяется в программировании, поскольку позволяет направлять пользователя по пути, ограниченному структурой программы. Совсем другой подход применяется при создании графических пользовательских интерфейсов, например, в операционных системах Windows, MacOS, X Window System и других, начиная с первой системы, использующей графический интерфейс XeroxStar. Задача программиста при создании действительно удобного графического интерфейса состоит в предоставлении пользователю возможности выполнять любое действие в любой момент времени: перемещать мышь, вводить команды с клавиатуры, выделять текст, выбирать опции в выпадающем меню и т.д. Для этого программа (или, точнее говоря, операционная система) должна отслеживать любые действия устройств ввода (мышь, клавиатура) и сигналы, поступающие из сети. Таким образом, операционная система регистрирует все события: как вызванные действиями пользователя, так и работой активных программ. Впоследствии система или текущая программа будет следить, как протекает каждое событие. Для этого события должны содержать определенную информацию о себе: как и в какой области экрана они происходят. Свойства событий Несмотря на большое разнообразие объектов событий, существует всего три модели события. Согласно первой модели объект событий создается в тот момент, когда происходит событие. Например, когда вы щелкаете мышью, в памяти браузера создается объект события. Когда объект создан, браузер присваивает значения свойствам события. Свойства отражают многочисленные характеристики конкретного события. Для события click — это координаты на экране и информация о том, какая кнопка мыши была использована. Чтобы облегчить задачу обработчику событий, браузер производит вычисления и устанавливает, на каком элементе экрана произошло событие click (например, на кнопке). Таким образом, одно из свойств объекта события содержит ссылку на элемент, на котором вы щелкнули мышью. Большинство свойств объекта события (для некоторых моделей событий — все свойства) доступны только для чтения. В том, что модель события позволяет изменять свойства объекта события, есть как преимущества, так и недостатки. Например, если пользователь вводит текст в текстовое поле, но там появляются совсем не те символы, которые он ввел, — ему вряд ли это понравится. С другой стороны, иногда может принести пользу изменение регистра вводимого текста (заглавные на строчные буквы) или замена одних символов другими. Каждая модель события предлагает свою концепцию управления. Модель события ГЕ4 предоставляет возможность изменять событие — нажатие клавиши на клавиатуре в модели событий NN4 и W3C DOM оказывается безрезультатным. Пожалуй, наиболее важное свойство объекта события состоит в том, что он хранится в памяти ровно столько времени, сколько требуется сценарию для обработки события. Каждое событие запускает обработчик события— обычно функцию. Эта функция, разумеется, может вызывать другие функции. Пока выполняются операторы обработчика события, 738 Часть III. Объекты документа
объект события и его свойства остаются доступными вашему сценарию в памяти, выделенной браузеру. Но когда выполняется последний оператор сценария, объект события возвращается в исходное состояние (пустой объект). Короткий срок жизни объекта — это следствие того, что в определенный момент времени существует только один объект события. Другими словами, независимо от того, насколько сложны функции обработчика событий, все они выполняются последовательно (для опытных программистов: один выполняемый поток). Операционная система заносит запущенные события в буфер. В редких случаях, когда буфер системы оказывается заполненным многими обработчиками событий, они выполняются в том порядке, в каком заносились в буфер. Статичные объекты событий Прежде мы говорили об объектах event (с маленькой е), которые являются экземплярами конкретных событий, со всем набором свойств, связанных с определенным действием. В моделях событий NN4 и W3C DOM присутствуют статичные объекты событий event. В модели событий W3C DOM представлена дополнительная подкатегория объектов. Эта подкатегория будет рассматриваться позже в данной главе, в настоящий момент нам важно показать различие между событием event и объектом event. Первое событие является временным объектом с информацией о конкретном действии пользователя; основное назначение второго — хранить значения констант-значений событий, которые могут быть использованы в сценарии. Статический объект также доступен для сценария из любого окна или фрейма. Если вы хотите увидеть список свойств объекта event в NN4 или NN6+, используйте приложение The Evaluator (описанное в главе 13); введите event в нижнее текстовое поле (можете также проверить свойства объекта KeyEvent в NN6+). Статический объект event используется и как родительский объект, т.е. на его основе могут создаваться другие объекты событий. Объект event имеет набор свойств и методов, которые передаются или наследуются другими объектам, созданным в результате определенного события. Наследование наиболее заметно проявляется в модели событий W3C DOM, при реализации которой использовались объектно-ориентированные принципы DOM. Передача событий В браузерах до 4 версии любое событие инициирует объект. Если для этого события и объекта задан обработчик события, то он выполняется; если обработчик не существует, событие игнорируется. Современные браузеры в любом случае отправляют событие в долгий путь, передавая его через объектную модель. Как уже отмечалось, на сегодняшний день существует три модели передачи события: NN4, ГЕ4 и W3C DOM, реализованная в NN6. Концепции моделей передачи событий в NN4 и ГЕ4 диаметрально противоположны. В модели W3C DOM реализованы обе модели одновременно, но с новым синтаксисом, который не повторяет ни одну из предыдущих моделей. В основу всех трех объектных моделей положено утверждение, что каждое событие имеет конкретную цель. Для действий, инициализированных пользователем, это очевидно. Если вы щелкаете мышью на кнопке или вводите текст в текстовое поле, то целью сгенерированного вами события являются, соответственно, кнопка или текстовое поле. Для событий, вызванных действиями системы, это не столь очевидно. Например, после завершения загрузки страницы возникает событие onload. Во всех моделях событий это событие запускает объект window. Различие между моделями передачи событий состоит в том, как событие достигает цели и что происходит с событием после того, как обработчик события заканчивает выполняться. Глава 25. Объекты событий 739
Передача событий в NN4 Несмотря на то, что популярность браузеров NN4 продолжает уменьшаться, эта модель передачи использует некоторые концепции, которые применяются в более современной модели W3C DOM. Название модели передачи событий в NN4 — захват события. В этой модели событие передается от верхнего в иерархии объекта window к объекту, представляющему цель события. Например, когда вы щелкаете на кнопке формы, событие щелчка проходит через объекты window и document (если возможно, то и объект layer) прежде, чем достигает объекта button (кнопка) (объект form не входит в цепочку передачи). Несмотря на кажущуюся сложность, эта передача происходит мгновенно, без потери производительности. Событие, которое проходит через объекты window, document и layer, само является полноценным объектом с полным набором свойств, описывающих действие пользователя или системы. Таким образом, если событие обрабатывается на уровне объекта window, одно из свойств объекта события содержит ссылку на объект, являющийся целью события. Благодаря этому сценарий обработчика событий, работающий на уровне объекта window, может получить необходимую информацию (например, имя кнопки) и создать ссылку на содержащую ее форму. Йо умолчанию захват события отключен. Чтобы события, проходящие через объекты window, document и layer, обрабатывались на уровне текущих объектов, включите для каждого из них захват события. Захват события в NN4 Все три описанных выше объекта— window, document и layer— имеют метод captureEvents О. С его помощью обеспечивается захват события на уровне любого из этих объектов. Данный метод требует наличия одного или нескольких параметров — имена типов событий (константы, содержащиеся в объекте Event), которые будут захвачены объектом. Остальные события пройдут через объект без изменений. Например, если вы хотите, чтобы объект window захватывал все события keyPress (нажатие клавиши на клавиатуре), включите в сценарий, выполняемый при загрузке страницы, следующую команду. window.captureEvents(Event.KEYPRESS); Желательно определить обработчик события в предполагаемом целевом объекте. Даже если он будет пустым (например onkeypress=""), это поможет быстрее сгенерировать событие. Если нужно, чтобы объект захватывал несколько типов событий, перечислите их все, используя в качестве разделителя вертикальную черту. window. captureEvents (Event. KEYPRESS | Event. CLICK) ; Далее определите, какие действия будут выполняться на уровне window над каждым типом события. Вам нужно создать функции для обработки события. Создайте ссылки на соответствующие функции, установив свойства обработчика событий объекта window следующим образом. window, onkeypress = processKeyEvent; window, onclick = processClickEvent; Теперь если пользователь введет текст в текстовое поле или щелкнет мышью в окне (window), эти события будут обработаны соответствующими функциями обработчика событий уровня объекта window. Отключение захвата события Выше мы рассмотрели захват события определенного типа. Но иногда (например, когда страница выгружается из браузера) требуется отключить захват события. Вы можете отключить захват события определенного типа, воспользовавшись методом releaseEvents () объектов 740 Часть III. Объекты документа
window, document и layer. Метод releaseEvents (), как и метод captureEvents (), требует в качестве параметров задать типы событий — константы объекта Event. Действие освобождения определенного типа события означает, что событие не обрабатывается в объектах верхнего уровня, а передается без изменений в целевой объект события (даже если в объектах верхнего уро'вня определены обработчики данного типа события). Вы можете освободить события определенного типа, указав соответствующие параметры метода releaseEvents (). События остальных типов, для которых захват события остался включенным, по-прежнему будут захватываться. Для демонстрации методов releaseEvents (), captureEvents (), а также методов других моделей событий мы представляем серию из нескольких версий одного документа HTML со встроенным сценарием JavaScript. Каждая последующая версия содержит дополнительные возможности, которые дополняют уже существующие. Также в них применяются различные типы взаимодействий между событиями и методами обработчиков событий. Документ содержит несколько кнопок и флажков, позволяющих выбирать методы, которые будут применяться. Объект layer также активно используется, поскольку многие директивы о захвате и модификации событий поступают от элементов уровня объекта layer. Листинг 25.1 — это первый пример, который демонстрирует захват и освобождение событий верхним в иерархии объектом document. Флажок позволяет устанавливать или отключать захват события click на уровне объекта document (все флажки в данном примере используют обработчик события onmouseup, так как событие click может быть изменено). Поскольку событие может захвачиваться объектом верхнего уровня, в результате применения метода captureEvents () каждый щелчок на кнопке слоя приведет к обработке события объектом верхнего уровня. (Листа*Ш.За^ '"' .' ■-;■';''- у'\-[:-'\ <html> <head> <titlex/title> <script type="text/javascript"> function setDocCapture(enable) { if (!enable) { document.captureEvents(Event.CLICK); } else { document.releaseEvents(Event.CLICK); } function doMainClick(e) { if (e.target.type == "button") { alert("Captured in top document"); document.captureEvents(Event.CLICK); document.onclick=doMainClick; </script> </head> <body> <b>Basic document-level capture of Event.CLICK</b> <hr /> <form> <input type="checkbox" onmousedown = "setDocCapture(this.checked)" checked="checked" />Enable Document Capture Глава 25. Объекты событий 741
<hr /> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event finally reached Button:' + this.name)" /> </form> <layer id="layerl" left="200" top=M150" bgcolor="coral"> <form> <br /> <pxinput type="button" value="Button ' layerButtonl ■ " name="layerButtonl" onclick="alert('Event finally reached Button:' + this.name)" /></p> <pxinput type="button" value="Button • layerButton2 ' " name="layerButton2" onclick^"alert('Event finally reached Button:' + this.name)" /></p> </form> </layer> </body> </html> Когда включен захват события на уровне объекта document (по умолчанию он включен), все события click захватываются обработчиком события объекта document — функцией, которая извещает пользователя о том, что событие было захвачено верхним в иерархии объектом. Следовательно, все события click кнопок слоя захватываются, не доходя до цели. Но если вы отключите захват, тогда события будут передаваться объекту-цели. # Если логика функции setDocCapture () кажется вам ошибочной, вспомните, что /назамену при генерировании события для флажка, сам флажок переходит в противопо- ' ,****' ложное состояние. В листинг 25.2 мы внесли некоторые дополнения, которые позволят захватить событие click объекту layer (но только тогда, когда выключен захват события объектом document). Захват события click объектом layer устанавливается с помощью JavaScript внутри дескриптора <layer>. Следовательно, если захват события верхним объектом иерархии отключен, то событие передается непосредственно кнопке и захватывается обработчиком событий слоя. Захват события объектом layer препятствует передаче событий от других объектов кнопкам слояч Эта операция становится возможной только в том случае, если вы отключите захват событий в обоих объектах: document и layer. \' document MiA <html> <head> <titlex/title> <script type="text/javascript"> function setDocCapture(enable) { if {'enable) { document.captureEvents(Event.CLICK); } else { document.releaseEvents(Event.CLICK); function setLayerCapture(enable) { if ((enable) { document.layer1.captureEvents(Event.CLICK); 742 Часть III. Объекты документа
} else { document.layerl.releaseEvents(Event.CLICK); } } function doMainClick(e) { if (e.target.type == "button") { alert("Captured in top document"); } } document.captureEvents(Event.CLICK); document.onclick=doMainClick; </script> </head> <body> <b>Document-level and/or Layer-level capture of Event.CLICK</b> <hr /> <form> <input type»"checkbox" onmousedown * "setDocCapture(this.checked)" checked-"checked" />Enable Document Capture <input type - "checkbox" onmousedown»"setLayerCapture(this.checked)" checked - "checked" />Enable Layer Capture <hr /> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event finally reached Button:' + this.name)" /> </form> <layer id="layerl" left="200" top="150" bgcolor="coral"> <ecript type-"text/javascript"> function doLayerClick(e) { if (e.target.type -= "button") { alert("Captured in layerl"); } } layerl.captureEvents(Event.CLICK); layerl.onelick-doLayerClick; </script> <form> &#160;layerl<br /> <pxinput type="button" value="Button ' layerButtonl' " name="layerButtonl" onclick="alert('Event finally reached Button:' + this.name)" /></p> <pxinput type="button" value="Button ' layerButton2 '" name="layerButton2" onclick="alert('Event finally reached Button:' + this.name)" /></p> </form> </layer> </body> </html> Глава 25. Объекты событий 743
Передача событий целевым объектам Если объект захватывает событие определенного типа, сценарий объекта может выполнять определенные действия с событием перед отправкой события к цели. Например, вам нужно выполнить определенное действие, когда пользователь щелкает на элементе интерфейса, удерживая нажатой клавишу <Shift>. В этом случае функция, обрабатывающая событие на уровне объекта document, изменяет свойства события. Если же клавиша <Shift> не была нажата, событие просто продолжит свой путь к элементу, на котором пользователь щелкнул мышью. Для передачи событий через всю объектную иерархию к целевому элементу используется метод routeEvents (), который получает в качестве параметра объект события, обрабатываемый текущей функцией. Метод routeEvents () не гарантирует того, что событие будет сразу же передано по назначению, поскольку в промежуточных объектах может быть включен захват событий данного типа и событие будет перехвачено. Эти объекты, разумеется, могут передать событие по назначению, используя собственный метод routeEvents (). Листинг 25.3 представляет собой документ, рассмотренный в предыдущих примерах, с добавлением средств передачи события. Целевые элементы события (кнопки) остаются без изменений, а функции обработчиков событий объектов получают дополнительные параметры. Для каждого из этих объектов, захватывающих события, создается флажок, который определяет, будет ли событие обрабатываться перед передачей объекту уровнем ниже. По умолчанию флажки установлены так же, как и в листинге 25.2, т.е. захват события click включен для обоих объектов: document и layer. Щелчок на любой из кнопок приводит к тому, что событие обрабатывается только обработчиком событий объекта document. Но если вы включите передачу событий на уровень ниже, то обнаружите, что щелчок на кнопках слоя вызывает два сообщения: событие обрабатывается и объектом document, и объектом layer. Если вы включите передачу событий ниже объекта layer, то щелчок на кнопке приведет к появлению трех окон сообщений. Это означает, что событие достигло конечной цели — кнопки. Поскольку кнопка mainl не является частью слоя, обработчики событий объектов слоя игнорируют связанные с ней события. <html> <head> <titlex/title> <script type="text/javascript"> function setDocCapture(enable) { if ('enable) { document.captureEvents(Event.CLICK); } else { document.releaseEvents(Event.CLICK); document.forms[0].setDocRte.checked - false; docRoute - false; } } function setLayerCapture(enable) { if (!enable) { document.layerl.captureEvents(Event.CLICK); } else { document.layerl.releaseEvents(Event.CLICK); document.forms[0].setLyrRte.checked = false; layerRoute « false; } 744 Часть III. Объекты документа
} var docRoute = false; var layerRoute a false; function setDocRoute(enable) { docRoute ■ (enable; } function setLayerRoute(enable) { layerRoute = !enable; } function doMainClick(e) { if (e.target.type == "button") { alert("Captured in top document"); if (docRoute) { routeEvent(e); } document.captureEvents(Event.CLICK); document.onclick=doMainClick; </script> </head> <body> <b>Capture, Release, and Routing of Event.CLICK</b> <hr /> <form> <input type="checkbox" name="setDocCap" onmousedown="setDocCapture(this.checked)" checked = "checked" />Enable Document Capture&#160; <input type»"checkbox" name«"setDocRte" onmousedown»"setDocRoute(this.checked)" /> And let event continue<br /> <input type="checkbox" name="setLyrCap" onmousedown="setLayerCapture(this.checked)" checked="checked" />Enable Layer Capture&#160; <input type*"checkbox" name«"setLyrRte" onmoueedown»»"setLayerRoute (this .checked) " /> And let event continue<br /> <hr /> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event finally reached Button:' + this.name)" /> </form> <layer id="layerl" left="200" top="150" bgcolor="coral"> <script type="text/javascript"> function doLayerClick(e) { if (e.target.type == "button") { alert("Captured in layerl"); if (layerRoute) { routeEvent(e); } layerl.captureEvents(Event.CLICK); layerl.onclick=doLayerClick; </script> <form> Глава 25. Объекты событий 745
&#160;layerl<br /> <pxinput type="button" value="Button ' layerButtonl' " name=nlayerButtonlM onclick="alert('Event finally reached Button:' + this.name)" /></p> <pxinput type="button" value="Button ' layerButton2 ' " name=HlayerButton2" onclick="alert('Event finally reached Button:' + this.name)" /></p> </form> </layer> </body> </html> В некоторых случаях сценарию требуется знать, было ли событие передано следующему объекту с помощью метода routeEvents (). Этот метод запускает функцию, которая возвращает значение true, если событие было передано с его помощью, и false — если нет. Возвращаемое значение используется тогда, когда объект "знает" о том, что первоначальное состояние события было изменено, и реагирует соответствующим образом (например, щелчок на ссылке может переместить или не переместить пользователя по ссылке href, в зависимости от того, что обнаруживает обработчик события — оператор return true или return false). Когда функция запускается с помощью метода routeEvents О, значение, возвращаемое конечной функцией, обратно возвращается методу routeEvents (). Это значение может обратно передавать объекту, который первоначально захватил событие. Отслеживание перемещения событий В следующем примере (последнем для модели событий NN4) объект верхнего уровня захватывает событие и передает его любому объекту в иерархии. Например, вы можете создать функцию обработчика событий объекта document, проверяющую свойство modifiers события; если оно содержит информацию о нажатии клавиши <Alt>, то функция передает событие объекту кнопки Help, обработчик события которого отображает панель справочной информации (или другой предварительно скрытый слой). Вы можете переадресовать любое событие, используя метод handle Event (). Этот метод отличается от других методов, рассмотренных в данной главе, поскольку он ссылается на объект, обрабатывающий событие (имя объекта события передается в качестве параметра, как и в других методах). Пока в целевом объекте определен обработчик для данного типа события, он (объект) обрабатывает это событие так, если бы оно генерировалось системой (даже если свойство target объекта события содержит совсем другой объект). Продемонстрируем, как выполняется переадресация событий. Листинг 25.4 содержит окончательную версию документа, который мы так долго создавали и неоднократно описывали в данной главе. В этом примере описан механизм, который позволяет направлять все события click второй кнопке слоя (в листинге layerButton2). Рассмотренные выше методы (захват события, освобождение и передача событий) продолжают работать, хотя невозможно одновременно осуществить передачу и переадресацию события. Чтобы проанализировать, как работает переадресация событий, включите захват событий для объектов document и layer (по умолчанию включена для обоих). Когда вы щелкаете на кнопке mainl, событие достигает только захватывающего событие обработчика объекта document. Но если вы выставите флажок Send event to layerButtonZ, связанный с объектом document, и щелкните на кнопке mainl, событие достигнет обработчиков событий объектов document и layerButton2 (объект связан со второй кнопкой слоя), несмотря на то, что кнопка mainl не является кнопкой слоя. Попробуйте поэкспериментировать с другими флажками и посмотреть, как выполняется захват, передача и переадресация событий. 746 Часть III. Объекты документа
<html> <head> <titlex/title> <script type="text/javascript"> function setDocCapture(enable) { if (!enable) { document.captureEvents(Event.CLICK); } else { document. releaseEvents (Event. CLICK)'; document.forms[0].setDocRte.checked = false; docRoute = false; } function setLayerCapture(enable) { if (!enable) { document.layerl.captureEvents(Event.CLICK); } else { document.layerl.releaseEvents(Event.CLICK); document.forms[0].setLyrRte.checked = false; layerRoute = false; var docRoute = false; var layerRoute = false; function setDocRoute(enable) { docRoute = !enable; document.forms[0].setDocShortCircuit.checked ■ false; docShortCircuit ■ false; function setLayerRoute(enable) { layerRoute = !enable; document.forms[0].setLyrShortCircuit.checked - false; layerShortClrcuit ■ false; } var docShortCircuit « false; var layerShortCircuit ■ false; function setDocShortcut(enable) { docShortCircuit = (enable; if (docShortCircuit) { document.forms[0].setDocRte.checked ■ false; docRoute * false; } } function setLayerShortcut(enable) { layerShortCircuit ■ 1enable; if (layerShortCircuit) { document.forms[0].setLyrRte.checked ■ false; layerRoute ■ false; } } function doMainClick(e) { if (e.target.type == "button") { alert("Captured in top document"); if (docRoute) { routeEvent(e); Глава 25. Объекты событий 747
} else if (docShortCircuit) { document.layer1.document.forms[0].layerButton2. handleEvent(e); } } } document.captureEvents(Event.CLICK); document.onclick=doMainClick; </script> </head> <body> <b>Redirecting Event.CLICK</b> <hr /> <form> <input type="checkbox" name="setDocCap" onmousedown="setDocCapture(this.checked)" checked = ' "checked" />Enable Document Capture&#160; <input type="checkbox" name = "setDocRte" onmousedown="setDocRoute(this.checked)" /> And let event continue <Input type*"checkbox" name-"setDocShortCircuit" onmousedown*"setDocShortcut(this,checked)" />Send event to 1layerButton2'<br /> <input type="checkbox" name="setLyrCap" onmousedown="setLayerCapture(this.checked)" checked="checked" />Enable Layer Capture&#160; <input type="checkbox" name="setLyrRte" onmousedown = "setLayerRoute(this.checked)" />And let event continue <input type»"checkbox" name-"setLyrShortCircuit" onmousedown*"setLayerShortcut(this.checked)" /> Send event to •layerButton2%<br /> <hr /> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event finally reached Button:' + this.name) " />. </form> <layer id="layerl" left="200" top="200" bgcolor="coral"> <script type="text/javascript"> function doLayerClick(e) { if (e.target.type == "button") { alert("Captured in layerl"); if (layerRoute) { routeEvent(e) ; } else if (layerShortCircuit) { document.forms[0]•layerButton2.handleEvent(e); »' } layerl.captureEvents(Event.CLICK) layerl.onclick=doLayerClick </script> <form> &#160;layerl<br /> <pxinput type="button" value="Button ' layerButtonl' " name="layerButtonl" onclick="alert('Event finally reached Button:' + this.name)" /></p> <pxinput type = "button" value="Button ' 1 ayerButton2 ■ " name="layerButton2" onclick="alert('Event finally 748 Часть III. Объекты документа
reached Button:' + this.name)" /></p> </form> </layer> </body> </html> Передача событий в 1Е4 Передача событий в Ш4 базируется на других принципах, отличных от принципов модели захвата событий в NN4. Модель передачи называется всплыванием события — в ней события, словно пузырьки в воде, поднимаются от целевого объекта вверх через все элементы иерархии. Вам следует ощутить разницу между старой моделью иерархической структуры объектов (принятой в модели захвата событий NN4) и более современным ее представлением — HTML-контейнеров, концепция которых принята в модели W3C DOM. Лучший способ продемонстрировать всплывание событий (поведение, которое включено по умолчанию), состоит в создании простого документа с несколькими обработчиками событий (посмотрите, как запускается каждый из них). Листинг 25.5 содержит обработчики события onclick, определенные для кнопки внутри формы, самой формы и каждого объекта элемента иерархии, вплоть до window. Листинг 25.5. Демотетр*^ <html onclick="alert('Event is now at the HTML element.')"> <head> <title>Event Bubbles</title> <script type="text/javascript"> function init() { window.onclick = winEvent document.onclick = docEvent; document.body.onelick = docBodEvent; } function winEvent() { alert("Event is now at the window object level."); } function docEventО { alert("Event is now at the document object level."); } function docBodEvent() { alert("Event is now at the BODY element."); } </script> </head> <body onload="init()"> <hl>Event Bubbles</hl> <hr /> <form onclick="alert('Event is now at the FORM element.')"> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event started at Button: ' + this.name)" /> </form> </body> </html> Глава 25. Объекты событий 749
Этот документ будет корректно работать в Ш4 и NN6, поскольку эти браузеры поддерживают всплывающие события. Но выполнение кода в различных браузерах и на различных платформах будет иметь свои особенности (например, в WinIE4+, MacIE4+ и W3C). После того, как вы щелкнете на кнопке документа, описанного в листинге 25.5, событие достигнет цели — кнопки. Потом событие начнет "всплывать" через элементы HTML: вначале через содержащий кнопку элемент form, потом через элемент body и т.д. Различия в поведении события начинают проявляться после элемента body. В табл. 25.1 можно увидеть, для каких элементов определены обработчики событий (речь идет о документе, описанном в листинге 25.5) и как событие всплывает через эти элементы в различных браузерах. Расположение обработчика событий WinlE4+ Мас1Е4+ NN6+/Moz1+/Safari button form body html document window да да . да да да нет да да да нет да нет да да да да да да Несмотря на отображенные в табл. 25.1 различия, события всплывают через элементы HTML одинаковым образом. Уровень объекта самой глобальной области рассмотрения, который представлен во всех браузерах (табл. 25.1), — это document. Предотвращение всплывания событий в IE Поскольку по умолчанию события всплывают,. вам может потребоваться блокировать всплывание события к верхнему элементу иерархии. Например, вы определили событие click на уровне объекта document, связанное с группой кнопок, но любой другой объект, генерирующий событие click, тоже будет передавать его через все элементы иерархии, пока он не достигнет объекта document. Всплывающее событие и событие, переданное непосредственно обработчику, могут конфликтовать между собой. В IE4 каждое событие имеет свойство cancelBubble (отменить всплывание события). По умолчанию значение этого свойства false, что означает следующее: событие всплывает через элементы иерархии, пока не достигнет обработчика. После того как событие достигнет обработчика, свойство cancelBubble изменится на true, выполнение обработчика завершается, но событие не всплывет далее по иерархии. Для того чтобы отключить всплывание событий, добавьте приведенный ниже код в функцию обработчика. event.cancelBubble=true; Вы можете включить этот код в документ, описанный в листинге 25.5, для отключения всплывания на любом уровне. Например, если вы измените обработчик события элемента form, добавив в него код, отключающий всплывание событий, событие не сможет подняться выше элемента form (речь идет о браузере Ш4, в NN6 существуют некоторые отличия в синтаксисе — см. далее). <form onclick="alert('Event is now at the FORM element.'); event.cancelBubble=true"> 750 Часть III. Объекты документа
Предотвращение действия по умолчанию Во времена, когда события только начали добавляться в объекты, они настраивались в атрибутах дескрипторов. Методика блокирования действия по умолчанию для события заключалась в выполнении в обработчике события оператора return false. Таким образом, например, обработчик onsubmit элемента form делал невозможной отправку данных на сервер при вводе пользователем неправильных данных. Чтобы реализовать подобное поведение (особенно при настройке событий нестандартными способами, например, с помощью свойств элементов), в объект event (в Ш) было включено свойство returnValue. Если назначить этому свойству в обработчике события значение false, то действие по умолчанию для данного события будет блокировано. event.returnValue = false; Такой метод блокировки событий в Ш более совершенный, чем применение оператора return false. Переадресация событий Начиная с версии Ш5.5, появилась возможность переадресации события любому элементу HTML (правда, с некоторыми ограничениями). Эта задача выполняется с помощью метода fireEvent(), которым обладают все элементы HTML (см. главу 15). К сожалению, переадресация события с помощью этого метода не эквивалентна генерированию нового события. Но большинство свойств текущего объекта event передается новому объекту event, если в качестве параметра метода f ireEvent () указать имя оригинального объекта event. Серьезный недостаток этого метода состоит в том, что при переадресации событий теряется ссылка на объект, являющийся целью события. Свойство scrElement исходного события, содержащее ссылку на целевой объект, заменяется ссылкой на целевой объект метода f ireEvent (). Приведем пример — обработчик события содержится внутри элемента form. function buttonEvent() { event.cancelBubble=true; document.body.f i reEvent("onelick", event); } После того как всплывание событий отключается, событие не передается вверх по иерархии элементу form. Вместо этого текущий объект event переадресовывается элементу body (второй параметр метода f ireEvent ()). Когда запускается обработчик события элемента body, объект event предоставляет информацию об исходном событии (например о том, какая кнопка мыши использовалась для щелчка) и о координатах указателя. Но свойство event. scrElement указывает на объект event. После того как событие достигнет элемента, свойство event. scrElement продолжит указывать на объект event. Вы можете убедится в этом, запустив документ, описанный в листинге 25.6, в Ш5.5+. <title>Event Cancelling & Redirecting</title> <script type="text/javascript"> // отображение сообщения со сведениями об объекте события function revealEvent(elem, evt) { var msg = "Event (from " + evt.srcElement.tagName + " at "; msg += event.clientX + "," + event.clientY + ") is now at the "; Глава 25. Объекты событий 751
msg += elem + " element."; alert(msg); } function init() { document.onclick = docEverit; document.body.onelick = docBodEvent; } function docEventO { revealEvent("document", event); } function docBodEvent() { revealEvent("BODY", event); } function buttonEvent(form) { revealEvent("BUTTON", event); // отмена при установке (1Е4+) event.cancelBubble = form.bubbleCancelState.checked; // перенаправление при установке (1Е5.5+) if (form.redirect.checked) { document.body.f i reEvent("one1i ck", event); </script> </head> <body onload="init()"> <hl>Event Cancelling &amp; Redirecting</hi> <hr /> <form onclick="revealEvent('FORM', event)"> <pxbutton name="mainl" onclick= "buttonEvent (this . form) "> Button 'mainl' </buttonx/p> <pxinput type="checkbox" name="bubbleCancelState" onclick="event.cancelBubble=true" />Cancel Bubbling at BUTTON<br /> <input type="checkbox" name="redirect" onclick="event.cancelBubble=true" /> Redirect Event to BODY</p> </form> </body> </html> Листинг 25.6 является модифицированной версией листинга 25.5. В первую очередь изменения коснулись обработчиков событий каждого уровня, таким образом, теперь вы можете видеть имя дескриптора события, имеющего отношение к свойству srcElement () (как и координаты указателя мыши в событии click). Если оба флажка сняты, то событие начинает всплывать от кнопки, и элемент button является целью события в течение всего процесса всплы- вания вверх по иерархии. Если вы выставите флажок Cancel Bubbling, то событие не продвинется далее элемента button, поскольку всплывание событий отменяется. Если вы выставите флажок Redirect Event to BODY, то исходное событие будет отменено на уровне элемента button, но на уровне элемента BODY будет запущено новое событие. Заметьте, что при передаче объекта в качестве второго параметра метода revealEvent () свойства, описывающие щелчок мышью (событие click), исходного события наследуются новым событием, запущенным на уровне элемента body. Это событие начинает всплывать вверх по иерархии, начиная от элемента body. И последний вариант: если вы выставите флажок Cancel Bubbling, а флажок Redirect Event to BODY оставите неснятым, то сможете увидеть, что переадресация происходит только 752 Часть III. Объекты документа
тогда, когда заканчивает выполняться обработчик события элемента button. Исходное событие никак не проявляется, пока переадресованное событие всплывает вверх по иерархии. Как только цепочка обработки переадресованного события заканчивается, исходное событие начинает всплывать к элементу form. Обратите внимание: пока объект события "знает" свою цель, элемент button и остальные его свойства тоже остаются неизменными. Это означает, что в определенный момент времени в памяти браузера может существовать два объекта event, но только один из них является "активным". Пока передается переадресованное событие, объект window, event ссылается только на этот объект event. Захват событий в IE Браузеры Winffi5 и выше в некой степени поддерживают захват событий, который доминирует над передачей событий. Разработанный изначально для захвата событий мыши, этот механизм был реализован с помощью методов setCapture () и releseCapture () объектов всех HTML-элементов (см. главу 15). При переходе в режим захвата все события мыши передаются объекту элемента, который вызывает метод setCapture (), независимо от конечной цели события. Такое поведение события требуется реализовать при выполнении операции перетаскивания элемента (событие генерируется за пределами текущего объекта, но все же приходит в целевой объект). Как только такая обработка событий станет не нужна, выполните метод releaseCapture (). Таким образом вы вернетесь к стандартному режиму управления событиями. Передача событий в NN6+ Каждая из рассмотренных выше моделей (всплывающие события и захват событий) имеет свои преимущества. Поэтому создатели модели события W3C DOM объединили в ней обе модели передачи. Страницы с новым синтаксисом работает в старых браузерах, поскольку модель захвата событий реализована так же, как и в NN4, а всплывание — как в IE4+. Другими словами, по умолчанию событие всплывает, но в то же время вы можете включить захват события. При этом событие вначале достигнет целевого элемента, а затем всплывет в обратном направлении. По умолчанию события всплывают так же, как и в Ш4+. Для того чтобы события захватывались в W3C DOM, объекту или элементу нужно определить приемник событий. Для этого используется метод addEventlistener () (детально о его использовании рассказано в главе 15). Один из параметров метода указывает, будет ли запускаться функция-приемник события в то время, как событие всплывает или захватывается. Листинг 25.7— это простой пример, который демонстрирует, как событие щелчка (click), назначенное кнопке, может всплывать и захватываться одновременно. Большинство функций обработчика событий определено внутри функции init (). Позаимствуем код из листинга 25.5 — в нем определены обработчики событий для объектов window, document и всех объектов, расположенных внутри дескриптора body. Они автоматически назначаются приемниками событий всплывающего типа. Далее два объекта — document и form — определяются приемниками события захватываемого типа для события click. Приемник событий объекта document вызывает функции, инициализированные в обработчике событий всплывающего типа (выводимое на экран сообщение содержит символ *, чтобы напомнить вам о том, что один и тот же текст может выводиться и при захвате события, и при всплыва- нии). Для объекта form приемник событий захватываемого типа запускает одну функцию, а приемник событий всплывающего типа того же объекта запускает совсем другую функцию. Другими словами, объект содержит одну функцию для события, которое движется к целевому элементу, и совершенно другую функцию — для события, которое начинает всплывать. Многие Глава 25. Объекты событий 7S3
функции обработчика события могут динамически считывать значение свойства event Phase объекта события с целью установить, в какой фазе передачи находится событие и какой обработчик события включен. <html> <head> <title>W3C DOM Event Propagation</title> <script type="text/javascript"> function init() { // использование старого синтаксиса обработки всплывания window.onclick = winEvent; document.onclick = docEvent; document.body.onclick = docBodEvent; // включение захвата щелчков для двух объектов document.addEventListener("click", docEvent, true); document.forms[0].addEventListener("click", formCaptureEvent, true); // установка приемников события при всплывании document.forms[0].addEventListener("click", formBubbleEvent, false); } function winEvent(evt) { alert("Event is now at the window object level (" + getPhase(evt) + ") .") ; } function docEvent(evt) { alert("Event is now at the **document** object level (" ч getPhase(evt) + ")."); } function docBodEvent(evt) { alert("Event is now at the BODY level } function formCaptureEvent(evt) { alert("This alert triggered by FORM only on CAPTURE."); } function formBubbleEvent(evt) { alert("This alert triggered by FORM only on BUBBLE."); } // определение режима обработки события function getPhase(evt) { switch (evt.eventPhase) { case 1: return "CAPTURING"; break; case 2: return "AT TARGET"; break; case 3: return "BUBBLING"; break; default: return ""; (" + getPhase(evt) + } } 754 Часть III. Объекты документа
</script> </head> <body onload="init()"> <hl>W3C DOM Event Propagation</hl> <hr /> <form> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event is now at the button object level (' + getPhase(event) + ').')" /> </form> </body> </html> Если вы хотите отменить захват события после того, как он был включен, используйте метод removeEventListener () любого объекта так же, как вы использовали метод addEventListener () для добавления захвата события (см. главу 15). Поскольку в одном объекте может быть определено несколько приемников событий, точно укажите три параметра метода removeEventListener () в соответствии с используемыми параметрами метода addEventListener(). Предотвращение всплывания и захвата событий в W3C Поставим в соответствие свойству cancelBubble объекта event в ГЕ4+ метод объекта события в модели событий W3C DOM. Метод, который предотвращает передачу события, называется stop Propagation (). Этот метод может вызываться в любом месте функции- обработчика приемника событий. Текущая функция будет полностью выполняться, но событие никуда не передается. Листинг 25.8 повторяет листинг 25.7, однако в него добавлено два флажка, которые не допускают возможность остановки передачи события на уровне элемента form для захватываемых или всплывающих событий. <html> <head> <title>W3C DOM Event Propagation*:/title> <script type="text/javascript"> function init() { // старый синтаксис обработки всплывающих событий window.onclick = winEvent; document.onclick = docEvent; document.body.onelick = docBodEvent; // включение обработки щелчков для двух объектов document.addEventListener("click", docEvent, true); document.forms[0].addEventListener("click", formCaptureEvent, true); // установка приемников событий при всплывании document.forms[0].addEventListener("click", formBubbleEvent, false); } function winEvent(evt) { if (evt.target.type == "button") { alert("Event is now at the window object level (" + getPhase(evt) + ")."); } Глава 25. Объекты событий 755
} function docEvent(evt) { if (evt.target.type == "button") { alert("Event is now at' the **document** object level (" + getPhase(evt) + ")."); } } function docBodEvent(evt) { if (evt.target.type == "button") { alert("Event is now at the BODY level (" + getPhase(evt) + ")."); } } function formCaptureEvent(evt) { if (evt.target.type == "button") { alert("This alert triggered by FORM only on CAPTURE."); if (document .forms [0] . stopAHProp. checked) { evt.stopPropagation(); } function formBubbleEvent(evt) { if (evt.target.type == "button") { alert("This alert triggered by FORM only on BUBBLE."); if (document.forms[0].stopDuringBubble.checked) { evt.preventBubble(); , > } // определение режима обработки события function getPhase(evt) { switch (evt.eventPhase) { case 1: return "CAPTURING"; break; case 2: return "AT TARGET"; break; case 3: return "BUBBLING"; break; default: return ""; } } </script> </head> <body onload="init()"> <hl>W3C DOM Event Propagation</hl> <hr /> <form> <input type="checkbox" name="stopAHProp" />Stop all propagation at FORM<br /> <input type="checkbox" name="stopDuringBubble" />Prevent bubbling past FORM' <hr /> <input type="button" value="Button 'mainl'" name="mainl" onclick="alert('Event is now at the button object level (' + getPhase(event) + ').')" /> 756 Часть ///. Объекты документа
</form> </body> </html> Кроме метода stopPropagation (), в NN6+, Mozl+ и Safari поддерживается свойство cancelBubble. Предотвращение действия по умолчанию в W3C Свойство returnValue (в Ш) в W3C DOM заменено методом preventDefault (). Он выполняется в обработчике события и блокирует действие по умолчанию для события. evt.preventDefault(); Переадресация событий в W3C Существует еще один механизм отправки события объекту, который отличается от стандартного, — с помощью переадресации, принятой в IE4+. Он использует другой синтаксис. Вместо метода IE4+ f ireEvent (), в NN6 применяется метод W3C DOM dispatchEvent (). Единственный параметр этого метода — объект события, например текущего. Листинг 25.9 повторяет листинг 25.6, однако в него внесены незначительные изменения для адаптации к модели событий W3C DOM. Заметьте, что метод dispatchEvent () получает в качестве единственного параметра объект текущего события. <l}tml onclick="revealEvent ('HTML1 , event) "> <head> <title>Event Cancelling & Redirecting</title> <script type="text/javascript"> // отображение сообщения со сведениями о событии function revealEvent(elem, evt) { var msg = "Event (from " + evt.target.tagName + " at "; msg += evt.clientX + ", " + evt.clientY + '*) is now at the "; msg += elem + " element."; alert(msg); } function init() { document.onclick = docEvent; document.body.onclick = docBodEvent; } function docEvent(evt) { revealEvent("document", evt); } function docBodEvent(evt) { revealEvent("BODY", evt); } function buttonEvent(form, evt) { revealEvent("BUTTON", evt); // перенаправление при установке if (form.redirect.checked) { document.body.dispatchEvent(evt); } // отмена при установке if (form.bubbleCancelState.checked) { evt.stopPropagation(); } Глава 25. Объекты событий 757
} </script> </head> <body onload="init()"> <hl>Event Cancelling & Redirecting</hl> <hr /> <form onclick="revealEvent('FORM', event)"> <pxbutton name="mainl" onclick="buttonEvent(this.form, event) " >Button 'mainl' </buttonx/pxp>< input type="checkbox" name="bubbleCancelState" onclick="event.stopPropagationO" />Cancel Bubbling at BUTTON<br /> <input type="checkbox" name="redirect" onelick="event.stopPropagationO" /> Redirect Event to BODY</p> </form> </body> </html> Ссылки на объект события Несмотря на то, что на сегодняшний день существует три различных модели событий, есть всего два способа доступа сценария к их объектам: принятый в IE и в NN (также в W3C). Начнем с более простого способа, принятого в Ш. Ссылки на объект события в IE4+ В IE4 объект event доступен как свойство объекта window, window.event Как вы уже знаете, окно является необязательной частью ссылки, т.е. ваши сценарии будут рассматривать объект события как глобальную ссылку. event.имяСвойства Таким образом, любой оператор в обработчике событий имеет доступ к объекту события без предварительного объявления или инициализации. Ссылки на объект события в W3C Несколько сложнее ситуация с моделью событий в NN4. В некоторых случаях вы должны явным образом задать объект как параметр функции обработчика событий. В то же время существуют ситуации, когда объект автоматически назначается как параметр. Разница состоит в том, каким образом обработчик событий связывается с объектом. Если вы используете обычный способ привязки обработчика событий к объектам (с помощью свойства дескриптора элемента), то вам необходимо задать объект события как параметр event. onclick="doSomething(event)" Это единственный случай в модели NN4, когда вы увидите явную ссылку на объект event (e в нижнем регистре) как на глобальный элемент. Эта ссылка не используется ни в каком другом контексте — только как параметр функции обработчикахобытий. Если в функции используется несколько параметров, то event можно указывать любым по счету, но я предпочитаю вводить его последним. 758 Часть III. Объекты документа
onclick="doSomething(this, event)" В определении функции должен задаваться параметр-переменная, описывающий объект события. function doSomething(widget, evt) {...} Этому параметру-переменной можно давать любое имя. В настоящей книге используется и event, и evt. Однако в процессе разработки сценариев для разных браузеров избегайте применения event как имени для параметра-переменной, поскольку это название идентично имени свойства event в Ш4. Существует еще несколько способов привязки функции обработчика событий к объектам — с помощью специальных свойств и метода addEventListener () в NN6+ — в обработчиках событий можно назначить ссылки на необходимые объекты в документе, как это показано ниже. document.forms[0].someButton.onclick = doSomething; document.getElementByld("my Button").addEventListener("click", doSomething, false); Привязка событий подобным образом не допускает передачи ваших собственных параметров вызываемым функциям. Но браузеры NN4+ автоматически воспринимают ссылку на объект события (который создается в ответ на действия пользователя или системы) как параметр. Это означает, что ваши функции "получают" обработанный объект события в качестве параметра-переменной. function doSomething(evt) {...} Вспомните: объект события содержит ссылку на объект, который был целью события. Исходя из этого, вы можете управлять любыми функциями целевого объекта, например, реально существующего объекта формы, содержащего элементы управления. Листинг 25.9 показывает, каким образом объект события обрабатывается как параметр. Для всех обработчиков событий, вызванных ссылкой (как на свойство объекта обработчика событий, так и на метод addEventListener ()), у функций есть параметр, который рассматривается как ссылка на объект события в пределах данной функции. Если вам необходимо вызвать оттуда другие функции, вы можете использовать в них ссылку на объект события. Объект события сохраняет свои свойства до тех пор, пока выполняется цепочка команд, запущенная событием. Совместимость объектов event Несмотря на несовместимость способов, с помощью которых в Ш и NN объект события попадает в функцию обработчика события, вы можете легко использовать одну переменную таким образом, что оба браузера ее поймут. Например, следующий фрагмент кода используется для получения события в NN, но при этом задает и объект event в Ш. function doSomething(evt) { evt = (evt) ? evt : ((window.event) ? window.event : null); if (evt) { // специальная обработка события Если объект события представлен как параметр, он и далее будет доступен как evt; в противном случае функция определяет объект window. event и присваивает его значение переменной evt. И наконец, если браузер не находит объект event, переменной evt присваивается пустая строка. Обработка осуществляется только тогда, когда evt содержит объект события. Глава 25. Объекты событий 759
Но это только цветочки. Ягодки начнутся при более детальном рассмотрении — при попытке разобраться в свойствах объект события. Имена свойств разные в трех моделях событий. Далее в этой главе будут детально описаны все свойства событий и способы построения всех трех моделей. Чтобы помочь вам разобраться, сравним их. В табл. 25.2 представлена основная информация об объекте события, а также имена свойств и методов, использующихся в трех моделях событий. Свойство/Действие NN4 IE4+ W3C DOM Целевой объект Тип события X координата в элементе Y координата в элементе X координата в позиционируемом элементе Y координата в позиционируемом элементе X координата на странице Y координата на странице X координата в окне Y координата в окне X координата на экране Y координата на экране Кнопка мыши Клавиша на клавиатуре Нажатая клавиша <Shift> Нажатая клавиша <Alt> Нажатая клавиша <Ctrl> Предыдущий элемент Следующий элемент Отменить всплывание Предотвратить действие по умолчанию target type * * layerX layerY pageX pageY - - screenX screenY which which modifiers modifiers modifiers - - - return false srcElement type offsetX offsetY X У * * clientX clientY screenX screenY button keyCode shiftKey altKey ctrlKey fromElement toElement cancleBubble returnValue target type * * layerX layerY pageX pageY clientX clientY screenX screenY button keyCode shiftKey altKey ctrlKey relatedTarget relatedTarget preventBubble() preventDefault() * Значение может быть получено в результате преобразований других параметров Как видно из табл. 25.2, свойства объектов событий в NN6+/W3C DOM и Ш4+ во многом схожи. Это хорошая новость, особенно если учитывать то, что людей, использующих NN4, становится все меньше. Основное разногласие состоит в том, как ссылаться на элемент, который является целью события. В результате возникает необходимость задания в коде переменной, которая ссылается на необходимый элемент. Например, в предыдущую функцию можно встроить следующий фрагмент кода. var elem = (evt.target) ? evt.target : evt.srcElement; Каждая модель события имеет дополнительные уникальные свойства. Именно им посвящена вторая часть этой главы. 760 Часть III. Объекты документа
Сравнение моделей событий Несмотря на то, что модели объектов событий существенно отличатся в обработке свойств, приспособить разные браузеры к управлению событиями довольно просто. В этом разделе рассматриваются два сценария, которые демонстрируют основные свойства событий. Первый сценарий определяет, нажата ли во время возникновения события клавиша- модификатор (и если да, то какая). Второй сценарий извлекает коды для обеих кнопок мыши и клавиш клавиатуры. Оба сценария работают со всеми браузерами, поддерживающими объекты событий, включая NN4. Если ваша аудитория больше не использует NN4, то вы можете удалить из сценария часть кода, выполняемого только в нем. Межплатформенное определение клавиш-модификаторов Листинг 25.10 демонстрирует технику определения клавиши-модификатора, которая нажата во время наступления события. Детально свойства объекта события (modifiers и alt Key) будут рассмотрены в этой главе несколько позже. Чтобы увидеть эту страницу в действии, щелкните на ссылке, введите какую-либо информацию в текстовом поле и щелкните кнопкой мыши, нажав комбинацию клавиш-модификаторов. Внизу представлен набор четырех флажков, соответствующих четырем клавишам-модификаторам. После того, как вы щелкнете мышкой и введете в поле данные при нажатом модификаторе, соответствующий флажок обозначит это. Листинг 25,10. Изменение событий € помвщыо <html> <head> <title>Event Modifiers</title> <script type="text/javascript"> function checkMods(evt) { evt = (evt) ? evt : ((window.event) ? window.event : null) if (evt) { var elem = (evt.target) ? evt.target : evt.srcElement; var form = document.output; if (evt.modifiers) { form.modifier[0].checked = evt.modifiers & Event.ALT_MASK; • form.modifier[1].checked = evt.modifiers & Event.CONTROL_MASK; form.modifier[2].checked = evt.modifiers & Event.SHIFT_MASK; form.modifier[3].checked * evt.modifiers & Event.META_MASK; } else { form.modifier[0].checked = evt.altKey; form.modifier[1].checked = evt.ctrlKey; form.modifier[2] .checked = evt.shiftKey; form.modifier[3].checked = false; } } Глава 25. Объекты событий 761
return false; } </script> </head> <body> <hl>Event Modifiers</hl> <hr /> <p>Hold one or more modifier keys and click on <a href="javascript:void(0)" onmousedown="return checkMods(event)">this link</a> to see .which keys you are holding.</p> <form name="output"> <p>Enter some text with uppercase and lowercase letters: <input type="text" size="40" onkeyup="checkMods(event)" /> </p> <pxinput type= "button" value= "Click Here With Modifier Keys" onelick="checkMods(event)" /></p> <pxinput type="checkbox" name= "modifier" />Alt <input type = "checkbox" name="modifier" />Control <input type="checkbox" name="modifier" />Shift <input type="checkbox" name="modifier" />Meta</p> </form> </body> </html> Разветвление задается только в функции checkMods (), т.к. все три обработчика событий совместно используют только ее одну. Заметьте также, что при ветвлении предпочтение отдается определению объекта, а не navigator.userAgent. В данном случае этот метод предпочтительнее, поскольку его функционирование основывается на существовании определенных объектов и свойств. Для NN4 объект события обрабатывается как параметр, свойство modifier которого остается постоянным для каждой клавиши-модификатора. Для Ш4+ и NN6 сценарий проверяет свойства объекта события для каждого из трех модификаторов. Межплатформенное определение клавиш Чтобы продемонстрировать управление клавиатурой в обоих браузерах, мы представили листинг 25.11, который определяет тип клавиши, введенной в текстовом поле, а также кнопку мыши, используемую для щелчка на кнопке. Как и в листинге 25.10, NN4 по поведению существенно отличается от ГЕ4+ и NN6+. Но так или иначе, NN6 все еще поддерживает синтаксис NN4, т.е. в нем вы можете использовать как старый, так новый синтаксис. В то время как NN4 комбинирует щелчок мыши и нажатие клавиши в одном свойстве объекта события, новые браузеры используют абсолютно разные свойства для этих значений. Листинг 25.11 написан таким образом, что NN6+ следует синтаксису NN4, но если этот синтаксис исчезнет в будущих версиях NN, браузер без всяких последствий будет использовать новый. <html> <head> <title>Button and Key Properties</title> <script type="text/javascript"> 762 Часть III. Объекты документа
function checkWhich(evt) { evt = (evt) ? evt : ((window.event) ? window.event : null); if (evt) { var thingPressed = ""; var elem = (evt.target) ? evt.target : evt.srcElement; if (elem.type == "textarea") { thingPressed = (evt.charCode) ? evt.charCode : ((evt.which) ? evt.which : evt.keyCode); } else if (elem.type == "button") { thingPressed = (typeof evt.button != "undefined") ? evt.button : ((typeof evt.which != "undefined") ? evt.which : "n/a"); } window.status = thingPressed; } return false; } </script> </head> <body> <hl>Button and Key Properties</hl> (results in the status bar) <hr /> <form> <p>Mouse down atop this <input type="button" value="Button" onmousedown="checkWhich(event)" /> with either mouse button (if you have more than one).</p> <p>Enter some text with uppercase and lowercase letters: <textarea cols="40" rows="4" onkeypress = "checkWhich(event)" wrap="virtual"></textarea> </p> </form> </body> ' </html> Коды клавиш клавиатуры соответствуют ASCII-значениям символов. Если вам необходимы коды других клавиш, обработчики событий onkeydown и onkeyup предоставят вам Unicode-значения любых клавиш клавиатуры. Подробно свойство keyCode описывается далее в этой главе. Типы событий Браузеры до версии 4 не поддерживали возможности управления объектом события; несмотря на это, мы рассмотрим свойство type. Объектные модели в IE4+ и NN6+/W3C предоставляют обработчик событий практически для каждого элемента HTML, таким образом возможно, например, назначить обработчик событий onclick не только для кнопки, на которой можно щелкнуть, но и для элемента р или произвольных span-элементов. К современным версиям браузеров мы скоро вернемся. Если вам необходимо создать сценарий, который будет выполняться в старых браузерах, определите, какие их элементы и какими обработчиками событий поддерживаются. Эта информация поможет определить общие свойства обработчиков событий, которые можно воплотить в ваших страницах, рассчитанных на те браузеры, с помощью которых, по вашим прогнозам, будут просматриваться эти страницы. Глава 25. Объекты событий 763
Старые версии браузеров Создатели старых браузеров стремились к уменьшению количества обработчиков событий, предоставляя их только тем элементам, которые, по их мнению, должны ими обладать. При этом увеличение количества объектов требовало все большего количества обработчиков. Прежде чем это было воплощено в Ш4+ и NN6+, разработчики попытались узнать пределы объектного моделирования. Табл. 25.3 показывает доступные для объектов обработчики событий в трех поколениях браузеров. Каждый столбец представляет версию браузера, в которой встречается определенный тип события. Например, объект window оснащен четырьмя типами событий, с появлением NN4 к ним было добавлено еще три. С другой стороны, объект area был впервые представлен в NN3, именно в нем для этого объекта впервые был представлен собственный обработчик события. объект NN2/IE3 NN3 NN4 window layer link area image form blur focus load unload click mouseover submit text, textarea, password blur ♦ allbuttons change focus select click mouseout mouseout mouseover abort error load reset dragdrop move resize blur focus load mouseout mouseover mouseup dblclick mousedown onmouseup click keydown keypress keyup mousedown mouseup За исключением объекта layer в NN4, все объекты, перечисленные в табл. 25.3, сохранились в более новых версиях браузеров — вы с уверенностью можете использовать их обработчики событий. Также имейте в виду, что из всех браузеров, перечисленных в таблице, только NN4 имеет все объекты событий, используемые в сценариях. 764 Часть III. Объект документа
Типы событий в IE4+ и NN6+/W3C К настоящему моменту вы уже должны были познакомиться с обработчиками ррбытий, определенных для наиболее часто используемых элементов. Этот список огромен. Каждый браузер — IE4, IE5, Ш5.5/6 — имеет уникальный список типов поддерживаемых событий. Если вы создаете страницы как для ГЕ4+, так и для NN6+/W3C, то вам необходимо знать их общие типы событий. Типы событий в NN6+/Mozl+/Safari базируются, в основном, на спецификации W3C DOM второго уровня; они включают в себя события клавиатуры, которые формально не являются частью этой спецификации. Табл. 25.4 представляет список совместных типов событий для современных браузеров, а также объектов, которые их поддерживают. Как видите, многие типы событий и соответствующих объектов так и не изменились. Наиболее существенные перемены заключаются в том, что события мыши стали доступны для любого отображаемого элемента. Табл. 25.4 имеет небольшой размер, поэтому она вместила в себя не полный список событий Ш (таким образом, она является только тем минимумом, который вам необходимо знать для управления браузерами). Тйбтща25.4. Тип события Элементы abort blur change click error focus keydown keypress keyup load mousedown mousemove mouseout mouseover mouseup preset resize scroll select submit unload object window, button, text, password, label, select, textarea text, password, select, textarea Bee window, frameset, object window, button, text, password, label, select, textarea text, password, textarea text, password, textarea text, password, textarea window, frameset, object Bee Bee Bee Bee Bee form window window text, password, textarea form window, frameset Глава 25. Объекты событий 765
Объект события в NN4 Свойства Методы Обработчики событий data layerX layerY modifiers pageX pageY screenX screenY target type which Синтаксис Доступ к свойствам объекта события в NN4. объектСобытия.свойство Совместимость: WinlE-, Macffi-, NN4+, Moz-, Safari- Описание объекта Детальные сведения об этом объекте были приведены при рассмотрении сравнительных характеристик объектов событий. Однако отметим, что уменьшение популярности NN4 делает эти объекты и их свойства менее важными. Свойства data Значение: массив строк Только для чтения Совместимость: WinlE-, Macffi-, NN4+, Moz-, Safari- Событие dragdrop содержит информацию о строке URL, которая помещается в окно браузера. Поскольку в окне браузера могут размещаться различные объекты (в некоторых операционных системах это могут быть значки, представляющие URL), значение этого свойства— совокупность строк, где каждая строка содержит один URL (включая file:// — URL для файлов локального компьютера). Учитывая то, что такая информация, как URL, является частной, она применяется только для защищенных сценариев — только тогда, когда пользователь дает разрешение на чтение данных браузера. Если вы хотите, чтобы ваш сценарий получал эту информацию, не загружая URL в окне, обработчик событий должен вернуть значение false. Пример На странице листинга 25.12 содержится текстовое поле, в котором отображаются URL- адреса перетаскиваемых элементов. Чтобы запустить этот защищенный сценарий, вам потребуется настроить доверителя (см. главу 46). 766 Насть III. Объекты документа
Загрузите страницу и перетащите в текстовое поле любой ярлык с рабочего стола, который представляет файлы, папки и приложения. Выделите и перетащите несколько элементов сразу. Поскольку обработчик ondragdrop выполняет оператор return false, файлы в окно браузера не загружаются. Если вы хотите просматривать URL-адреса и загружать только некоторые из них, то создайте конструкцию if. . .else, возвращающую в обработчик значение true или false. Выполнение оператора return true приводит к обработке события dragdrop стандартным образом — после завершения работы обработчика события. <html> <head> <title>Drag and Drop</title> <script type=ntext/javascript"> function handleDrag(evt) { netscape.security.PrivilegeManager. erfablePrivilege("UniversalBrowserRead"); var URLArray = evt.data; netscape.security.PrivilegeManager. disablePrivilege("UniversalBrowserRead"); if (URLArray) { document.forms[0].output.value = URLArray.join("\n"); } else { document.forms[0].output.value = "Nothing found."; } return false; } </script> </head> <body ondragdrop="return handleDrag(event)"> <b>Drag a URL to this window (NN4 only).</b> <hr /> <form> URLs:<br /> <textarea name= "output" cols="70" rows="4"x/textareaxbr /> <input type="reset" /> </form> </body> </html> layerX layerY pageX pageY screenX screenY Значение: целое Только для чтения Совместимость: WinlE-, МасШ-, NN4+, Moz-, Safari- Для многих (но не всех) связанных с мышью событий в обработчике NN4 предоставляется достаточное количество информации о координатах указателя во время наступления события. Глава 25. Объекты событий 767
В усложненном варианте щелчок мышью на объекте слоя имеет три четко определенных пары координат: слоя, страницы и всего экрана. Бели для документа не заданы слои, то системы координат страницы и слоя совпадают. Заметьте, что эти значения, по сути, являются физическими; сами по себе они никакой информации об объекте не несут (информация содержится в свойстве eventObject. target). Указанные свойства координат указателя устанавливаются только для специфических событий. В случае объекта ссылки событие click и четыре остальных события мыши отправляют эти значения объекту события. Для кнопок только события мыши (mousedown и mouseup) получают эти координаты. Каждый из двух типов событий окна (move и resize) использует одну из этих пар свойств, чтобы передать результаты действий пользователя. Например, когда пользователь изменяет размер окна, событие resize использует свойства объектСобытия. layerX и объектСобытия. layerY, в которых содержатся значения размеров окна браузера (если хотите, можете также использовать свойства объектСобытия. width и объектСобытия. height). Когда пользователь перемещает окно, экранные координаты верхнего левого угла окна отображаются в свойствах объектСобытия. screenX и объектСобытия. screenY. Пример Ознакомиться с координатной системой и связанными с ней свойствами вы можете, изучив листинг 25.13. В верхней части страницы вы найдете три поля для пар свойств 1 ayerX-layerY, pageX-pageY и screenX-screenY. Два объекта, на которых можно щелкнуть (кнопка и изображение), добавлены, чтобы показать разницу между объектами на слое и объектами вне слоя. Объект за пределами слоя располагается в той же координатной системе, что и сам слой, а также остальные объекты страницы. Два не упомянутых выше поля отображают координаты перемещения и изменения размера окна. Если вы максимально увеличите окно браузера в Windows, то его левый верхний угол выйдет за края экрана на четыре пикселя в каждом направлении. Именно поэтому свойства screenX и screenY принимают значения -4. <html> <head> <title>X and Y Event Properties</title> <script type="text/javascript"> function checkCoords(evt) { var form = document.forms[0] ; form.layerCoords.value = evt.layerX + "," + evt.layerY; form.pageCoords.value = evt.pageX + "," + evt.pageY; form.screenCoords.value = evt.screenX + "," + evt.screenY; return false; } function checkSize(evt) { document.forms[0].resizeCoords.value = evt.layerX + ", " + evt.layerY; } function checkLoc(evt) { document.forms[0].moveCoords.value = evt.screenX + "," + evt.screenY; } </script> </head> 788 Часть III. Объекты документа
<body onresize="checkSize(event)" onmove="checkLoc(event)"> <hl>X and Y Event Properties (NN4)</hl> <hr /> <p>Click on the button and in the layer/image to see the coordinate values for the event object.</p> <form name="output"> <table> <tr> <td colspan="2n>Mouse Event Coordinates:</td> </tr> <tr> <td align="right">layerX, layerY:</td> <tdxinput type="text" name=" layer Coords" size="10" /></td> </tr> <tr> <td align="right">pageX, pageY:</td> <tdxinput type="text" name="pageCoords" size="lQ" /></td> </tr> <tr> <td align="right">screenX, screenY:</td> <td><input type="text" name="screenCoords" size="10" /></td> </tr> <tr> <td align="right"><input type="button" value="Click Here" onmousedown = "checkCoords(event)" /></td> </tr> <tr> <td colspan="2"xhr /></td> </tr> <tr> <td colspah="2">Window Resize Coordinates:</td> </tr> <tr> <td align="right">layerX, layerY:</td> <tdxinput type="text" name="resizeCoords" size="10" /></td> </tr> <tr> <td colspan="2"xhr /x/td> </tr> <tr> <td colspan="2">Window Move Coordinates:</td> </tr> <tr> <td align="right">screenX, screenY:</td> <tdxinput type="text" name="moveCoords" size="10" /></td> </tr> </table> </form> <layer name="display" bgcolor="coral" top="140" left="300" height="250" width="330"> <a href="javascript:void(0)" onclick="return checkCoords (event) "ximg alt="image" src="nile.gif " Глава 25. Объекты событий 769
width="320" height="240" border="0" /></a> </layer> </body> </html> См. также: методы перемещения и изменения размера объектов layer и window. modifiers Значение: константа Только для чтения Совместимость: Winffi-, MacIE-, NN4+, Moz-, Safari- Свойство modifier в NN4 обращается к клавишам-модификаторам, которые могут быть нажаты во время щелчка мышью или работы с клавиатурой. К клавишам-модификаторам относятся <Alt> (<Option> на клавиатуре Macintosh), <Ctrl>, <Shift>, а также мета-клавиша (например, клавиша <Command> на клавиатуре Macintosh). Вы можете использовать это свойство, чтобы определить, нажимались ли какие-либо клавиши-модификаторы во время выполнения события. Значения для этих клавиш являются целочисленными величинами, разработанными таким образом, что любая комбинация клавиш имеет уникальное значение. К счастью, вам не обязательно знать что-либо об этих значениях, так как модель события поддерживает некоторые константы обычного языка (свойства глобального объекта Event всегда доступны), которые сценарий может использовать в качестве значения свойства обрабатываемого объекта. Константа состоит из имени клавиши (в верхнем регистре), за которым следует символ подчеркивания и слово MASK (все в верхнем регистре). Например, если клавиша <АК> нажата отдельно или в сочетании с другой клавишей-модификатором, то вы можете использовать логический оператор AND (&) и константу Event .ALT_MASK, чтобы узнать, присутствует ли клавиша <Alt> в значении свойства. function handleMyEvent(eyt) { if (evt.modifiers & Event.ALT_MASK) { //Установка обработчика событий для клавиши <Alt> } } Модификаторы доступны не в каждом событии. Вы можете привязать их к событиям mousedown и mouseup для кнопок и ссылок. Щелчок мыши позволяет привязать модификаторы только к объектам кнопок. События клавиатуры в текстовых объектах также включают эти модификаторы. Но будьте аккуратны с комбинациями клавиш (<Ctrl>+<Q> для выхода) — они не воспринимаются моделями событий JavaScript, так как зарезервированы для использования в качестве команд браузера. Пример Обратитесь к листингу 25.10 выше в этой главе, в котором описано, как клавиши-модификаторы управляются в NN4. target Значение: ссылка на объект Только для чтения Совместимость: Winffi-, MacIE-, NN4+, Moz-, Safari- Каждый объект имеет свойство, содержащее ссылку на объект, на котором щелкнули мышью, что-то ввели или совершили другое действие. Обычно это свойство проверяется, когда вы задаете на странице обработку событий на уровне окна, документа или слоя, как 770 Часть III. Объекты документа
описывалось выше в этой главе. Свойство target позволяет вам точнее задать расположение события, сразу проводя обработку для всех его типов. Имея ссылку на объект target, ваш сценарий может непосредственно извлечь и/или установить свойства этого объекта. type Значение: строка Только для чтения Совместимость: Winffi-, МасШ-, NN4+, Moz-, Safari- Тип объекта события — это имя события, которое сгенерировало объект события. Имя события — то же, что и у обработчика, только без приставки on. Таким образом, если обработчик события onclick кнопки запускается в результате щелчка, то он соответствует событию click (все в нижнем регистре). Если вы создаете многоцелевую функцию для обработки событий, то можете воспользоваться свойством объектСобытия. type, чтобы помочь функции решить, каким образом обрабатывать событие. Эту задачу выполняет управляющая структура swi tch (см. главу 31). \ which Значение: целое Только для чтения Совместимость: Winffi-, Macffi-, NN4+, Moz-, Safari- Значение свойства which зависит от типа события: индикатор кнопки мыши для событий мыши и символ клавиши для событий клавиатуры. Для событий мыши свойство объектСобытия .'which содержит следующие значения: 1 — для левой (основной) кнопки мыши и 3 — для правой (дополнительной) кнопки мыши. Большинство компьютеров Macintosh оборудовано однокнопочной мышью — избегайте разработки страниц, управляемых второй кнопкой мыши. Даже в Windows и других платформах необходимо запрограммировать обработчик событий onmousedown объекта на задание оператора return false для дополнительной кнопки мыши, чтобы на экране не появлялось всплывающее меню браузера. События клавиатуры генерируют код ISO-Latin нажатой клавиши. Это целое значение в диапазоне от 0 до 255. Если сценарий требует просмотреть истинный символ, который был введен, а не код клавиши, можно воспользоваться методом строка. f romCharCode () (см. главу 27), чтобы провести обратное преобразование. Если у вас возникают трудности с получением кода из событий клавиатуры, попробуйте использовать обработчики событий onkeyup и onkeydown вместо onkeypress. В любом случае, функциональные клавиши не имеют кодов символов. Пример Пример использования свойства объектСобытия. which приведен в листинге 25.10. Объект события в IE4+ Свойства Методы Обработчики событий altKey altLeft behaviorCookie behaviorPart bookmarks Глава 25. Объекты событий 771
Окончание таблицы Свойства Методы Обработчики событий boundElements button cancelBubble clientX clientY contentOverflow ctrlKey ctrlLeft dataFld dataTransfer fromElement keyCode nextPage offsetX offsetY propertyName , qualifier reason recordset repeat returnValue saveType screenX screenY shiftKey shiftLeft srcElement srcFilter srcUrn toElement type x У Синтаксис Доступ к свойствам объекта event в Ш4+. [window. ] event. свойство Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Описание объекта Объект event является свойством объекта window в Ш4+. Основные операции с ним описывались выше в этой главе. , 772 Часть III. Объекты документа
С объектом event можно ознакомиться с помощью приложения The Evaluator (см. главу 13). Если вы введете event в нижнем текстовом поле, то сможете исследовать свойства объекта event для событий, которые запускают функцию, отображающую свойства объекта event. Нажав клавишу <Enter>, вы увидите свойства события keypress, которое запустило внутренний сценарий. Щелкните мышью на кнопке List Properties, чтобы увидеть свойства события click, генерируемого кнопкой. Щелкните мышью одновременно с нажатием клавиши-модификатора, чтобы узнать, как это влияет на некоторые свойства. Просматривая свойства объекта event, обратите внимание на таблицу совместимости для каждого свойства. Список свойств для этого объекта значительно увеличился в результате совершенствования модели событий в Г£4+. Он также расширился в результате развития объектной модели ГЕ4+. Преимущественно свойства, перечисленные в этом списке, имеют статус Только для чтения. Но для IE5+ они представлены как Чтение/Запись, если были созданы вручную с помощью таких методов ГЕ5+, как document .createEventObject (). Объекты событий, которые были созданы пользователем или системой, имеют всего несколько свойств, что не позволяет вашим сценариям изменить действия пользователя. Свойства altKey ctrlKey shiftKey Значение: булево Только для чтения Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Когда объект event создается в ответ на действия пользователя или системы, то эти три свойства определяют, нажаты ли клавиши-модификаторы в момент выполнения действия (например, ^ЫЛ+щелчок мышьк»). Если клавиша нажата, свойству присваивается значение true, если нет — false. Обычно эти выражения используются в составе условной конструкции if. Так как это булевы величины, в одном условии можно комбинировать различные свойства. Например, в той части функции, которая будет выполняться только тогда, когда во время выполнения события нажаты клавиши <Ctrl> и <Shift>, условие должно выглядеть следующим образом. if (event.shiftKey && event.ctrlKey) { // выполняемые функции } Также можно создать более простую запись функции, которая будет выполняться по- другому, если нажата одна из клавиш-модификаторов. if (event.shiftKey || event.ctrlKey || event.shiftKey) { // выполняемые функции ) Суть представленных выше выражений — предложить пользователю упрощенное решение, но не заставлять его при этом запоминать специфические комбинации клавиш- модификаторов. Пример В листинге 25.10 значения этих трех свойств используются для установки свойств checked соответствующих типов событий. См. также: свойства altLef t, ctrlLef t, shif tLef t. Глава 25. Объекты событий 773
altLeft ctrlLeft shiftLeft Значение: булево Только для чтения Совместимость: Winffi5.5, МасШ-, NN-, Moz-, Safari- Некоторые версии Windows (особенно Windows NT и Windows 2000) во время использования Ш5.5+ позволяют модифицировать события только с помощью левых клавиш <Alt>, <Ctrl>, <Shift>. Чтобы эти модификаторы были восприняты объектом event, должен быть активным сам документ (тело), а не элемент управления формы. Если свойство для левой клавиши возвращает значение false, а для обоих— true, то сценарий "знает", что во время генерирования события нажимается правая клавиша-модификатор. См. также: свойства altKey, ctrlKey, shif tKey. behaviorCookie behaviorPart Значение: целочисленное Только для чтения Совместимость: WinIE6+, Macffi-, NN-, Moz-, Safari- Эти два свойства относятся к технологии Windows, которую Microsoft называет поведением отображения. В отличие от поведений, описанных при обсуждении метода addBehavior () (см. главу 15), поведения отображения написаны на C++; они предоставляют возможность рисования на ваших Web-страницах. Подробно о них можно узнать в документе Implementing Rendering Behaviors на узле http: //msdn .microsoft. com/workshop/ browser/editing/imprendbehav.asp. bookmarks boundElements dataField qualifier reason recordset Значение: см. текст Только для чтения Совместимость: Winffi6+, Macffi-, NN-, Moz-, Safari- Эта группа свойств объектов event связана с использованием технологии Data Binding (связывание данных) в IE4+ для Windows. Детальные сведения о связывании данных мы приводить не будем, но табл. 25.5 предоставляет информацию об этом объекте в контексте рассматриваемого в этой книге материала (большая часть терминологии используется в Data Binding, но не относится к сценариям). Подробные сведения о ней вы можете узнать на узле ActiveX Data Objects (ADO) по адресу http: //msdn. microsoft. com/workshop/. button Значение: целочисленное Только для чтения Совместимость: WinTE4+, MacIE4+, NN6+, Moz-, Safari- 774 Часть III. Объекты документа
Свойство Значение Впервые параметра представлен Описание bookmarks Массив IE4 boundElements Массив IE5 dataFld Строчный IE5 qualifier Строчный IE5 reason recordset Целый 1Й Объект IE4 Массив закладок ADO (сохраненных позиций) для записей, которые связаны с объектом, получившим событие Массив ссылок на все элементы, которые связаны с одним набором данных, затронутым текущим событием Имя столбца с данными, который связан с ячейкой таблицы, получившей событие ceiichange Имя члена данных, который связан с источником данных, получающего событие. Доступно только в том случае, если объект - источник данных (data source object — DSO) - разрешает существование членов данных со многими именами или если классификатор был явным образом установлен с помощью атрибута datasrc элемента. ВIE5 доступно для чтения и записи Устанавливается только из события ondatasetcompiete; представляет код результата загрузки данных (0=успешный; 1=передача прервана; 2=другая ошибка) Ссылка на текущую запись в источнике данных Свойство button показывает, какая кнопка или кнопки были нажаты для активизации события мыши. Если не была нажата ни одна кнопка мыши, то значение параметра равно 0. Целые числа от 1 до 7 определяют нажатые кнопки или комбинации кнопок (в том числе и для трехкнопочной мыши) в случае, если та распознается операционной системой. Целые значения этого параметра соотносятся с кнопками в соответствии со следующей схемой. Значение Описание Кнопки не нажаты Левая (основная кнопка) Правая кнопка Одновременно левая и правая кнопки Средняя кнопка Левая и средняя Правая и средняя Левая, средняя и правая Все кнопки мыши, за исключением основной, проще просматривать в событиях mouseup, чем в onclick. Помните: когда пользователь нажимает несколько кнопок, каждая запускает событие mousedown. Таким образом, если пользователь сначала нажимает левую кнопку, запускается событие со значением свойства event. button, равным 1. Затем, когда нажимается другая кнопка, событие mousedown запускается снова, но на этот раз со значением event .button, равным 3. Если ваш сценарий подразумевает выполнение особых действий в ответ на нажатие обоих клавиш, он должен игнорировать нажатие отдельных кнопок, т.к. событие одной кнопки запустит свой процесс, который будет мешать правильной работе сценария. Глава 25. Объекты событий 775
Внимание! При написании сценариев со свойством event .button для обоих браузеров NN6+ и ВЕ4+ примите к сведению, что модель событий W3C DOM определяет иные значения для отдельно используемых кнопок мыши (0, 1 и 2 для, соответственно, левой, средней и правой) и никаких значений для комбинаций кнопок. Пример В листинге 25.11 свойство event .button используется для управления строкой состояния. Проверьте кнопки на странице, щелкнув на них разными кнопками мыши. Затем протестируйте комбинации кнопок — результаты можно увидеть в строке состояния. caneelBubble Значение: булево Только для чтения Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство cancelBubble (которое звучит, скорее, как метод) определяет, будет ли текущий объект события всплывать выше по иерархии документа. По умолчанию значение этого свойства false — если событие может всплывать, то сделает это автоматически. Чтобы предотвратить всплывание текущего события, установите в функции обработчика событий параметр в значение true. Также можно отменить всплывание непосредственно в атрибутах обработчика событий. onelick="doButtonclick(this); event.cancelBubble = true" Отмена всплывания применяется только для текущего события. У каждого события, запущенного позже, это свойство будет включено. Пример В листинге 25.6 описано свойство cancelBubble. Несмотря на то, что некоторые части листинга предназначены для выполнения в Ш5.5+, это свойства прекрасно поддерживается и в IE4. См. также: свойство returnValue clientX clientY offsetX offsetY screenX screenY x У Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ В IE4 объект event предоставляет четыре набора координат: элемента, родительского элемента целевого элемента, доступной для обозрения части окна браузера и всего экрана. К несчастью, некоторые свойства, отвечающие за эти наборы координат, могут возвращать неверные значения, о чем и пойдет речь далее. Заметьте, что свойства не предопределяют явной позиции события по отношению к странице, если пользователь прокручивает документ. Начнем с самого первого набора координат — для элемента, который является целью события, — свойства offsetX, offsetY представляют координаты целевого элемента 776 Часть III. Объекты документа
в пикселях. Пользуясь ими, можно определить место щелчка на изображении, в зависимости от того, каким образом оно присоединено: в элементе body или div. Ш6 для Windows в большинстве случаев возвращает корректные значения свойств. Но для некоторых дочерних объектов элемента body вертикальное (у) значение может зависеть от размеров окна, а не самого элемента. Пример вы можете увидеть при изучении листинга 25.14, щелкнув мышью на элементах hi или р вначале страницы. Эта проблема не затронула IE для Мае, но в данной версии браузера существует другая проблема: если страница прокручивается за пределы своих исходных размеров, то в качестве значений прокрутки используются значения clientX и clientY. Необходимо принять в расчет эту ошибку несовместимости при задании координат щелчка для объекта на странице, которую можно прокручивать. Исправлять эту ошибку необходимо только для Мае, так как в Windows она отсутствует. Свойства х и у в Ш5+ для Windows возвращают координаты смещения относительно родительского элемента (элемента, который можно обнаружить с помощью свойства of f set Parent). Для большинства элементов без строго заданного расположения эти значения соответствуют значениям свойств clientX и clientY, поскольку смещение элемента относительно его родительского элемента — body — нулевое. Примите к сведению также, что в WinIE4 и МасШ5 свойства х и у допускают смещение только относительно body. Даже в Ш5+ для Windows в некоторых случаях это свойство может выдавать ложные значения. В целом этими двумя свойствами пользоваться не стоит. Следующий набор координат, clientX и clientY, относится к видимой части окна браузера. Если документ прокручивается до конца в пределах окна (или не прокручивается вообще), эти координаты будут такими же, что и у всей страницы. Но из-за того, что страница может прокручиваться "за" видимую часть окна, координаты страницы могут изменяться. В Ш для Windows можно регистрировать события мыши на расстоянии двух пикселей за пределами элемента body. Таким образом, в WinlE щелчок мышью на фоне элемента body запустит событие для элемента body, но значения clientX/clientY будут на два пикселя больше, чем of f setX/of f setY (в Macffi они равны). Несмотря на эти небольшие расхождения, на описываемые свойства можно положиться, задавая координаты для события, которое определяется для позиционируемого элемента. Но лучше, чтобы эти координаты были привязаны ко всему доступному для обзора окну, чем просто к позиционируемому содержимому. Обычно очень важно при работе с координатами принять во внимание возможность прокрутки. Не создав для пользователя окна с фиксированными размерами, вы не сможете угадать, как это окно будет заполнено данными. Если вы собираетесь обрабатывать щелчок мышью на специальном месте страницы, то необходимо принять во внимание возможность прокрутки. Фактор прокрутки может быть получен из свойств document. body. scrollLef t и document .body. scrollTop. Работая со свойствами clientX и clientY, убедитесь, добавлены ли соответствующие координаты прокрутки. var coordX = event.clientX + document.body.scrollLeft; var coordY = event.clientY + document.body.scrollTop; Наконец, свойства screenX, screenY возвращают координаты места события в пикселях относительно всего экрана. Это свойство может быть полезно, если IE предоставляет дополнительные свойства размеров окна. По причине того, что события мыши запускаются только в том случае, когда указатель находится в пределах окна браузера, вы не получите значения за пределами обозначенной области. Если это объяснение вам кажется несколько туманным, не отчаивайтесь. Добавьте в любой программный продукт несколько ошибок — и вы получите полнейшую неразбериху. Но задумайтесь над тем, как вы можете использовать координаты места событий в сценариях. Как правило, вам необходимо знать одну из двух координат события: в самом элементе и на странице. Воспользуйтесь of f setX/of f setY в первом случае и clientX/clientY — во втором. Глава 25. Объекты событий 777
Как известно, свойства координат используются, в основном, для событий мыши. Существует небольшая уловка, позволяющая определить, каким образом пользователь изменил размер окна: с помощью кнопки в строке заголовка окна или потянув за правый нижний угол окна. Координаты указателя в момент возникновения события мыши записываются в объект event для события resize. При использовании кнопки разворачивания окна в строке заголовка свойство clientY принимает отрицательное значение (кнопка располагается над рабочей областью окна), a clientX — имеет значение на 45 пикселей больше исходной ширины окна (document.body.clientwidth). Значения свойств, конечно же, назначаются после изменения размера окна. Пример В листинге 25.14 приведен пример чтения всех координатных" свойств: clientX, clientY, of f setX, of f setY, screenX, screenY, x, у. Реакция на все события задается в обработчике onmousedown. Пощелкайте на странице, чтобы увидеть результат выполнения обработчика. Изображение располагается в элементе div, чтобы продемонстрировать, что же происходит с отдельными свойствами, когда событие нацелено на позиционируемый элемент. <html> <head> <title>X and Y Event Properties (IE4+ Syntax)</title> <script type="text/javascript"> function checkCoords(evt) { evt = (evt) ? evt : ((window.event) ? window.event : null); if (evt) { var elem = (evt.target) ? evt.target : evt.srcElement; var form = document.forms[0]; form.srcElemTag.value = "<" + elem.tagName + ">"; form.clientCoords.value = evt.clientX + "," + evt.clientY; if (typeof document.body.scrollLeft != "undefined") { form.pageCoords.value = (evt.clientX + document .body, s его ULeft) + ", " + (evt.clientY + document.body.scrollTop); } form.offsetCoords.value = evt.offsetx + "," + evt.offsetY; form.screenCoords.value = 'evt.screenX + "," + evt.screenY; form.xyCoords.value = evt .x + "," + evt.y; if (elem.offsetParent) { form.parElem.value = "<" + elem.offsetParent.tagName + ">"; } return false; function handleSize(evt) { evt = (evt) ? evt : ((window.event) ? window.event : null); if (evt) { document.forms [0] .resizeCoords.value = evt.clientX + "," + evt.clientY; </s'cript> </head> <body onmousedown=ncheckCoords(event)" onresize = 778 Часть III. Объекты документа
"handleSize(event)"> <hl>X and Y Event Properties (IE4+ Syntax)</hl> <hr /> <p>Click on any element to see the coordinate values for the event object-</p> <form name="output"> <table> <tr> <td colspan="2">IE Mouse Event Coordinates:</td> </tr> <tr> <td align="right">srcElement:</td> <tdxinput type="text" name=MsrcElemTag" size="10" /> </td> </tr> <tr> <td align="right">clientX, clientY:</td> <td><input type="text" name="clientCoords" size="10" /></td> <td align="right">...With scrolling:</td> <td><input type="text" name="pageCoords" size="10" /></td> </tr> <tr> <td align="right">offsetX, offsetY:</td> <td><input type="text" name="offsetCoords" size="10" /></td> </tr> <tr> <td align="right">screenX, screenY:</td> <td><input type=f,text" name="screenCoords" size="10" /></td> </tr> <tr> <td align="right">x, y:</td> <tdxinput type="text" name ="xyCoords" size="10" /> </td> <td align="right">...Relative to:</td> <tdxinput type="text" name="parElem" size^'lO1' /> </td> </tr> <tr> <td align="right"><input type="button" value="Click Here" /></td> </tr> <tr> <td colspan="2"xhr /x/td> </tr> <tr> <td'colspan="2">Window Resize Coordinates:</td> </tr> <tr> <td align="right">clientX, clientY:</td> <td><input type="text" name="resizeCoords" size="10" /></td> </tr> </table> </form> <div id="display" style="position:relative; left:100"> Глава 25. Объекты событий 779
<img alt="imageM src="nile.gif" width="320M height="240M border="0" /> </div> </body> </html> Чтобы лучше понять взаимосвязь между "координатными" свойствами, с помощью документа, представленного листингом 25.14, выполните следующие задачи. 1,. Щелкните на точке над буквой i в кнопке Click Label. Целевой элемент в данном случае представлен объектом input (кнопка), свойство которого of f set Parent установлено равным элементу ячейки таблицы. Значение свойства of f setY небольшое, поскольку указатель располагается совсем рядом с началом отсчета системы координат элемента. Клиентские координаты (а также х и у) связаны, тем не менее, с видимой областью документа. Если окно браузера максимально расширено, то свойства screenX и clientX равны. Разница между свойствами screenY и clientY равна расстоянию, на которое документ прокручен в окне браузера. Если документ вообще не прокручивать, то указанные пары свойств всегда будут равны. 2. Ознакомьтесь с приведенными в документах значениями свойств, а затем слегка прокрутите документ (щелчок на полосе прокрутки приведет к возникновению события). Далее снова щелкните на точке, расположенной на кнопке. Свойство clientY уменьшилось, поскольку при прокрутке вниз расстояние между кнопкой и верхним краем отображаемой в окне части документа стало меньше. Все offset-свойства в Windows продолжают рассчитываться правильно — во внутренней системе координат элемента. В Мае, тем не менее, для их получения из глобальных координат вычитается прокрученное расстояние. 3. Щелкните на большом изображении. Клиентские свойства (как и screen-свойства в Windows и Мае) вычисляются весьма точно. Но в Windows свойства х и у возвращают координаты события относительно значения свойства of f set Parent элемента img, который помещен в элемент div. Обратите внимание, что браузер рассматривает элемент div как начинающийся на 10 пикселей левее от левого края изображения. В WinIE5.5 вы можете щелкнуть в пределах этих 10 прозрачных пикселей, чтобы вызвать событие элемента div. Это поле учитывается автоматически, что отражается в значениях свойств х и у. Все сказанное выше в полной мере справедливо и для MacIE, но до тех пор, пока страница не начнет прокручиваться. 4. Щелкните на верхнем элементе hr под заголовком. На это у вас может уйти некоторое время. Убедитесь, что клиентская система координат изменилась (в Мае это справедливо только до прокрутки документа). Щелкните в левой части разделителя, чтобы найти начало отсчета внутренней системы координат элемента. Если вы пользуетесь Windows, то можете ознакомиться с неожиданным проявлением "координатных" свойств. 1. Не прокручивая страницу, щелкните в произвольном месте правой части страницы (вдалеке от текста, чтобы элемент body был представлен объектом srcElement). Поскольку теоретически элемент body занимает всю площадь окна браузера, то все пары координатных свойств должны быть равны, за исключением свойств screen. Вы заметите, что свойства offset на 2 пикселя меньше остальных свойств. В большинстве случаев эта разница особо не повлияет на результаты выполнения сценариев, но ее нужно учесть при отладке сложных приложений. По неизвестной мне причине, система 780 Часть III. Объекты документа
координат для свойств offset смещена на 2 пикселя вправо и вниз относительно левого верхнего угла окна браузера. В Мае эта ошибка никак не проявляется. 2. Щелкните на тексте элементов hi и р (над и под горизонтальным разделителем в верхней части документа). Теоретически свойства offset должны измеряться в системе координат самих элементов. Вместо этого они измеряются в той же системе координат, что и клиентские свойства (плюс 2 пикселя). Это поведение никак не связано с установкой текстового курсора в элементах. В Мае подобного поведения не наблюдается. Многие описанные выше свойства представлены в W3C DOM, а потому поддерживаются браузерами этой спецификации. Неподдерживаемые свойства в >УЗС-браузерах принимают значения undefined. Вы можете ознакомиться с другими примерами "координатных" свойств в главе 39, в которой описываются методы перетаскивания элементов. См. также: свойства f romElement, toElement. dataTransfer Значение: объект Только для чтения Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Свойство dataTransfer является ссылкой на объект dataTransfer (только в Winffi). Можно использовать этот объект в операциях перетаскивания не только для контроля передачи данных, но и для определения формы указателя мыши во время выполнения этих действий. Табл. 25.6 предоставляет список свойств и методов объекта dataTransfer. Таблица 25.S. ОтвЫк с*о*ст* и i Свойство/метод Тип возвращаемого значения -"?, dropEf f ect string (строка) Элемент, являющийся потенциальным приемником отдельного действия, может использовать обработчики событий ondragenter, ondragover ИЛИ ondrop, ДЛЯ установки типа указателя, отображенного поверх элемента. Прежде, чем это сможет работать, обработчик события ondragstart элемента источника должен задать значение свойства eventEf feet Allowed. Возможные строковые значения ДЛЯ Обоих СВОЙСТВ — copy, link, move ИЛИ none. Эти значения соответствуют системным указателям Windows, которые обычно используются при управлении файлами или документами. Следует также отметить действие по умолчанию (речь идет об установке свойства event.ReturnValue в значение false) для всех обработчиков события: ondragenter, ondragover И ondrop ef f ectAilowed string (строка) Вызывается как реакция на событие dragstart элемента источника. Это свойство определяет тип действия перетаскивания, которое будет ПРОИСХОДИТЬ, copy, link, move ИЛИ попе — это возможные строковые значения. Значение должно соответствовать значению свойства dropEf f ect объекта event целевого элемента и отменять действия по умолчанию (речь идет Об установке свойства event. ReturnValue в значение false) в обработчике события ondragstart Гл9ва 25. Объекты событий 781
Окончание табл. 25.5 Свойство/метод Тип возвращаемого значения Описание ciearData нет Переносит данные в буфер обмена. Если данные не имеют ([ формат]) форматирования, все они будут уничтожены. Форматирование данных задается одним или несколькими следующими Значениями: Text, URL, File, HTML, Image getData string (строка) Восстанавливает (извлекает) данные указанного формата (формат) из буфера обмена. Формат представлен одним из значений: Text, URL, File, HTML, Image. Буфер обмена не освобождается после извлечения данных, поэтому его можно использован в нескольких последовательных операциях setData Boolean (булев) Поставляет данные строки в буфер обмена. Формат - (формат, это одно из следующих значений: Text, url, File, html, данные) image. Для нетекстовых форматов данные представлены строкой, которая определяет путь или URL содержимого. Возвращение значения true возникает в случаях, если передача в буфер обмена проведена успешно Объект dataTransf ег действует как проводник и контролер данных, которые сценарии передают при перетаскивании пользователем объекта от одного элемента к другому. Следует придерживаться четкой последовательности действий, запущенных группой обработчиков событий. Это означает, что объект event вызывается при возникновения любого события перетаскивания как отдельный экземпляр. Последовательность начинается в элементе источника, где обработчик события ondragstart обычно задает значение свойства dropEf f ect. Метод getData () используется для фиксации данных объекта источника, которые перемещаются к конечной цели. Например, при перетаскивании изображения может перемещаться его URL — данные, извлекаемые свойством event. srcElement. src данного события (src — это свойство изображения). В целевом элементе/элементах присутствует три обработчика события: ondragenter, ondragover и ondrop. Как правило, первые два из них выполняют лишь подготовку элемента непосредственно для события dropEf f ect (должно соответствовать effect All owed в элементе источнике перед началом перетаскивания) и задают свойство event. returnValue равным false, чтобы указатель соответствовал необходимым требованиям. Эти задачи также выполняются в ondrop; кроме них, он также обрабатывает действия, заданные для целевого элемента при вызове метода getData () объекта dataTransf ег для приобретения данных, "сохраненных" getData () в начале перетаскивания. Убедиться, что данные случайно не вызываются другим событием, можно, используя метод ciearData () для удаления их из памяти. Заметьте, что тип перетаскивания, описываемый в данном случае, не характерен для элемента, перетаскиваемого на экране (хотя можно создать сценарий и таким образом). Целью является обработка операции перетаскивания таким же образом, как это осуществляется в окне программы Windows Explorer. Для пользователя перетаскивание связано с указателем мыши. Именно поэтому свойство dataTransf ег объекта обеспечивает появление курсора в точке отпускания содержимого, что является способом передачи потребителю типа действия, которое произойдет в конечном счете. 782 Часть III. Объекты документа
Пример Детальный пример использования свойства dataTransfer на практике можно найти в листинге 15.37 в разделе, в котором описан обработчик события ondrag. См. также: обработчики события ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop. £ romElement toElement Значение: объект элемента Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойства f romElement и toElement позволяют элементу установить, где указатель появился или исчез. Эти свойства расширяют область действия обработчиков события onmouseover и onmouseout, увеличивая ее с внешней стороной текущего элемента (обычно соседним элементом). Когда для элемента запускается обработчик события onmouseover, указатель еще располагается на другом элементе, а свойство f romElement задает ссьшку на этот элемент. Наоборот, когда возникает событие onmouseout, указатель уже располагается на другом элементе, а свойство toElement задает на него ссылку. Пример В листинге 25.15 приведен пример использования свойств f romElement, toElement. При наведении указателя на центральную ячейку в строке состояния указывается текст ячейки, с которого переместился указатель. <html> <head> <title>fromElement and toElement Properties</title> <style type="text/css"> .direction {background-color:#00FFFF; width:100; height:50; text-align:center} #main {background-color:#FF6666; text-align:center} </style> <script type="text/javascript"> function showArrival() { var direction = (event.fromElement.innerText) ? event.fromElement.innerText : "parts unknown"; status = "Arrived from: " + direction; } function showDeparture() { var direction « (event.toElement.innerText) ? event.toElement.innerText : "parts unknown"; status = "Departed to: " + direction; } </script> </head> <body> <hl>fromElement and toElement Properties</hl> <hr /> Глава 25. Объекты событий 783
<p>Roll the mouse to the center box and look for arrival information in the status bar. Roll the mouse away from the center box and look for departure information in the status bar.</p> <table cellspacing=M0" cellpadding="5"> <tr> <tdx/td> <td class="direction">North</td> <tdx/tdx/tr> <tr> <td class=ndirection">West</td> <td id="main" onmouseover="showArrival()" onmouseout="showDeparture 0">Roll</td> <td class="direction">East</td> </tr> <tr> <tdx/td> <td class="direction">South</td> <tdx/td> </tr> </table> </body> </html> Это весьма полезный пример, поскольку он выявляет потенциальные ограничения, заданные в браузере. Элементы, представленные свойствами f romElement и toElement, должны генерировать события мыши, чтобы быть зарегистрированными. Каждый следующий элемент в последовательности в обязательном порядке представлен одним из этих свойств. Например, если вы наведете указатель на центральную ячейку, а затем быстро сведете его в нижнюю часть окна, то нижняя ячейка может не успеть зарегистрироваться в браузере. Таким образом, текст в строке состояния будет представлен содержимым элемента body, т.е. элементом, который воспринял событие мыши, зарегистрированное свойством toElement для центральной ячейки. См. также: свойство srcElement. keyCode Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Для событий клавиатуры свойство keyCode возвращает целые числа, соответствующие значению кодов символов в системе Unicode (для событий keypress) или клавиш на клавиатуре (для событий keydown и keyup). Эти системы кодирования символов существенно отличаются друг от друга. Значения кода Unicode (такие же, как значения ASCII для латинского набора символов) нажатой пользователем клавиши можно узнать, используя свойство KeyCode обработчика события onkeypress. Например, а в нижнем регистре возвращает 97, в то время как ■ в верхнем регистре А возвращает 65. Небуквенные символы (стрелки, символы цифровой клавиатуры, функциональные знаки) в обработчике событий onkeypress для свойства keyCode возвращают значение null. Другими словами, свойство keyCode для событий keypress — это, скорее, код буквы, чем код клавиши. Чтобы фиксировать клавишу на клавиатуре, нажимаемую пользователем, используются обработчики события onkeydown или onkeyup. Для них объект event определяет числовой код, связанный с определенной клавишей клавиатуры. Для клавиш букв он определяется используемым языком, назначенным в качестве системного. Важно, что никакого различия между верхним и нижним регистрами клавиш букв 784 Часть III. Объекты документа
теперь нет. Клавиша А в режиме латинского языка возвращает значение 65, независимо от состояния клавиши <Shift>. В то же время, однако, нажатие клавиши <Shift> генерирует ее собственные события onkeydown и onkeyup, задающие значение keyCode. Другие небуквенные символы — стрелки, символы цифровой клавиатуры, функциональные знаки и т.д. — также имеют свои собственные коды. Все они детализированы (включая специальные коды клавиш цифровой клавиатуры, которые отличаются от соответствующих им чисел верхней строки алфавитно-цифровой клавиатуры). Вы можете ознакомиться с детальным описанием событий клавиатуры в главе 15, а с примерами применения свойства keyCode — в соответствующих приложениях. Пример Листинг 25.16 предоставляет вам возможность детально изучить свойство keyCode для всех трех событий клавиатуры при вводе текста в область text area. Впоследствии вы сможете использовать эту страницу для получения кодов клавиш. Листинг2Б.16.Отобрююнюкодммшт '&•- ^'::* .':г: <html> <head> <title>keyCode Property</title> <style type="text/ess"> td {text-aligmcenter} </style> <script type="text/javascript"> function showCode(which) { document.forms[0].elements[which] «value = event.keyCode } function clearEmO { for (var i = 1; i < document.forms[0].elements.length; i++) { document.forms[0].elements[i].value = "" } } </script> </head> <body> <hl>keyCode Property</hl> <hr /> <form> <p><textarea name="scratchpad" cols="40" rows="5" wrap="hard" onkeydown="clearEm(); showCode('down•)" onkeyup="showCode('up')" onkeypress="showCode ('press1) "></textareax/p> <table cellpadding="5"> <tr> <th>Event</th> <th>event.keyCode</th> </tr> <tr> <td>onKeyDown:</td> <tdxinput type="text" name="down" size="3" /></td> </tr> <tr> <td>onKeyPress:</td> <tdxinput type="text" name="press" size="3" /></td> </tr> Глава 25. Объекты событий 785
<tr> <td>onKeyUp:</td> <tdxinput type="text" name="up" size="3" /></td> </tr> </table> </form> </body> </html> Ниже описаны специальные задачи, которые решаются с помощью документа, представленного листингом 25.16. Если вы используете кодировку, отличную от English или Latin, то получите совершенно другой результат. 1. Введите символ а в нижнем регистре. Обработчик onkeypress отображает код 97. Это значение представляет код Unicode (и ASCII) первой буквы нижнего регистра латинского алфавита. Два других обработчика отображают код 65. 2. Введите символ А в верхнем регистре. Если вы были внимательны, то знаете, что клавиша <Shift> представлена кодом 16 (в событиях onkeydowm и onkeyup). Но для всех трех событий в данном случае отображаются значения 65, поскольку ASCII-код символа в верхнем регистре совпадает с кодом символа для этой буквы. 3. Нажмите и отпустите клавишу со стрелкой "вниз" (убедитесь, что текстовый курсор все еще находится в текстовой области, иначе события клавиатуры не будут регистрироваться). Поскольку эта клавиша не представляет символ, то событие onkeypress не генерируется. Остальные события возникают и возвращают код 40. 4. Понажимайте другие несимвольные клавиши. Некоторые из них выводят на экран диалоговые окна и меню, поэтому их коды (если таковые отображаются) вам мало пригодятся. Обратите внимание, что в Windows и Мае коды символов далеко не всегда одинаковы. См. также: обработчики события onkeydown, onkeypress, onkeyup. nextPage Значение: строка Только для чтения Совместимость: WinIE5*5+, MacIE-, NN-, Moz-, Safari- Свойство nextPage применяется в том случае, если документ в WinIE5.5 использует поведение TemplatePrinter. К значениям этого свойства относятся следующие: left, right или пустая строка. Чтобы получить дополнительную информацию о поведении TemplatePrinter в WinIE5.5 посетите узел http://msdn.microsoft.com/workshop/browser/hosting/printpreview/ reference/ behaviors/TemplatePrinter.asp p rop e r tyName Значение: строка Только для чтения Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Свойство propertyName принимает значение только после возникновения события onpropertychange. Если сценарий изменяет свойство, запускается обработчик события onpropertychange, а строчное значение свойства сохраняется в свойстве event.propertyName. Если это 786 Часть ///. Объекты документа
свойство оказывается принадлежащим объекту style, связанному с элементом, то свойство propertyName— это полная ссылка на определенное свойство, например style.back- groundColor. Пример В листинге 15.46 описан обработчик события onpropertychange, который представляет пример значений, возвращаемых этим свойством. См. также: обработчик события onpropertychange (глава 15) repeat Значение: булево Только для чтения Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Свойство repeat задается для события onkeydown только тогда, когда клавиша находится в режиме повторного нажатия (как определено параметрами настройки папки Панель управления для клавиатуры). Благодаря этой информации, можно предотвратить автоматическое повторное введение символов, распознаваемых браузером. Это свбйство можно вызвать вручную, если удерживать клавишу нажатой слишком долго. Следующий фрагмент сценария — обработчик события onkeydown для текстового поля или объекта text area; он предотвращает появление различных символов, даже если система работает в режиме повтора. if (event.repeat) { Event.returnValue = false; } Отключите действие по умолчанию во время работы в режиме повтора, и вы не допустите повторного появления символов в текстовом поле до отключения режима (нажатия другой клавиши). Это свойство не предназначено для МасШ5. См. также: обработчик события onkeydown. returnValue Значение: булево Только для чтения Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Если ГЕ4+ продолжает следовать первоначальному способу предотвращения действия по умолчанию для обработчика события (т.е. задает в качестве последнего оператора обработчика события выражение return false), то модель событий IE4+ предоставляет свойство, которое позволяет аннулировать действие по умолчанию, полностью происходящее в пределах функции, вызванной обработчиком события. По умолчанию свойство returnValue объекта event имеет значение true. Это означает, что элемент обрабатывает событие после того, как запрограммированный обработчик завершает выполнение всех задач (так, если бы сценария не было вообще). Обычная обработка (по умолчанию), например, приводит к отображению введенного символа, перемещению по ссылке href после щелчка на ней или передаче данных формы после щелчка на кнопке Submit. Но не всегда необходимо, чтобы действие по умолчанию произошло. Например, в текстовом поле предполагается вводить только числа. Обработчик события onkeypress может вызвать функцию, рассматривающую каждый введенный символ. Если символ — не цифра, то он не достигает текстового поля. Подобная функция проверки правильности данных может вызываться обработчиком события onkeypress только этого текстового поля. function checklt () j[ var charCode = event.keyCode; if (charCode < 48 || charCode > 57) { Глава 25. Объекты событий 787
alert ("Please make sure entries are numerals only."); event.returnValue = false; } } Используйте этот обработчик события, и вы не допустите появления ошибочного символа в текстовом поле. Заметьте, что это свойство — не заменитель выражения return в функции обработчика. Если необходимо, возвращаемое значение можно использовать, применив оператор return в дополнение к определению значений свойств event. returnValue. Пример Вы найдете несколько примеров использования свойства returnValue в главе 15. Внимательно изучите листинги 15.30, 15.33, 15.36, 15.37, 15.38 и 15.45. См. также: оператор/выражение return. saveType Значение: строка Только для чтения Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Свойство saveType приобретает значение только тогда, когда событие oncontentsave привязывается к поведению Winffi, определяемому DHTML, (.htc). Для получения дополнительной информации о поведениях посетите узел по адресу http: //msdn. microsoft. com/ workshop/author/behaviors/overview.asp См. также: метод addBehavlor (). srcElement Значение: ссылка на объект элемента Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство srcElement — это ссылка на элемент объекта HTML, который является целью исходного события. Событие может проходить через иерархическую структуру объектов и обрабатываться на любом уровне. Поэтому оно имеет свойство, указывающее на элемент, который инициировал событие. Когда ссылка на этот элемент задана, можно получить, а также изменить любое его свойство или вызвать любые его методы. Пример В качестве простейшего примера возможностей свойства srcElement я привел листинг 25.17. В нем в элементе body настроено два обработчика события, каждый из которых вызывает отдельную функцию. Идея сценария очень проста: события onmousedown и onmouseup всплывают независимо от целевого элемента, а функции определяют последние и изменяют их цвет стиля. В каждой функции проверяется свойство className целевого элемента. Если это свойство имеет значение bold (имя класса общее для всех трех элементов span абзаца), то правило таблицы стилей для этого класса изменяется. В собственных сценариях вы можете задать более сложные операции форматирования документа Обратите внимание на то, что сценарий может ничего не "знать" об объектах страницы, чтобы правильно обратиться к ним. Причина состоит в том, что свойство srcElement предоставляет всю необходимую информацию о целевом элементе. 788 Часть III. Объекты документа
Листинг 25Л7. Исгюльзовд^ <html> <head> <title>srcElement Property</title> <style type="text/css"> .bold jfont-weight:bold} .ital {font-style:italic} </style> <script type="text/javascript"> function highlight() { var elem = event.srcElement; if (elem.className == "bold") { document.stylesheets[0].rules[0].style.color = "red"; } else { elem.style.color = "#FFCC00"; } function restore() { var elem = event.srcElement; if (elem.className == "bold") { document.stylesheets[0].rules[0].style.color = ""; } else { elem.style.color = ""; } } </script> </head> <body onmousedown="highlight()" onmouseup="restore()"> <hl>srcElement Property</hl> <hr /> <p>One event handler...</p> <ul> <li>Can</li> <li>Cover</li> <li>Many</li> <li>Objects</li> </ul> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, <span class="bold">sed do</span> eiusmod tempor incididunt <span class="ital">ut labore et</span> dolore magna aliqua. Ut enim adminim veniam, <span class="bold">quis nostrud exercitation</span> ullamco laboris nisi ut aliquip ex ea <span class="bold">commodo consequat</span>.</p> </body> </html> См. также: свойства fromElement, toElement. srcFilter Значение: строка Только для чтения Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Согласно концепции Microsoft, свойство srcFilter должно возвращать строку с именем фильтра, который был применен для вызова обработчика события onf ilterchange. Если свойство существует в объекте event, его значение всегда null, по крайней мере в Ш6. См. также: обработчик события onf ilterchange; объект style. filter. Глава 25. Объекты событий 789
srcUrn Значение: строка Только для чтения Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Если событие используется в Winffi при подключении к элементу поведения, для которого определен идентификатор URN, свойство srcUrn возвращает строку с URN-идентификато- ром. Для получения дополнительной информации о поведениях посетите узел http://msdn.microsoft.com/workshop/author/behaviors/overview.asp См. также: метод addBehavior (). toElement См. f romElement type Значение: строка Только для чтения Совместимость: WinDE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Всегда можно выяснять, какое событие запускается при создании объекта event с помощью свойства type. Его значение — строковая версия имени события, только без префикса on, который обычно ассоциируется с именем обработчика события в Ш. Это свойство применяется для определения одного обработчика события в качестве функции обработки различных видов событий. Например, и onmousedown, и onclick — обработчики события для объекта; они вызывают одну функцию. Внутри функции задано ветвление в зависимости от способа ее вызова (mousedown или click) и события, которое генерируется. Вам не обязательно использовать подобные обработчики, но знать о возможности совместного использования функции просто необходимо. Данное свойство и его значения полностью совместимы с моделями событий NN4 и NN6+/W3C. Пример Используйте приложение The Evaluator для ознакомления со значениями, которые возвращаются свойством type. Введите следующее имя объекта в нижнее текстовое поле и нажмите <Enter>. event Если необходимо, прокрутите область Results, чтобы найти свойство type, имеющее значение keypress. Щелкните на кнопке List Properties. Значение свойства type изменится на click. Причина такого "поведения" приложения очень проста. Объект event, свойства которого мы определяем, представляет событие, которое запускает функцию отображения свойств. В текстовой области это обработчик onkeypress, а у кнопки — onclick. См. также: все обработчики события (глава 15). Объект события в NN6+ Свойства события Методы Обработчики события altKey initEvent()* bubbles initKeyEvent()* 790 Часть III. Объекты документа
Окончание таблицы Свойства события Методы Обработчики события ,button initMouseEvent()* cancelBubble initMutationEvent()* cancelable initUIEvent()* charCode preventDefault() clientX stopPropagationO clientY ctrlKey currentTarget detail eventPhase isChar keyCode layerX layerY metaKey originalTarget pageX pageY relatedTarget screenX screenY shiftKey target timestamp type view Синтаксис Доступ к свойствам и методам объекта события в NN6+. объектСобытия. свойство \ метод ( [параметры] ) Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safaril+ Описание объекта Несмотря на то, что данный объект базируется в значительной мере на объекте события, определенном в W3C DOM 2, объект события NN6+/Moz также имеет некоторые характеристики, присущие его версии в NN4. Ряд свойств добавлен прежде всего для обеспечения совместимости. Поскольку разработки для NN6, скорее всего, будут игнорировать особенности Глава 25. Объекты событий 791
NN4 DOM и ее модель событий, то использовать их на практике следует чрезвычайно осторожно (см. ниже). Везде, где возможно, используйте и поддерживайте положения модели событий W3C DOM. Подобно Ш4+, модель событий NN6+ обеспечивает разработчика всплывающими событиями, однако несовместимость ссылок на объекты в обработчиках событий все еще присутствует. В W3C (как в NN4) объект события явно передается как параметр функции обработчика (или, скорее, приемника) события. Но после назначения специфичного для браузера объекта события, определенного как переменная внутри функции, несколько свойств приобретают одинаковые имена в моделях событий IE4 + и NN6+. Если Microsoft в своих будущих разработках обратит больше внимания на модели обработки событий в W3C DOM, то совместимость Ш4+ с другими браузерами только улучшиться. Объект события, описываемый в этом разделе, — экземпляр события, который получен в результате действий пользователя или системы. NN6 DOM включает дополнительный статический объект Event. Многие свойства статического объекта Event наследуются экземпляром события, поэтому детальное описание этих свойств также будет приведено в настоящем разделе (именно этот объект события используется для написания сценариев). Во многих фрагментах кодов в следующих подразделах, будут присутствовать ссылки, которые начинаются с evt. Это предполагает, что оператор или операторы, заданные внутри функции, оперируют объектом события в виде переменной evt. function myFunction (evt) {.♦.} Как отмечалось ранее в этой главе, ссылки на объекты событий в NN6 и Ш4+ с помощью этого метода можно сделать одинаковыми, так как сценарии управляют идентичными (или подобными) свойствами объекта события. Свойства altKey ctrlKey metaKey shiftKey Значение: булево Только для чтения Совместимость: WinIE4+, MacEE4+, NN6+, Mozl+, Safari 1+ Когда объект события создается в ответ на действие пользователя или системы, эти четыре свойства вызываются в зависимости от того, удерживались ли соответствующие клавиши- модификаторы в момент щелчка. Если клавиша удерживалась, свойству присваивается значение true; иначе — значение false. Свойство metaKey соответствует клавише <Command> клавиатуры Macintosh, но не соответствует ни одной клавише в системе Windows. Обычно выражения, содержащие это свойства, используются в условной конструкции if. Поскольку им присвоен булев тип данных, различные свойства можно комбинировать в отдельном условии. Например, при ветвлении функции, которая выполняется, если событию щелчка предшествует нажатие клавиш <Shift> и <Ctrl>, условия будут выглядеть следующим образом. if (evt.shiftKey && evt. ctrlKey) { // выполняемые операторы ) Наоборот, можно избрать более удобный для пользователей метод для указания варианта действия в случае использования одной из четырех клавиш-модификаторов. 792 Часть III. Объекты документа
if (evt.shiftKey || evt.ctrlKey || evt.metaKey || evt.altKey) { // выполняемые операторы } Цель этого метода — предоставить возможность быстро выполнить необходимое действие, а не заставить вас запомнить названий всех клавиш-модификаторов. Пример В листинге 25.10 значения этих свойств используются при задании свойства checked соответствующих флажков для событий самых разных типов. bubbles Значение: булево Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ He каждое событие является всплывающим. Например, событие submit не распространяется далее объекта формы, с которым связано событие. События, не являющиеся всплывающими, имеют свойство bubbles объекта события, равное false. Все другие объекты событий имеют свойства bubbles, равные true. Используйте это свойство в редких случаях, когда обработчик события управляет огромным количеством событий. Для всплывающих событий можно выполнить один набор действий, а все остальные обрабатывать в каждом отдельном случае по-разному. Для реализации этого подхода необходимо использовать конструкцию if в качестве условного оператора. if (evt.bubbles) { // специальная обработка всплывающего события } Нет необходимости задавать ветвление только для отмены всплывания. Нераспростра- няемые события не вступят в конфликт с браузером, если запретить им распространяться. См. также: свойство cancelBubble. button Значение: целочисленное Только для чтения Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство button определяет кнопку, которая была нажата при инициализации события мыши. Левая (основная) кнопка возвращает значение 1. Если мышь трехкнопочная, средняя кнопка возвращает 2. Правая кнопка (любой многоклавишной мыши) возвращает значение 3. Заметьте, что эти значения отличаются от сформулированных в W3C DOM (0, 1 и 2, соответственно), но они обратно совместимы со свойством which в NN4. ■' Кнопки мыши, отличные от основной (первой), проще обрабатывать в событиях mousedown или mouseup, чем в click. В случае нажатия пользователем нескольких кнопок учитываться будет значение только самой последней. Будьте осторожны при создании сценариев с использованием свойства button в Ш4+ и NN6+. Соответствующие модели событий определяют различные значения для кнопок мыши. Пример В листинге 25.11 значение свойства button отображается в строке состояния. Щелкните разными кнопками мыши на графической кнопке на экране, чтобы увидеть результат. Глава 25. Объекты событий 793
cancelBubble Значение: булево Чтение/Запись Совместимость: WinlE-, МасШ-, NN6+, Mozl+, Safari 1+ Свойство cancelBubble является недоработанным образцом свойства события ГЕ4+, реализованного в NN6+/Moz/Safari, даже при том, что оно не определено в W3C DOM. Свойство функционирует так же, как и в Ш4+, в котором определяет, будет ли объект текущего события всплывать выше в иерархии объектов документа. По умолчанию это свойство имеет значение false; если событие способно к всплыванию, то эта операция выполняется автоматически. * Чтобы не допустить всплывания текущего события, задайте в пределах функции обработчика события значение true. Альтернативным решением может быть отмена всплывания непосредственно в атрибуте обработчика события элемента. onclick = "doButtonClick. (this); event.cancelBubble = true" Отмена всплывания события выполняется только для текущего события. Следующее инициированное событие будет по умолчанию способно к всплыванию (имеет свойство всплывания). Если вам необходимо в максимально возможной степени совместить ваш код с поддерживаемым в W3C DOM, то используйте метод stopPropagation (), а не свойство cancelBubble. Для обеспечения совместимости браузеров предпочтительнее использовать cancelBubble. Пример В листинге 25.6 можно увидеть свойство cancelBubble в действии в среде Ш. Даже при том, что листинг представляет код со специфичными для ЕЕ5.5+ операторами, демонстрация отмены всплывания выполняется и в Г£4. См. также: метод stopPropagation (). cancelable Значение: булево Только для чтения Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari 1+ Если событие отменяемое, то его поведение по умолчанию может быть изменено с помощью сценария. Большинство событий являются отменяемыми, однако некоторые из них — все еще нет. Свойство отмены события позволяет запрашивать сведения о специфическом событии, чтобы убедиться, присутствует ли у объекта свойство cancelable. Значения свойства— булевы. Вы можете использовать в сценарии только отменяемые события, если необходимо обеспечить возможность ветвления. Для ветвления удобно использовать свойство в условной конструкции if. if (evt.cancelable) { // специальная обработка всплывающего события ) Однако не обязательно выполнять ветвление только для предотвращения действий события по умолчанию. Неотменяемое событие не входит в конфликт с браузером, если для него отменить поведение по умолчанию. См. также: метод preventDefault (). charCode keyCode Значение: целочисленное Только для чтения Совместимость: WinlE-, МасШ-, NN6+, Mozl+, Safari 1+ 794 Часть ///. Объекты документа
Модель событий в W3C четко различает символы Unicode, задаваемые алфавитно-цифровым клавишам клавиатуры, и код, определенный каждой клавише на клавиатуре (независимо от ее символа). Чтобы получить символ клавиши, сначала используйте событие onkeypress — так вы создадите объект события. Затем примените свойство charCode объекта event. Это свойство возвращает 97 для а и 65 для А, так как оно определяет символ, связанный с клавишей. Его значение нулевое для событий onkeydown и onkeyup. Напротив, свойство keyCode при нажатии алфавитно-цифровых клавиш имеет ненулевые значения для событий onkeydown и onkeyup (для onkeypress это свойство имеет нулевое значение). Для большинства других небуквенных символов все три события используют свойство key Code. С его помощью можно получить коды небуквенных клавиш — клавиш со стрелками, функциональных клавиш и т.д. Для буквенных клавиш верхний и нижний регистр в свойстве не различается: клавиша А латинской раскладки клавиатуры возвращает значение 65, независимо от состояния клавиши <Shift>. Однако в это же время нажатие клавиши <Shift> генерирует ее собственные события onkeydown и onkeyup, присваивающие свойству keyCode значение 16. Другие небуквенные символы также имеют свои собственные коды. Все коды клавиш детализированы, включая специальные клавиши цифровой клавиатуры, которые отличаются от соответствующих им цифр в верхней строке алфавитно-цифровой клавиатуры. / Safari 1.0 не поддерживает свойство charCode. Вместо него в данном браузере /назаметку используется свойство keyCode, которое возвращает коды алфавитно-цифровых * .«^ клавиш, и не возвращает коды для остальных клавиш клавиатуры. Детальное описание событий клавиатуры приведено в специальном разделе главы 15. Там же вы узнаете об использовании свойства в приложениях. Пример В листинге 25.18 приведен пример использования свойств keyCode и charCode для трех событий клавиатуры при вводе текста в область text are а. В дальнейшем это приложение можно использовать в качестве справочника по кодам клавиш и символов. Лв, ОшбражОНИе СВОЙСТВ charCode И keyCode <html> <head> <title>charCode and keyCode Properties</title> <style type="text/css"> td {text-align:center} </style> <script type="text/javascript"> function showCode(which, evt) { document.forms[0].elements[which + "Char"].value = evt.charCode; document.forms[0].elements[which + "Key"].value = evt.keyCode; } function clearEm() { for (var i = 1; i < document.forms[0].elements.length; i++) { document:forms[0].elements[i].value = ""; } } </script> </head> Глава 25. Объекты событий 795
<body> <hl>charCode and keyCode Properties</hl> <hr /> <form> <pxtextarea name="scratchpad" cols="40" rows="5" wrap="hard" onkeydown="clearEm(); showCode('down', event)" onkeyup="showCode('up•, event)" onkeypress="showCode('press' , event) "></textareax/p> <table cellpadding=n5"> <tr> <th>Event</th> <th>event.charCode</th> <th>event.keyCode</th> </tr> <tr> <td>onKeyDown:</td> <td><input type="text" name="downChar" size="3" /></td> <tdxinput type="text" name="downKey" size="3" /></td> </tr> <tr> <td>onKeyPress:</td> <td><input type="text" name="pressChar" size="3" /></td> <tdxinput type="text" name="pressKey" size="3" /></td> </tr> <tr> <td>onKeyUp:</td> <tdxinput type="text" name =" up Char" size="3" /></td> <tdxinput type="text" name="upKey" size="3" /></td> </tr> </table> </form> </body> </html> Ниже описаны специальные задачи, которые решаются с помощью документа, представленного листингом 25.18, в NN6+/Mozl+. Если вы используете кодировку, отличную от English или Latin, то получите совершенно другие результаты. 1. Введите символ а в нижнем регистре. Обработчик onkeypress отображает код 97. Это значение представляет код Unicode (и ASCII) первой буквы нижнего регистра латинского алфавита. Два других обработчика отображают код 65. 2. Введите символ А в верхнем регистре. Если вы были внимательны, то знаете, что клавиша <Shift> представлена кодом 16 (в событиях onkeydowm и onkeyup). Но для всех трех событий в данном случае отображаются значения 65, поскольку ASCII-код символа в верхнем регистре совпадает с кодом символа для этой буквы. 3. Нажмите и отпустите клавишу со стрелкой "вниз" (убедитесь, что текстовый курсор все еще находится в текстовой области, иначе события клавиатуры не будут регистрироваться). Поскольку эта клавиша не представляет символ, то событие onkeypress не генерируется. Остальные события возникают и возвращают код 40. 4. Понажимайте другие несимвольные клавиши. Некоторые из них выводят на экран диалоговые окна и меню, поэтому их коды (если таковые отображаются) вам не пригодятся. См. также: обработчики события onkeydown, onkeypress, onkeyup. 796 Часть III. Объекты документа
alientX clientY layerX layerY pageX pageY screenX screenY Значение: целочисленное Только для чтения Совместимость: WinDE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Объект события NN6 включает свойства координат указателя мыши как в модели NN4, так и IE4+. Для управления указателем мыши в W3C вам не требуется специальных знаний, если вы уже имеете опыт работы с другими браузерами. Подобно объекту события в Ш4+, свойства clientX и clientY объекта события в W3C DOM задают координаты относительно просматриваемой области содержимого окна. Эти значения заданы для окна браузера, а не самого документа. Но, в отличие от YEA +, вам не обязательно вычислять координаты указателя в документе, .так как другая пара свойств — pageX и pageY — предоставляет необходимую информацию автоматически. Если страница не прокручивалась, то значения для окна браузера и документа остаются одинаковыми. Поскольку координаты указателя мыши в момент возникновения события важнее знать для документа, чем для окна, свойства pageX и pageY используются чаще. Другая пара свойства, layerX и layerY, происходит от уже не существующих объектов слоев NN4, которые, тем не менее, будут служить еще достаточно долго. Эти координаты задаются относительно содержимого позиционируемого элемента, который принимает событие. Как правило, непозиционируемые элементы в разделе body документа более распространены, чем позиционируемые. Для последних элементов значения координат относительно страницы и слоя будут одинаковыми. Но при создании позиционируемого элемента координатное пространство измеряется от верхнего левого угла соответствующего объекта. Так, при использовании координат для определения расположения перетаскиваемых элементов можно задать соответствующие свойства только для позиционируемых объектов. Недостаток системы координат в NN6+/Moz — ртсутствие целевого элемента как такового (сопоставимого со свойствами of f setx и of f setY в IE4+). Эти значения, однако, могут быть вычислены путем вычитания из координат страницы значений offset Left и of f set Top как целевого элемента, так и его позиционируемого содержимого. Например, для получения координат указателя в событии щелчка на изображении обработчик события вычисляет необходимые значения следующим образом. var clickOffsetXvar = evt.pageX — evt.target.offsetLeft — document.body.offsetLeft; var clickOffsetY — evt.pageY — evt.target.offsetTop — document.body.offsetTop; Последний набор свойств, screenX и screenY, предоставляет разработчику значения, соответствующие координатному пространства экрана монитора. Из всех представленных свойств только координатные пространства окна браузера и экрана монитора определены в стандарте W3C DOM 2. Помните, что в NN6 к целевым объектам события также относят текстовые узлы внутри элементов. Поскольку эти узлы не обладают всеми свойствами полноценного элемента (например, Глава 25. Объекты событий 797
они не имеют свойств смещения, отражающих их размещение в документе), то управлять ими приходится из родительского узла; именно родительский узел предоставляет все необходимые свойства, которые задают "геометрию" элемента страницы. Подобное решение используется только для ситуаций, когда в сценарии необходимо обработать события, инициированные щелчком на тексте. Пример Вы можете ознакомиться с "координатными" свойствами NN6+/Moz в листинге 25.19. На странице, представленной этим листингом, отображаются значения во всех четырех системах координат. Чтобы нагляднее представить разницу между объектом на слое и объектом вне слоя, на страницу было добавлено два элемента, на которых можно щелкать. На рис. 25.1 показан результат щелчка на позиционируемом слое. В одном из полей указываются значения, в которых учитывается величина прокрутки документа в окне. Но, как нетрудно заметить, эти значения совпадают с другими значениями (группы page). Остальные поля представляют координаты в системе измерений, связанной с целевым элементом. Обратите внимание: если целевой элемент имеет свойство nodeType, равное text, то в вычислениях принимает участие родительский элемент текстового узла. L £Ht £4* 9«* fif X and Y Event Properties (NN6+) Click, on the button and in the DIVYimage to see the coordinate values for the event object. NN6 Mouse Event Coordinates: target: (<J^G> clientX, clientY: (140.354 layerX, layer У:|зг26 ...With scrolling: (140.365 pageX. pageY: (140.365 Withm Element: (140.365 screenX, screenY: |140.423 OtekHam I Ш0Ш ;- Wli Рис. 25.1. Координаты места щелчка в NN6+/Moz <html> <head> <title>X and Y Event Properties (NN6+)</title> <script type="text/javascript"> function checkCoords(evt) { 798 Часть III. Объекты документа
var form = document.forms["output"]; var targText, targElem; if (evt.target.nodeType ==3) { targText = "[textnode] inside <" + evt.target.parentNode.tagName + ">"; targElem = evt.target.parentNode; } else { targText = "<" + evt.target.tagName + ">"; targElem = evt.target; } form:srcElemTag.value = targText; form.clientCoords.value = evt.clientX + "," + evt.clientY; form.clientScrollCoords.value = (evt.clientX + window.scrolIX) + "," + (evt.clientY + window.scrollY); form.layerCoords.value = evt.layerX + "," + evt.layerY; form.pageCoords.value = evt.pageX + "," + evt.pageY; form.inElemCoords.value = (evt.pageX - targElem.offsetLeft - document.body.offsetLeft) + "," + (evt.pageY - targElem.offsetTop - document.body.offsetTop); form.screenCoords.value = evt.screenX + "," + evt.screenY; return false; } </script> </head> <body onmousedown="checkCoords(event)"> <hl>X and Y Event Properties (NN6+)</hl> <hr /> <p>Click on the button and in the DIV/image to see the coordinate values for the event object.</p> <form name="output"> <table> <tr> <td colspan="2">NN6 Mouse Event Coordinates:</td> </tr> <tr> <td align="right">target:</td> <td colspan="3"><input type="text" name="srcElemTag" size="25" /></td> </tr> <tr> <td align="right">clientX, clientY:</td> <tdxinput type="text" name="clientCoords" size="10" /></td> <td align="right">...With scrolling:</td> <tdxinput type="text" name="clientScrollCoords" size="10n /></td> </tr> <tr> <td align="right'^layerX, layerY:</td> <tdxinput type="text" name="layerCoords" size="10" /> </td> </tr> <tr> <td align="right">pageX, pageY:</td> <tdxinput type="text" name="pageCoords" size="10" /> </td> <td aligh="right">Within Element:</td> <tdxinput type="text" name="inElemCoords" size="10" /x/td> / Глава 25. Объекты событий 799
' </tr> <tr> <td align="right">screenX, screenY:</td> <tdxinput type="text" name="screenCoords" size="10" /></td> </tr> <tr> <td align="right"><input type="button" value="Click Here" /></td> </tr> </table> </form> <div id="display" style="position:relative; left:100"> <img alt«"image" src="nile.gif" width="320" height="240" border="0" /> </div> </body> </html> См. также: свойство target. currentTarget Значение: ссылка на объект элемента Только для чтения Совместимость: WinBE-, MacIE-, NN6+, Mozl+, Safari 1+ Приемник события может обрабатывать событие в процессе всплывания, поскольку оно проходит по строго определенному пути. Так как событию известна его цель, очень часто в функции приемника события необходимо указать, какой из объектов в данный момент обрабатывает событие. Свойство currentTarget задает ссылку на объект элемента, в котором приемник события выполняется в текущий момент. Это позволяет одной функции приемника потенциально обработать событие на различных уровнях, разветвляя код для согласования действий на разных уровнях, обрабатывающих событие. Зачастую в подобных операциях важно знание еще одного свойства события — event Phase. Оно помогает функции приемника события определить, в каком состоянии находится событие: в состоянии сбора данных, режиме всплывания или в цели. Это свойство демонстрируется в одном из следующих разделов. Пример В листинге 25.20 приведен пример практического применения свойства currentTarget. С его помощью определяется элемент, обрабатывающий событие в процессе его передачи. Подобно листингу 25.7, этот пример несколько упрощен, чтобы позволить свойствам объекта event выполнить большинство операций по обработке события. Получатели событий в различных режимах передачи настроены для самых различных узлов документа. После щелчка на кнопке каждый из них последовательно получает событие. В диалоговом окне отображается, какой из узлов в данный момент обрабатывает событие. Как и в листинге 25.7, свойство event Phase применяется для отображения режима передачи в процессе обработки события каждым узлом. Лжэтэдг 25Ж С»ойста currentTarget и eventPhaee - <html> <head> <title>currentTarget and eventPhase Properties</title> <script type="text/javascript"> 800 Часть III. Объекты документа
function init{) { // старый синтаксис обработки всплывающих событий document.onclick = processEvent; document.body.onelick = processEvent; // включениечобработки щелчков для документа и формы document.addEventListener("click", processEvent, true); document.forms[0].addEventListener("click", processEvent, true); // установка приемника события для формы document.forms[0].addEventListener("click", processEvent, false); } function processEvent(evt) { var currTargTag, msg; if (evt.currentTarget.nodeType ==1) { currTargTag = "<" + evt.currentTarget.tagName + ">"; } else { currTargTag = evt.currentTarget.nodeName; } msg = "Event is now at the " + currTargTag + " level "; msg += "(" + getPhase(evt) + ")."; alert(msg); } // определение режима обработки события function getPhase(evt) { switch (evt.eventPhase) { case 1: return "CAPTURING"; break; case 2: return "AT TARGET"; break; case 3: return "BUBBLING"; break; default: return ""; } } </script> </head> <body onload="init()"> <hl>currentTarget and eventPhase Properties</hl> <hr /> <form> <input type="button" value="A Button" name="mainl" onclick="processEvent(event)" /> </form> </body> </html> Вы можете щелкать не только на кнопке. Например, если вы наведете указатель на место справа от кнопки, то щелкнете на элементе form. Обработка события будет выполнена соответствующим образом. См. также: свойство eventPhase. Глава 25. Объекты событий 801
detail Значение: целочисленное Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safaril+ Свойство detail включено в W3C DOM как дополнительное, цель которого может быть определена создателем браузера. Теоретически целочисленное значение этого свойства может передавать дополнительную информацию о событии. Пока свойство присутствует только в объекте события NN6 (значения возвращаются далеко не для всех событий), оно не содержит никаких полезных данных, но может содержать их в будущем. evexitPhase Значение: целочисленное Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1 + Событие постоянно находится в одной из трех возможных фаз: сбор данных события, целевой объект или всплывание. Поскольку одна и та же функция приемника события может обрабатывать событие в нескольких фазах, в ней можно задать значение свойства event Phase объекта события для определения, в какой фазе событие находится при вызове функции. Это свойство имеет целочисленные значения — 1 (сбор данных), 2 (в целевом объекте) и 3 (всплывание). Пример Пример использования свойства eventPhase был приведен ранее в листинге 25.20. В нем применялась конструкция switch для выбора операторов обработки события, что зависело от фазы текущего события. См. также: свойство currentTarget. isChar Значение: булево Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Для каждого события клавиатуры можно определить, соответствует ли нажимаемая клавиша символу, изучая значение свойства isChar. Чаще всего для сбора данных о символьных и несимвольных клавишах используются обработчики событий, применяемые для захвата событий клавиатуры: onkeypress для клавиш символов; onkeydown или onkeyup для несимвольных клавиш. Свойство isChar возвращает несогласованные значения (даже для той же самой клавиши) в первом выпуске NN6. См. также: свойства charCode, keyCode. originalTarget Значение: ссылка на объект узла Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Это свойство содержит ссылку на объект узла, который выступает первой целью события. Возвращаемое значение зависит от внутренней структуры элементов. Во многих случаях оно равно значению свойства target. related/Target Значение: объект элемента Только для чтения Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ 802 Часть III. Объекты документа
Свойство relatedTarget позволяет выявить элементы, с которых наводится указатель мыши на текущий элемент, и на которые он сводится с текущего элемента. Это свойство расширяет возможности обработчиков событий onmouseover и onmouseout, распространяя их на соседние с текущим объекты. Данное свойство в NN6 выполняет те же задачи, что и свойства f romElement и toElement объекта event в IE4+. Когда событие onmouseover инициируется в элементе, указатель все еще находится в другом элементе. Свойство relatedTarget задает ссылку на этот элемент. Наоборот, когда возникает событие onmouseout, указатель уже расположен на другом элементе; свойство relatedTarget также задает ссылку на него. Пример Листинг 25.21 содержит пример использования свойства relatedTarget. С его помощью определяется расположение указателя до и после наведения его на центральный элемент. При наведении указателя на центральный элемент (ячейка таблицы) обработчик onmouseover отображает текст из ячейки, в которой указатель находился перед этим (свойство node Value текстового узла, расположенного в ячейке). Если же указатель переместился в центр из угла таблицы (нелегкая задача), то отображается специальное сообщение. Две функции, которые выводят результат, выполняют дополнительную проверку: они обрабатывают объект события только в случае возникновения его в элементе и если элемент relatedTarget отличный от вложенного текстового узла центральной ячейки таблицы. <html> <head> <title>relatedTarget Properties</title> <style type="text/css"> .direction {background-color:#00FFFF; width:100; height:50; text-align:center) #main {background-color:#FF6666; text-align:center} </style> <script type="text/javascript"> function showArrival(evt) { if (evt.target.nodeType ==1) { if (evt.relatedTarget != evt.target.firstChild) { var direction = (evt.relatedTarget.firstChild) ? evt. relatedTarget. firstChild. nodeVa^lue : "parts unknown"; window.status = "Arrived from: " + direction; function showDeparture(evt) { if (evt.target.nodeType ==1) { if (evt.relatedTarget != evt.target.firstChild) { var direction = (evt.relatedTarget.firstChild) ? evt.relatedTarget.firstChild.nodeValue : "parts unknown"; window.status = "Departed to: ,f + direction; </script> </head> Глава 25. Объекты событий
<body> <hl>relatedTarget Properties</hl> <hr /> <p>Roll. the mouse to the center box and look for arrival information in the status bar. Roll the mouse away from the center box and look for departure information in the status bar.</p> <table cellspacing="0" cellpadding="5"> <tr> <tdx/td> <td class=udirection">North</td> <td></td> </tr> <tr> <td class="direction">West</td> <td id=MmainM onmouseover="showArrival(event)" onmouseout="showDeparture(event)">Roll</td> <td class="direction">East</td> </tr> <tr> <tdx/td> <td class=Mdirection">South</td> <tdx/td> </tr> </table> </body> </html> См, также: свойство target. target Значение: ссылка на объект элемента Только для чтения Совместимость: WinlE-, МасГЕ-, NN6+, Mozl+, Safari 1+ Свойство target — ссылка на объект элемента HTML, который является первоначальной целью события. Событие может передаваться вниз и всплывать вверх по иерархии объектов, обрабатываясь в процессе продвижения на любом уровне структуры. При этом событие имеет свойство, указывающее на элемент, от которого происходит инициированное событие. При наличии ссылки на этот элемент можно получать и изменять его свойства или вызывать любые методы. Пример В качестве простейшего примера возможностей свойства target приведем листинг 25.22. В нем в элементе body настроено два обработчика события, каждый из которых вызывает отдельную функцию. Идея сценария очень проста: события onmousedown и onmouseup всплывают независимо от целевого элемента, а функции определяют последние и изменяют их цвет стиля. В каждой функции проверяется свойство className целевого элемента. Если это свойство имеет значение bold (имя класса общее для всех трех элементов span абзаца), то правило таблицы стилей для этого класса изменяется. В собственных сценариях вы можете задать более сложные операции форматирования документа. Обратите внимание, что сценарий может ничего и не "знать" об объектах страницы, чтобы правильно обратиться к ним— свойство srcElement предоставляет всю необходимую информацию о целевом элементе. 804 Часть III. Объекты документа
<html> <head> <title>target Property</title> <style type="text/ess"> .bold (font-weight:bold} .ital {font-style:italic} </style> <script type=ntext/javascriptM> function highlight(evt) { var elem * (evt.target.nodeType ==3) ? evt.target.parentNode : evt.target; if (elem.className == "bold") { document.stylesheets[0].cssRules[0].style.color = "red"; } else { elem.style.color = "#FFCC00"; function restore(evt) { var elem = (evt.target.nodeType ==3) ? evt.target.parentNode : evt.target; if (elem.className == "bold") { document.stylesheets[0].cssRules[0].style.color = "black"; } else { elem.style.color = "black"; } } </script> </head> <body onmousedown="highlight(event)" onmouseup="restore(event)"> <hl>target Property</hl> <hr /> <p>One event handler...</p> <ul> <li>Can</li> <li>Cover</li> <li>Many</li> <li>Objects</li> </ul> <p>Lorem ipsum dolor sit amet, consectetaur adipisicing elit, <span class="bold">sed do</span> eiusmod tempor incididunt <span class=Mital">ut labore et</span> dolore magna aliqua. Ut enim adminim veniam, <span class="bold">quis nostrud exercitation</span> ullamco laboris nisi ut aliquip ex ea <span class="bold">commodo consequat</span>.</p> </body> </html> См. также: свойство relatedTarget. times tamp Значение: целочисленное Только для чтения Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari 1+ Каждое событие имеет временную отметку, заданную в миллисекундах относительно даты начала отсчета в JavaScript, — 1 января 1970 года. Также, как с объектом Date, точность полученного времени полностью зависит от точности системных часов компьютера пользователя. Глава 25. Объекты событий 805
Точное время возникновения события может быть ценно только в некоторых ситуациях, а время между определенными событиями часто используется в приложениях решения задач на время или в играх в жанре экшн. Время возникновения последнего события можно сохранить в глобальной переменной; сравните его с текущей временной меткой последующих событий, чтобы определить разницу между ними. Пример В листинге 25.23 приведен пример использования свойства timeStamp. С его помощью вычисляется скорость ввода текста в области text area. Вычисления существенно упрощены, поэтому они не учитывают длительных задержек и пауз, которые часто случаются при вводе больших текстовых фрагментов. Более того, полученное значение округляется к ближайшему целому, Лжггинг 25.23, Свойство tiaestanqp <html> <head> <title>timeStamp Property</title> <script type="text/javascript"> var stamp; function calcSpeed(evt) { if (stamp) { var gross = evt.timeStamp - stamp; var wpm = Math.round(6000/gross); document.getElementByld("wpm").firstChild.nodeValue = wpm + " wpm."; } stamp = evt.timeStamp; } </script> </head> <body> <hl>timeStamp Property</hl> <hr /> <p>Start typing, and watch your instantaneous typing speed below:</p> <pxtextarea cols="60" rows="10" wrap="hard" onkeypress=McalcSpeed(event)"></textareax/p> • <p>Typing Speed: <span id="wpm">&#160; </spanx/p> </body> </html> См. также: объект Dat<s. type Значение: строка Только для чтения Совместимость: WinlE-, Mac IE-, NN6+, Mozl+, Safari 1+ Выяснить, какой тип события был инициирован для создания определенного объекта события, можно, используя свойство type. Его значение — строковая версия имени события — только имя события не имеет префикса on, который обычно связывают с именами приемника события в NN6. Это свойство может быть полезно, когда для обработки различных видов событий используют всего одну функцию. Например, обработчики событий 806 Часть III. Объекты документа
onmousedown и onclick объекта могут вызывать одну функцию. Внутри функции ветвление задается в зависимости от типа события— mousedown или click— с соответствующей обработкой каждого типа. Вам не обязательно задавать совместное управление событиями, но знание о возможности организации подобной конструкции в сценариях весьма полезно. Это свойство и его значения полностью совместимы с моделями событий в NN4 и Ш4+. ^ Ш% События клавиатуры в Safari 1.0 распознаются как khtmljceydown, khtmljceypress fimijrrifet n.khtmi_keyup. Префикс в названиях типов представляет программное ядро, на #'::??У%, основе которого создавался этот браузер, Подобное именование полностью co- pi ответствует стандартам еще незавершенной спецификации W3C DOM 3. См. также: все обработчики события (глава 15). view Значение: ссылка на объект window Только для чтения Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Чем ближе объектная модель W3C DOM 2 к объектным моделям браузеров, тем сильнее ощущается необходимость в специальном объекте, называемом объектом абстрактного вида (класс Abstract View). Единственное свойство этого объекта (ссылка на содержащийся в нем документ) корневой узел уже знакомого документа. Пользовательские события всегда происходят в пределах этого объекта, что отражено в свойстве view объекта event. В NN6 оно возвращает ссылку на объект window (может иметь многоуровневую структуру), в котором происходит событие. Эта ссылка позволяет объекту события быть переданной сценариям других структур, а эти сценарии могут получить доступ к объекту document окна целевого элемента. См. также: объект window. Методы initEvent(eventType, bubbleFlag# cancelableFlag) initKeyEvent(eventType, bubbleFlag, cancelableFlag/ view, ctrlKeyFlag, altKeyFlag, shiftKeyFlag, metaKeyFlag, keyCode , charCode) initMouseEvent(eventType, bubbleFlag, cancelableFlag, view, detailVal, screenX, screenY, clientX, clientY, ctrlKeyFlag, a11KeyF1ag, shi £ tKeyF1ag, me taKeyF1ag, buttonCode, relatedTargetNodeRef) initMutationEvent(eventType, bubbleFlag, cancelableFlag, relatedNoderef, prevValue, newValue, attrName, attrChangeCode) initUIEvent(eventType, bubbleFlag, cancelableFlag, view, detailVal) Возвращаемое значение: отсутствует. Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safaril+ Глава 25. Объекты событий 807
Методы инициализации объектов в W3C DOM предполагают назначение только что созданному событию всего набора свойств, характерных для него. Аргументы каждого метода инициализации зависят от типа создаваемого события. Тем не менее, все методы инициализации имеют три основных аргумента: eventType, bubbleFlag, cancelableFlag. Первый параметр имеет строковое значение и определяет тип события, например "mousedown" или "keypress". Атрибут bubble Flag является булевым значением, которое указывает на реализацию всплывания события (true) или отказ от всплывания (false). Третий аргумент также представляет собой булево значение, которое указывает на предотвращение или реализацию действия события по умолчанию. Отдельные методы содержат аргументы view и detailVal. Первый соответствует окну или фрейму, в котором событие происходит, второй аргумент принимает целочисленный код, связанный с данными конкретного события. Вам совсем не обязательно использовать сложные методы, если вы настраиваете простое событие. Например, если требуется настроить событие mouseup, то можете инициализировать его с помощью общего метода initEvent (), а затем связать это событие с конкретным элементом, не указывая сведения о координатах, кнопках и других характеристиках события в методе initMouseEvent (). var evt = document.createEvent("MouseEvents"); evt.initEvent("mouseup", true, true); document.getElementById("myButton").dispatchEvent(evt); См. также: метод document. createEvent (). preventDefault() Возвращаемое значение: отсутствует. Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari 1+ NN6+ продолжает следовать первоначальному способу предотвращения поведения по умолчанию обработчика события (т.е. задавать в качестве последнего оператора обработчика события return false). В то же время модель событий NN6+ предоставляет метод, который позволяет аннулировать действия по умолчанию, полностью происходящие в пределах вызванной обработчиком события функции. Например, рассмотрим текстовое поле, которое, как предполагается, в своих пределах позволяет вводить только числа. Обработчик события onkeypress может вызывать функцию, которая рассматривает каждый введенный символ. Если символ не цифра, то он не отображается в текстовом поле, просто не достигая его. Следующая функция проверки правильности вызывается в обработчике события onkeypress описанного ниже текстового поля. function checklt (evt) { '*~ var charCode = evt.charCode; if (charCode < 48 | charCode > 57) { alert("Please make sure entries are numbers only"); evt.preventDefault(); } } Таким образом, ошибочный символ не будет добавлен в текстовое поле. Вызов метода preventDef ault О в NN6+/Moz/Safari эквивалентен присвоению свойству event. re turn Value значения true в Ш5+.' См. также: свойство cancelable. 808 Часть III. Объекты документа
stopPropagation() Возвращаемое значение: отсутствует. Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safaril+ Используйте метод stopPropagationO, чтобы не допустить продвижения события вниз или всплывания вверх по иерархии элементов. В функции приемника события метод вызывается следующим образом. evt.stopPropagation(); Альтернативным методом является задание отмены всплывания непосредственно в атрибуте обработчика события элемента. onclick="doButtonClick(this); event.stopPropagation()"; При написании межбраузерных сценариев также используются значения свойства cancelBubble, совместимого с Ш4+. См. также: свойства bubbles, cancelBubble. Глава 25. Объекты событий 809
Таблица стилей и объекты стилей Полную поддержку таблицы стилей получили только с появлением браузеров версии 4 (браузеры ШЗ частично поддерживали таблицы стилей). В настоящее время страницы Всемирной сети содержат большой объем информации и при этом подлежат постоянному изменению, поэтому таблицы стилей применяются очень часто. С помощью таблиц стилей Web-разработчик получает возможность разграничить содержимое страницы и элементы, подлежащие изменению. Текстовая информация может поступать из различных электронных источников. Разместить ее зачастую необходимо в разном контексте. Например: блок последних новостей поступает на многочисленные Web-узлы портала, при этом каждый узел имеет свой унифицированный вид. Задача Web-дизайнера— определить, каким образом информация будет отображаться на Web-странице. Таблицы стилей помогают решать различные задачи. Например, крупному корпоративному Web-узлу необходимо придать унифицированный вид с помощью характерного стиля. Семейство таблиц стилей может определить тип шрифта и его размер, вид выделенного текста и ширину полей всего текста Web-узла. Применять эти стили к каждому элементу в отдельности довольно трудно и даже рискованно — если в коде одной из страниц дескрипторы стиля пропущены, унифицированный вид всего Web-узла будет нарушен. Более того, если требования корпоративного дизайна Web-узлов изменятся и вам придется изменять, например, тип шрифта, операция замены стилей в каждом дескрипторе даже при использовании функции "найти и заменить" станет очень непростой задачей. Если же информация об используемых стилях будет содержаться во внешнем файле таблицы стилей, Web-дизайнер сможет внести все необходимые изменения только в этот файл. В результате вид всего Web-узла будет изменен быстро и просто. В этой книге мы не рассматриваем способы создания и применения таблиц стилей. Данная глава рассчитана на тех читателей, которые уже знакомы с терминами, используе-
мыми при работе с таблицами стилей (например, правило и селектор таблицы стилей). Если эти термины вам пока не знакомы, всю необходимую информацию вы сможете найти в учебных пособиях и на специализированных Web-страницах. Браузеры Internet Explorer и Netscape Navigator достаточно строго придерживаются стандартов W3C для таблиц стилей (называемых Cascading Style Sheets — каскадные таблицы стилей — CSS). Всю дополнительную информацию рекомендуется искать в независимых источниках. В частности, Microsoft дополняет словарь несколькими терминами, которые употребляются лишь при использовании браузеров ГЕ4+ для Windows. Поэтому, если вы создаете приложение, рассчитанное не только на эту модель браузеров и операционную систему, то вам следует привести целый ряд характеристик каскадных таблиц к общему знаменателю. В этой главе рассматриваются все версии. Особое внимание следует уделить листингам совместимости для каждого элемента. И последнее замечание, касающееся совместимости: несмотря на то, что NN4 предоставляет возможность использования многих средств CSS, таблицы стилей и правила стилей в NN4 не представлены в качестве объектов. Некоторые стили непосредственно связаны со статической природой страницы NN4. Поскольку браузер не может переформатировать страницу в ответ на'изменения, стили уже загруженного содержимого Web-страницы просто не могут быть изменены. В NN6+/Mozl+ страница может быть свободно переформатирована, а все, что задается стилями, представлено в виде модели объекта. Имена объектов Сначала необходимо разобраться в терминах, относящихся к объектам таблиц стилей, с которыми вам предстоит работать. Иногда значения этих терминов частично совпадают. Некоторые объекты абстрактны по сравнению с другими, но они, тем не менее, важны. Мы рассмотрим следующие из них. ■ Объект элемента стиля (s ty 1 е). ■ Объект stylesheet (элемент массива stylesheets). ■ Правило или объект cssRule (элемент массивов rules или ess Rules). ■ Объект style. Объект элемента style соответствует дескриптору <style> документа. Многие свойства этот объект унаследовал от объектов обычных элементов HTML, рассмотренных в главе 15. Пока объект элемента style имеет свойство disabled (отключенный), вы не сможете получить доступ к таблицам стилей с помощью объекта style. Таблица стилей вкладывается в документ с помощью дескриптора <style> или связывается с документом посредством дескриптора <link>. Объект document обладает свойством stylesheets, которое позволяет активизировать массив (совокупность) всех задействованных в текущем документе объектов stylesheet, независимо от того, были они подключены или нет. Несмотря на то, что дескриптор <style> содержит строки кода, составляющие правила таблиц стилей, объект элемента style не используется для получения доступа к индивидуальным правилам. Для этой цели задается объект stylesheet. С помощью этого объекта можно подключать или отключать всю таблицу, получать доступ к отдельным правилам (используя массив свойств rules или ess Rules), а также добавлять или удалять правила для данной таблицы стилей. В основе каждой таблицы стилей — правила, определяющие, как элементы должны отображаться. На уровне объектов термины, применяемые для IE4+ и NN6, отличаются. В модели объекта ГЕ4+ каждое правило таблицы стилей называется объектом правила. NN6+/Moz, следуя стандарту W3C DOM 2, называет каждое правило объектом правила каскадных таблиц стилей. Глава 2В. Таблица стилей и объекты стилей 811
Ш5 для Macintosh и Safari принимает оба варианта обозначения одного и того же объекта. Несмотря на разные имена, объекты имеют общие основные имена свойств. Чтобы обратиться к правилу, необходимо задать целый массив ссылок. Например, ссылка на первое правило первого объекта stylesheet документа для двух типов браузеров будет выглядеть следующим образом. var oneRule = document .stylesheets [0 ] .rules [0] IE4+, MaclE5, Safari var oneRule = document .stylesheets [0] .cssRules [0] MaclE5, NN6+/M0Z, Safari Последний объект из группы объектов, относящихся к стилям, — это объект style. Данный объект — основа, в которой определены все стили. В предыдущих главах были приведены примеры того, как можно изменить одно или несколько свойств style-элемента. Чаще всего изменения осуществляются с помощью свойства style элемента HTML. Например, вы можете задать цвет шрифта элемента span, идентификатор которого равен hot, следующим образом. document.all.hot.style.color = "red" IE4+ document.getElementByld("hot").style.color = "red" IE5+, W3C Объект style также является свойством объекта rule/cssRule. Таким образом, если вы хотите изменить стиль элементов, находящихся под влиянием существующего правила таблиц стилей, получить доступ к объекту style можно разными способами, однако работать с этим объектом следует так же, как и с любыми другими элементами. document, stylesheets [0] .rules [0] .style, color = "red" IE4+, MaclE5, Safari document .stylesheets [0] .cssRules [0] .style, color = "red" MaclE5, NN6+/ Moz, Safari Многие Web-дизайнеры работают только с объектом style, поэтому он обычно ассоциируется с объектом определенного элемента. Управлять объектами stylesheet приходится редко, кроме тех случаев, когда их нужно активизировать или отключить в сценарии. Поэтому, если вы до сих пор знакомы не со всеми этими объектами, особое внимание уделите объекту style. Импортированные таблицы стилей Таблицы стилей, вложенные в документ посредством элемента style, могут импортировать дополнительные таблицы с помощью селектора ©import. <style type="text/ess"> ©import url(externalStyle.css); p {font-size:16pt} </style> В этом сценарии документ "видит" только один объект stylesheet. В такой объект вложена таблица стилей, содержащаяся во внешнем файле. Ш4+ называет одну из этих импортированных таблиц стилей объектом import. Объект import обладает всеми характеристиками объекта stylesheet, но его свойство parentStyle является ссылкой на stylesheet, который "владеет'* правилом ©import. Оператор ©import отсутствует в совокупности правил объекта stylesheet в Ш. Следовательно, для получения доступа к первому правилу импортированной таблицы стилей следует задать такую ссылку. document. styleSheets*[0] . imports [0] .rules [0] W3C DOM и NN6+/Moz трактуют объекты правила import иначе, чем IE. В соответствии со стандартами W3C DOM даже импортированное правило считается элементом совокупности cssRules объекта stylesheet. Одним из свойств объекта cssRules является type. Это свойство служит для выражения целого значения кода. С его помощью можно определить, относится ли текущее правило к CSS или принадлежит к другому типу правил, 812 Часть ///. Объекты документа
включая правило import. Разумеется, импортированный объект правила в качестве одного из свойств имеет объект stylesheet, который, в свою очередь, содержит правила, определенны во внешнем файле таблицы стилей. Здесь также имеют место родительско-дочерние отношения, в то время, как к свойству parentStyle импортированного объекта обращаются с помощью ссылки на свойство parentStyle объекта stylesheet (как и в ГЕ4+). Получение свойств стиля Объектные модели ГЕ4+ и NN6 (W3C) обладают одной и той же характерной особенностью поведения, которая может поначалу сбить вас с толку. С одной стороны, стандарты W3C и практика работы в HTML предлагают определять стили удаленно (т.е. подключать их с помощью дескрипторов <style> и <link>), а не задать значения атрибута style дескриптору каждого элемента документа. Это соответствует тенденции отделения стилей от содержимого. С другой стороны, объектные модели могут быть очень коварны. Если объект элемента представляет свойство, отражающее атрибут дескриптора этого элемента в тот момент, когда программа впервые пытается прочесть это свойство, значение будет соотноситься с этим свойством только в том случае, если атрибут явно задан в коде HTML. Если же вы подключаете удаленную таблицу стилей, то значения не будут представлены в дескрипторе в явном виде. Следовательно, свойство style такого элемента оказывается пустым, даже несмотря на то, что стиль данного элемента находится под контролем удаленной таблицы стилей. Проблем не возникнет, если вы должны лишь задать новое значение свойства style, поскольку определенное вами значение свойства style объекта элемента аннулирует любой стиль, назначенный этому свойству в удаленной таблице стилей (это новое значение содержится в свойстве style). Но если вы решили получить текущие настройки, то исходное значение не будет представлено в объекте style данного элемента. К счастью, в Ш5+ появилось дополнительное свойство, доступное только для чтения, — current Style. Оно позволяет увидеть значения таблицы стилей, которые в данный момент применена к элементу, независимо от того, где расположены определения таблицы стилей. Свойство current Style выдает объект, который обладает тем же форматом и свойствами, что и обычное свойство style. Если ваша Web-страница рассчитана на аудиторию, использующую браузеры IE5 и более современные, вам следует ознакомиться со стилями элемента с помощью свойства current Style. Чтобы изменить свойство стиля объекта только для одного элемента, используйте свойство style. Но если изменения касаются всех элементов, стиль которых контролируется одним удаленным правилом таблиц стилей, эти изменения следует внести в свойство style объекта правила. В W3C DOM решение представлено в виде метода getComputedStyle (). Чтобы получить значение определенного свойства стиля, примененного к элементу, сначала следует получить значение вычисляемого стиля (computed style) для указанного элемента, а затем определить необходимое свойство CSS-стиля. Например, для получения значения свойства стиля font-family, примененного к элементу с идентификатором туР, выполните следующие операторы. var elem = document .getElementById("myP") ; var computedStyle = window.getComputedStyle(elem, ""); var fontFam = computedStyle.getPropertyValue("font-family"); Учтите, что вы должны использовать имя свойства CSS-стиля (например, font-family), а не его сценарный эквивалент (например, font Family). К сожалению, Safari 1.0 не поддерживает метод getComputedStyle (), а потому не позволяет получить значения свойств стилей, заданных вне атрибутов элементов. Глава 26. Таблица стилей и объекты стилей 813
Объект элемента style Свойства, методы и обработчики этого объекта описаны в главе 15. Свойства Методы Обработчики событий media type Синтаксис Доступ к объекту и методам элемента style. (IE4+) document. all. идентификатор. свойство /метод ( [параметры] ) (IE5+/W3C) document.getElementById {идентификатор) . свойство/метод( [параметры] ) Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Описание объекта Элемент style является одним из объектов указания (см. главу 36). Этот элемент располагается в разделе head документа, а его содержимое не отображается на Web-странице. Содержимое элемента style существенно влияет на то, каким образом будут отображаться остальные элементы страницы. Большинство свойств, методов и обработчиков событий, которые унаследованы элементом style от элементов HTML, существенной роли в управлении документом не играют. Однако есть одно исключение — булево (логическое) свойство disabled. Существует несколько способов деактивизации таблицы стилей (свойство disabled объекта stylesheet), однако для подключения и отключения таблицы стилей удобнее всего использовать объект элемента STYLE. Этому элементу вы можете назначить идентификатор и явно ссылаться на него. Следовательно, вам будет проще использовать его свойства, чем пытаться определить, какой именно объект stylesheet из массива stylesheets документа необходимо использовать в каждой конкретной ситуации. Свойства media Значение: строка Чтение/Запись Совместимость: WinIE4+, MacBE4+, NN6+, Mozl+, Safari 1+ Свойство media представляет атрибут media элемента style. Этот атрибут определяет тип устройства вывода, соответствующего назначению текущей таблицы стилей. В спецификации к HTML 4.0 этому атрибуту приписывается целый ряд значений. Однако браузеры в большинстве случаев используют следующие значения: screen, print и all. Таким образом вы можете создать один набор стилей для отображения страницы на экране, а второй — для печати документа. 814 Часть ///. Объекты документа
Чтение/Запись type Значение: строка Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство type представляет атрибут type элемента style. Для таблиц стилей CSS это свойство всегда имеет значение text /ess. Но если в сценарии данному свойству присвоить другое значение, то браузер не будет поддерживать этот тип таблиц стилей, таблица стилей перестанет восприниматься как CSS, а все стили, задаваемые этой таблицей, будут заменены на исходные стили по умолчанию. Объект stylesheet Свойства Методы Обработчики событий cssRules cssText disabled href id imports media ownerNode ownerRule owningElement pages parentStylesheet readonly rules. title type addlmport() addRule() deleteRule() insertRule() removeRule 0 Синтаксис Доступ к свойствам и методам объекта stylesheet. (IE4+/W3C) document. stylesheets [индекс] . свойство /метод ( [параметры] ) Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safaril+ Описание объекта Если объект элемента style— это точное воплощение таблицы стилей, то объект stylesheet — это ее абстрактный эквивалент* Объект stylesheet существует на основе определения таблицы стилей, вложенного в текущий документ с помощью дескриптора <style> или присоединенного из внешнего файла с помощью дескриптора <link>. Каждый Глава 26. Таблица стилей и объекты стилей 815
элемент, который вводит таблицу стилей в текущий документ, создает свой собственный объект stylesheet. Доступ к объекту stylesheet осуществляется с помощью массива document. stylesheets. Если определение таблицы стилей в документе отсутствует, массив имеет нулевую длину. Стили, которые были применены к документу с помощью атрибута элемента STYLE, не являются объектами stylesheet. Объекты stylesheet присутствуют как в Ш4+, так и в W3C DOM. Более того, в браузерах обоих типов значение этого объекта одинаково. Однако во многих случаях свойства и методы значительно отличаются. Зачастую объекты несут одну и ту же информацию, но эта информация передается с помощью свойств, имена которых отличаются в этих двух различных типах браузеров. Интересным является тот факт, что для некоторых особо важных свойств (например, тех, которые возвращают массив правил стилей и обращаются к элементу HTML, ответственному за таблицы стилей текущего документа) МасШ5+ и Safari поддерживает терминологию Microsoft и W3C. Методы этого объекта направлены, в основном, на добавление и удаление правил из таблицы стилей. Таким образом, объект stylesheet используется в качестве шлюза к отдельным правилам (заданным массивом rules или cssRules). Свойства cssRules Значение: массив объектов правил Только для чтения Совместимость: WinlE-, МасШ5, NN6+, Mozl+, Safari 1+ Свойство cssRules возвращает массив объектов правил таблицы стилей. В терминологии W3C DOM это объекты cssRule. Данное свойство присутствует в ГЕ5+ для Мае, но его нет в версии для Windows, например в Ш6. Список объектов правил приведен в порядке представления их в исходном коде. Соответствующее свойство WinEE4+ — rules. Пример Используйте приложение The Evaluator (глава 13) для изучения свойства cssRule в браузерах W3C DOM и МасШ5. Сначала узнайте, сколько правил определено в первом объекте stylesheet страницы, введя в верхнее текстовое поле следующее выражение, document.stylesheets[0].cssRules.length Далее используйте массив, чтобы получить доступ к отдельным объектам правил и их свойствам. Введите в нижнее текстовое поле такое выражение, document.stylesheets[0].cssRules[1] Используйте этот синтаксис для изменения правил стилей, заданных в объекте stylesheet. См. также: свойство rules; объекты cssRule и rule. cssText Значение: строка Чтение/Запись Совместимость: Winffi5+, Macffi5, NN-, Moz-, Safari- Свойство cssText содержит строку правил таблицы стилей, заключенных в объекте stylesheet. Анализировать этот текст, чтобы найти определенные строки, не имеет смысла, поскольку в тексте, возвращенном с помощью этого свойства, могут присутствовать символы возврата каретки и другие элементы форматирования, которые не имеют места в тексте, заданном в правилах таблицы стилей в явном виде. Вы, конечно, можете использовать данное свойство, чтобы полностью переписать правила таблицы стилей прямым методом: скомпоновать 816 Часть III. Объекты документа
строку, состоящую из новых правил, и назначить эту строку свойству cssText. Формальный способ изменения правил (добавление и удаление) предпочтителен, но вы можете использовать свойство cssText, если рассчитываете только на пользователей Ш5+. Пример Приложение The Evaluator также можно использовать для замены всех правил стиля с помощью свойства cssText. Начните с изучения значения, возвращаемого свойством cssText исходно отключенной таблицы стилей. Для этого введите в верхнее текстовое поле следующее выражение. document.stylesheets[0].cssText Далее подключите таблицу стилей, чтобы применить ее правила в документе. document.stylesheets[0].disabled = false Наконец, введите приведенное ниже выражение в верхнее текстовое поле приложения, чтобы заменить существующие правила таблицы стилей абсолютно новыми. document.stylesheets[0].cssText = "p {color:red}" Перезагрузите страницу, если хотите вернуться к исходным правилам таблицы стилей. См. также: методы addRulq (), deleteRule (), insertRule () и removeRule. disabled Значение: булево Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Свойство disabled объекта элемента style характерно только для элемента, однако свойство disabled объекта stylesheet применимо также и к объекту stylesheet, который присоединен к документу с помощью элемента link. Активизация и отключение таблиц стилей— это один из способов изменения стилей Web-страницы, позволяющий пользователю указать необходимое форматирование. Web- страница может иметь большое количество таблиц стилей, контролирующих одни и те же элементы, однако сценарий имеет возможность подключить одну из таблиц и отключить другую, чтобы изменить стиль страницы в целом. Указанная операция выполняется с помощью обработчика событий onload. Например, у вас есть отдельные таблицы стилей для браузеров Windows и Мае. Вы можете добавить эти таблицы в документ в отключенном исходном состоянии. Обработчик событий onload определяет операционную систему и активизирует таблицу стилей, предназначенную исключительно для нее. Если ваши таблицы стилей имеют не очень большой объем, их вставка для разных операционных систем не окажет значительного влияния на время загрузки документа. Пример Приложение The Evaluator может подключать и отключать первый объект stylesheet страницы. Введите в верхнее текстовое поле следующее выражение. document.stylesheets[0].disabled = (!document.stylesheets[0].disabled) Включение в это выражение оператора отрицания (!), приведет к изменению текущего состояния на противоположное. Таким образом, при щелчке на кнопке Evaluate значение true свойства disabled будет заменено на значение false; и наоборот, значение false изменится на значение true. См. также: свойство disabled объекта элемента style. Глава 26. Таблица стилей и объекты стилей 817
href Значение: строка Чтение/Запись (см. текст) Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Если таблица стилей присоединяется к документу с помощью элемента link, свойство href объекта stylesheet содержит строку с URL соответствующего файла. Таким образом, свойство href элемента link передается в объект stylesheet, который определяет результат присоединения стилей. В IE4+ для Windows это свойство доступно для чтения и записи, что позволяет динамично присоединять внешний файл таблицы стилей после того, как Web-страница уже загружена. В МасШ и NN6+/Moz это свойство доступно Только для чтения. См. также: объект элемента link. id Значение: строка Только для чтения Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Свойство id объекта stylesheet наследует свойство id содержащегося в объекте его элемента-контейнера (style или link). Такое обстоятельство вызывает некоторые трудности, поскольку кажется, что два объекта имеют одинаковый идентификатор. Однако это не так: id может служить индексом массива document .stylesheets в IE4+ (например, document. stylesheets [ "winLINK" ]); в NN6 подобного идентификатора, который был бы связан с объектом stylesheet, нет. См. также: свойство id объектов всех элементов. imports Значение: массив объектов stylesheet Только для чтения Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Таблица стилей может содержать одно или более правил ©import для импортирования внешнего файла таблицы стилей в документ. Каждый импортированный объект stylesheet считается объектом import. Свойство imports представляет собой массив всех импортированных объектов stylesheet, принадлежащих текущему объекту stylesheet. Импортированные таблицы стилей не добавляются в массив document .stylesheets, поэтому ссылки на импортированные объекты должны задаваться с помощью массива document.stylesheets[i] .imports[i], Объект import является объектом stylesheet. Поэтому все свойства и методы, примененные к объекту stylesheet, могут применятся и к объекту import. Следовательно, если вы хотите загрузить на Web-страницу другую таблицу стилей, новый URL вы сможете задать в свойстве href импортированного объекта stylesheet. document.stylesheets[0].imports[0].href = "alternate.ess"; Такие операции могут быть проведены в Winffi, но не в МасШ. См. также: объект stylesheet. media Значение: см. текст '" Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safaril+ Таблицы стилей CSS могут применяться для работы с такими видами устройств вывода, как экран монитора, принтер, а в будущем — со специальными устройствами обработки человеческой 818 Часть III. Объекты документа
речи и генераторами Брайля. Такую возможность предоставляет атрибут media элементов style или link. Его значение представлено в свойстве media объекта stylesheet. В ГО4+ значение свойства media представляет собой строку с одним из трех возможных значений: screen, printer или all. W3C DOM и NN6+ позволяет определить атрибуту media множественные значения. Значение в NN6+/Moz/Safari представляет собой массив строк с названиями определенных устройств вывода. ownerNode Значение: ссылка на узел Только для чтения Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safari 1+ Свойство ownerNode представляет собой ссылку на узел документа, в котором определен объект stylesheet. Для тех объектов stylesheet, которые определены в элементах style и link, свойство ownerNode служит для ссылки на этот элемент. Соответствующее свойство в Ш4+ называется owningElement. Отметим также, что в системе Macffi5 существует дополнительное свойство owningNode, имя которого несколько отличается, а значение совпадает со значением свойства owningElement. Пример Приложение The Evaluator можно запустить в NN6+/Mozl+/Safari для изучения свойства ownerNode первого объекта stylesheet документа. Введите в верхнее текстовое поле следующее выражение. document.stylesheets[0].ownerNode.tagName См. также: свойства ownerRule и owningElement. ownerRule Значение: объект с s s Ru 1 е Только для чтения Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safaril+ Свойство ownerRule применяется по отношению к объекту stylesheet, который был импортирован в документ с помощью правила ©import. Это свойство возвращает ссылку на правило ©import, отвечающее за загрузку внешней таблицы стилей. Между свойствами ownerRule и ownerNode существует взаимосвязь, которая заключается в том, что импортированное правило имеет свойство ownerRule, а значение его свойства ownerNode равно null; и наоборот, обычный stylesheet имеет значение ownerNode, а значение его свойства ownerRule равно null. Следует отметить, что в NN6 импортированные таблицы стилей не считаются объектами, поэтому данное свойство в NN пока не поддерживается. См. также: свойство ownerNode. owningElement Значение: ссылка на элемент Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство owningElement представляет собой ссылку на объект элемента, в котором определен объект stylesheet. Для тех объектов stylesheet, которые определены в элементах style и link, свойство owningElement служит для ссылки на последние. Соответствующее свойство в NN6+ называется ownerNode. В системе Мас1Е5 существует дополнительное свойство owningNode, имя которого несколько отличается, а значение совпадает со значением свойства owningElement. Глава 26. Таблица стилей и объекты стилей 819
Пример В приложении The Evaluator, запущенном в Ш4+, можно быстро ознакомиться с возможностями свойства owningElement первого объекта stylesheet. Введите в верхнее текстовое поле следующее выражение. document.stylesheets[0].owningElement.tagName Этот оператор возвращает имя style дескриптора элемента. См. также: свойство ownerNode. pages Значение: массив правил ©page Только для чтения Совместимость: Winffi5.5+, МасШ-, NN-, Moz-, Safari- Правило стиля ©page определяет размеры и ширину полей напечатанной версии Web- страницы. Свойство pages возвращает массив правил ©page, содержащихся в текущем объекте stylesheet. Если в таблице стилей не определено ни одно правило ©page, длина массива будет равна нулю. Кроме свойств, характерных для всех объектов правил, правило ©page имеет одно дополнительное свойство, доступное Только для чтения. Это свойство — pseudoClass, которое возвращает все определения псевдоклассов в этом правиле. Например, приведенные ниже правила определяют разные конфигурации левого и правого полей страниц при печати. ©page :left {margin-left :4cm; margin-right :3cm;} ©page :right {margin-left:3cm; margin-right :4cm;} Значения свойства pseudoClass правил для каждой из двух страниц — : left и : right соответственно. Согласно стандартам W3C DOM, правило ©page — это всего лишь один из объектов правил, свойство type которого возвращает page. Более подробную информацию об этом свойстве вы найдете по адресу. http://www.w3.org/TR/REC-CSS2/page.html. parentStyleSheet Значение: объект stylesheet Только для чтения Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Импортированная таблица стилей отображается благодаря главному объекту stylesheet, заданному с помощью элементов style или link. Ссылка на этот объект stylesheet осуществляется с помощью свойства parentStyleSheet. Значение свойства parentStyleSheet для большинства объектов stylesheet (тех, которые не были импортированы с помощью правила ©import) равно null. Следует различать свойство parentStyleSheet, указывающее на объект stylesheet, и другие свойства, ссылающиеся на элемент HTML, которому "принадлежлт" объект stylesheet. readonly Значение: булево Только для чтения Совместимость: WinBE4+, МасГ£4+, NN-, Moz-, Safari- Имя readonly не совсем точно соответствует назначению этого свойства. Булево значение позволяет сценарию определить, была ли текущая таблица стилей подключена к документу с помощью элемента style или импортирована из внешнего файла с помощью элемента 820 Часть ///. Объекты документа
link (либо правила ©import). В том случае, если таблица стилей была вложена с помощью элемента style, свойство readonly будет иметь значение false. Если же таблица стилей была импортирована, свойство имеет значение true. Значение true не свидетельствует о том, что свойства стилей не могут быть изменены сценарием. Свойства стилей можно изменять в процессе работы, однако эти изменения не будут отображаться во внешнем файле. См. также: свойство owningElement. rules Значение: массив объектов rule Только для чтения Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari 1+ Свойство rules возвращает массив всех объектов правил (кроме правил @), определенных в текущей таблице стилей. Порядок следования объектов правил в массиве соответствует порядку расположения правил, определенных в элементе style внешнего файла исходного кода. Массив rules следует использовать в качестве основного метода ссылки на индивидуальное правило, определенное в данной таблице стилей. Если вы используете цикл for для того, чтобы найти нужное правило в массиве, вероятнее всего, для этого следует применять свойство selectorText объекта правила. Этот метод основывается на том, что каждый селектор таблицы стилей уникален. Использование уникальных селекторов предпочтительно, однако вы можете при необходимости повторно использовать имя того или иного селектора для получения дополнительной информации о стилях, примененных к тем же элементам селектора. Соответствующее свойство в NN6+/Moz имеет имя cssRules. В МасГЕ5 и Safari воспринимаются оба имени данного свойства. Пример Запустите приложение The Evaluator в ГЕ4+ для изучения свойства rules первого объекта stylesheet страницы. Сначала определите количество правил в этом объекте, введя в верхнее текстовое поле следующее выражение. document.stylesheets[0].rules.length Далее изучите свойства одного из правил, введя в нижнее текстовое поле такое выражение. document.stylesheets[0].rules[1] Вы должны увидеть в поле результатов все свойства выбранного правила в ГЕ4+. См. также: объект rule; свойство cssRules. title Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Если вы зададите значение атрибуту title элемента style или link, который загружает таблицу стилей, это строковое значение преобразуется в свойство title объекта stylesheet. Строковое значение может служить своеобразным идентификатором, но оно не может быть использовано в качестве индекса массива stylesheets. В результате применения к отображаемым элементам HTML атрибут title преобразует текст во всплывающую подсказку для элементов. Для скрытых элементов style и link атрибут не оказывает никакого влияния на вид страницы на экране. Следовательно, этот атрибут и соответствующее свойство вы можете использовать для задания любого строкового значения. См, также: свойство title всех элементов HTML. Глава 26. Таблица стилей и объекты стилей 821
type Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Свойство type объекта stylesheet имеет непосредственное отношение к атрибуту type элементов style или link, с помощью которых таблица стилей вложена в текущий документ. Если вы не экспериментируете с новым языком написания таблиц стилей (предположим, его даже поддерживает браузер), то это свойство будет иметь значение text /ess. Методы addlmport(" URL"[, индекс]) Возвращаемое значение: целочисленное Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Метод addlmport () позволяет добавить правило ©import к объекту stylesheet. Первый параметр, который для этого необходим, это URL внешнего файла .ess, содержащего одно или более правил таблицы стилей. Если вы пропустите второй параметр, правило ©import будет присоединено в конце массива правил объекта stylesheet. Вы также можете назначить целое число в качестве индекса места расположения этого правила в массиве. Порядок следования правил в объекте stylesheet влияет на порядок каскадного включения перекрывающих друг друга правил таблиц стилей (т.е. множественные правила, примененные к одним и тем же элементам). Значение, которое возвращается в результате применения этого метода, представляет собой целое число, которое служит индексом места расположения нового правила в массиве правил объекта stylesheet. Если вы впоследствии собираетесь обращаться к этому правилу, то можете сохранить значение, возвращенное методом addlmport (), и использовать его в качестве индекса массива rules. См. также: метод addRule. addRule("селектор", "спецСтиля"[, индекс]) removeRule(индекс) Возвращаемое значение: целочисленное (для addRule) Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Метод addRule () присоединяет или вставляет правило таблицы стилей в текущий объект stylesheet. Первые два параметра представляют собой строки двух компонентов каждого правила: селектор и спецификацию стиля. Допускается использовать любой действительный селектор, включая множественные селекторы, селекторы с разделителями. Строка спецификации стиля содержит список пар атрибут: значение, разделенных точками с запятой (без фигурных скобок, определяющих спецификацию обычного правила таблицы стилей). Если вы пропустите последний параметр, правило будет присоединено в конце массива правил rules объекта. Вы также можете назначить целое число в качестве индекса место расположения этого правила в массиве правил rules. Порядок правил в объекте stylesheet влияет на порядок каскадного включения перекрывающих друг друга правил таблиц стилей (т.е. множественные правила, примененные к одним и тем же элементам). Значение, которое при этом возвращается, не несет значащей информации. Для того чтобы удалить правило из массива rules объекта stylesheet, следует использовать метод removeRule (). Будьте внимательны, задавая значение индекса правила, 822 Часть III. Объекты документа
которое вы хотите удалить. В сценарии можно использовать цикл for, чтобы в массиве правил найти соответствие свойству selectorText (при условии использования уникальных селекторов). Индекс соответствующего правила в дальнейшем может использоваться в качестве параметра метода removeRule (). Этот метод не возвращает значения. Соответствующие методы в NN6+ называются insertRule () и deleteRule (). Пример Приложение The Evaluator в ЕЕ4+ используется также для добавления правила таблицы стилей в первый объект stylesheet страницы. Сначала убедитесь в доступности таблицы стилей, введя в верхнее текстовое поле следующее выражение. document.stylesheets[0].disabled = false Далее добавьте стиль, который задает цвет элемента text Area. document.stylesheets[0].addRule("textarea", "color:red") Введите в нижнее текстовое поле корректную ссылку на любой объект (например, document. body), чтобы узнать, как добавленный стиль применяется к элементу textArea. Теперь можете удалить добавленный ранее стиль, обратившись к последнему элементу коллекции rules. document.stylesheets[0].removeRule(document.stylesheets[0]. rules.length - 1) См. также: методы deleteRule () и insertRule () deleteRule(индекс) insertRule("правило", индекс) Возвращаемое значение: целочисленное (для insertRule ()) Совместимость: Winffi-, Macffi5, NN6+, Mozl+, Safaril+ Метод insertRule () присоединяет или вставляет правило таблицы стилей в текущий объект stylesheet. Первый параметр представляет собой строку, содержащую правило стиля в том виде, в котором оно обычно представлено в таблице стилей, включая селектор и фигурные скобки, в которые заключен список пар атрибут: значение, разделенных точками с запятой. Место вставки нового правила в массиве cssRules задается с помощью индекса. Если вы хотите присоединить правило в конце списка, используйте в качестве параметра свойство length массива cssRules. Порядок расположения правил в объекте stylesheet может повлиять на порядок каскадного включения перекрывающих друг друга правил таблиц стилей (т.е. множественные правила, примененные к одним и тем же элементам). Значение, которое возвращается, представляет собой индекс места расположения вставленного правила. / В Safari 1.0 этот метод выполняется без вывода сообщения об ошибке, хотя /Надомну вставленное правило никак не влияет на вид элементов страницы. Для того чтобы удалить правило из массива cssRules объекта stylesheet, следует использовать метод deleteRule О. Будьте внимательны, задавая значение индекса правила, которое вы хотите удалить. В сценарии можно использовать цикл for, чтобы в массиве правил cssRules найти соответствие свойству selectorText (при условии использования уникальных селекторов). Индекс соответствующего правила в дальнейшем может использоваться в качестве параметра метода deleteRule (). Этот метод не возвращает значения. Соответствующие методы в Ш4+ называются addRule () и removeRule (). Глава 26. Таблица стилей и объекты стилей 823
Пример Приложение The Evaluator в NN6+/Moz также используется для добавления правила таблицы стилей в первый объект stylesheet страницы. Сначала убедитесь в доступности таблицы стилей, введя в верхнее текстовое поле следующее выражение. document.stylesheets[0].disabled = false Далее добавьте стиль, который задает цвет элемента text Area. document.stylesheets[0].insertRule("textarea {color:red}", document.stylesheets[0].cssRules.length) Введите в нижнее текстовое поле корректную ссылку на любой объект (например, document. body), чтобы узнать как добавленный стиль применяется к элементу textArea. Теперь можете удалить добавленный ранее стиль, обратившись к последнему элементу коллекции правил. document.stylesheets[0].deleteRule(document.stylesheets[0]. cssRules.length - 1) См. также: методы addRule () и removeRule (). Объекты cssrule и rule Свойства Методы Обработчики событий cssText parentStyleSheet readonly selectorText style type Синтаксис Доступ к свойствам объектов rule и cssrule. (IE4+) document. stylesheets [индекс] . rules [индекс] . свойство (MaclE5/W3C) document. stylesheets [индекс] . cssRules [индекс] . свойство Описание объектов Объекты rule и cssRule — различные варианты одних и тех же объектов. В ГЕ4+ объект называется rule (а массив этих объектов — rules). В NN6 (и МасШ5), в соответствии с рекомендациями W3C DOM, объект имеет имя cssRule (а массив этих объектов — cssRules). В этом разделе мы назовем их объектами правил. Объект правила состоит из двух основных компонентов. Первый—это текст селектора, которыр определяет, к какому элементу (элементам) следует применить правило стиля. Второй компонент — определение стиля с набором пар атрибут: значение, разделенных точками с запятой. В обеих моделях объектов, ВЕ4+ и NN6+/W3C, определение стиля считается объектом style, который имеет целый ряд свойств, представляющих поддерживаемые браузером 824 Часть III. Объекты документа
атрибуты стиля. Объект style, входящий в состав объекта правила, — это тот же объект style, связанный с одним из объектов элементов HTML. Для того чтобы получить доступ к свойствам style правила таблицы стилей, следует задать длинную ссылку. document.stylesheets[0].rules[0].style.color = "red"; Формат ссылки полностью соответствует правилам точечного синтаксиса JavaScript. Свойства cssText Значение: строка Чтение/Запись Совместимость: Winffi-, Macffi5, NN6+, Mozl+, Safaril+ Свойство cssText полностью возвращает текст текущего объекта cssRule. Поскольку текст, возвращенный этим свойством, может быть разделен на отдельные строки, к свойствам индивидуальных стилей рекомендуется обращаться с помощью свойства style объекта cssRule. Safari l .0 возвращает пустую строку. См. также: свойство style. parentstyleSheet Значение: объект stylesheet Только для чтения Совместимость: Winffi-, Macffi5, NN6+, Mozl+, Safari 1+ Свойство parentStyleSheet представляет собой ссылку на объект stylesheet, содержащий текущий объект cssRule. Возвращаемое значение является ссылкой на объект stylesheet, у которого сценарий может запрашивать и изменять свойства, характеризующие всю таблицу стилей. См. также: свойство parent Rule. readonly Значение: булево Только для чтения Совместимость: WinIE5+, Macffi5, NN-, Moz-, Safari- Имя readonly не совсем соответствует сущности этого свойства. Булево значение позволяет сценарию определить следующее: был ли текущий объект stylesheet правила вложен в документ с помощью, элемента style, импортировался из внешнего файла посредством элемента link или использовалось правило ©import. Если таблица стилей была вложена с помощью элемента style, свойство readonly будет иметь значение false. Если таблица стилей была импортирована, свойство имеет значение true. Значение true не свидетельствует о том, что свойства стилей не могут быть изменены сценарием. Свойства стилей могут быть изменены в процессе работы, однако эти изменения не будут отображены во внешнем файле. См. также: свойство stylesheet. readonly. selectorText Значение: строка Только для чтения Совместимость: Winffi5+, Macffi5, NN6+, Mozl+, Safari 1+ Свойство selectorText возвращает только селекторную часть правила таблицы стилей. Значение представляет собой строку. Если селектор содержит множественные, разделенные пробелами элементы, значение selectorText возвращается в форме строки с про- Глава 26. Таблица стилей и объекты стилей 825
белами. В том случае, если селектор применен к классам, которым предшествует точка, или идентификаторам, которым предшествует символ решетки, эти специальные символы также возвращаются в виде части строки. Если вы решили заменить селектор правила, рекомендуется удалить исходное правило и вставить на его место новое. При этом вы сохраните свойство style исходного правила и зададите стиль новому правилу. Пример Используйте приложение The Evaluator для изучения свойства selectorText правила первого объекта stylesheet страницы. Введите каждое из приведенных ниже выражений в верхнем текстовом поле. document.stylesheets[0].rules[0].selectorText document.stylesheets[0].rules[1].selectorText Сравните полученные результаты с результатами для элемента style страницы. См. также: свойство style. style Значение: объект style Чтение/Запись Совместимость: Winffi5+, МасШ5, NN6+, Mozl+, Safari 1+ Свойство style объекта rule (или cssRule) само по себе является объектом, свойства которого состоят из атрибутов стилей CSS, поддерживаемых браузером. Для изменения свойства объекта style следует задать достаточно длинную ссылку. document.stylesheets[0] .rules [0] .style.color = "red"; Любые изменения свойств style правила влияют на стиль элементов, обозначенных в селекторе правил. Если вы хотите изменить стиль отдельного элемента, обратитесь к свой- тву style именно этого элемента. Значения стилей, примененные непосредственно к элементу, доминируют и отменяют значения, назначенные этому элементу в таблице стилей. Пример Приложение The Evaluator можно смело применять для изменения свойства style правила stylesheet объекта страницы. Ниже приведены выражения, выполняемые в IE4+. Вы всегда можете заменить ссылку на объект cssRule ссылкой на объект rule, используемый в NN6+, МасШ5 и W3C DOM. Сначала перезагрузите страницу приложения и убедитесь, что таблица стилей активна. Для этого введите в верхнем текстовом поле следующее выражение. document.stylesheets[0].disabled = false Первое правило задается для элемента туР страницы. Изменим стиль font-size этого правила. document.stylesheets[0].rules[0].style.fontSize = "20pt" Изучите свойства объекта style: ознакомьтесь с описанием объекта style далее в этой главе и поэкспериментируйте с этими свойствами, произвольным образом изменив каждое из них. Чтобы восстановить значения стилей, достаточно перезагрузить страницу. См. также: объект style. type Значение: целое число Только для чтения Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari* 826 Часть III. Объекты документа
W3C DOM выделяет несколько классов правил таблиц стилей. Для того чтобы сценарий мог определить, с каким типом cssRule он имеет дело, свойство type возвращает целое число, значение которого указывает на один из типов cssRule. He все доступные типы правил могут быть применены в NN6. Полный список типов, который соответствует стандартам W3C DOM, выглядит следующим образом. Тип Описание 0 Unknown type (Неизвестный тип) 1 Regular style rule (Правило обычного стиля) 2 @charset rule (Правило набора символов) 3 ©import rule (Правило импортирования) 4 ©media rule (Правило носителя) 5 @font-space rule (Правило шрифта) 6 @page rule (Правило страницы) Большинство правил таблиц стилей, с которыми вам предстоит работать, относится к типу 1. Чтобы получить более подробную информацию о типах правил, обратитесь к спецификации W3C для CSS по адресу: http: //www. w3 . org/TR/REC-CSS2. Объекты currentstyle, runtimestyle и style Свойства Методы Обработчики событий (См. ниже) Синтаксис Доступ к свойствам объектов currentstyle, runtimeStyle и style. (IE4+/W3C) ссылкаНаЭлемент. style. свойство (IE4+/W3C) document. stylesheets [индекс] . style. свойство (IE5+) ссылкаНаЭлемент. currentstyle. свойство (IE5.5) ссылкаНаЭлемент. runtimeStyle. свойство Описание объектов Объекты currentstyle, runtimeStyle и style возвращают объект, содержащий целый ряд свойств, относящихся к спецификациям таблицы стилей, которая, в свою очередь, связана либо с объектом stylesheet (только для объекта style), либо с объектом любого отображаемого элемента HTML. Благодаря возможности переформатирования страницы в современных браузерах изменение свойств объектов style и runtimeStyle, характерное для Ш, мгновенно отражается на содержимом Web-страницы. Доступ к базовому объекту style осуществляется так же, как и к свойству объекта stylesheet или объекта элемента HTML. Необходимо помнить, что свойства стиля элемента HTML отображаются в объекте style только в том случае, если спецификация задана Глава 2В. Таблица стилей и объекты стилей 827
с помощью атрибута style внутри дескриптора элемента. Если необходимо таблицы стилей применить с помощью дескрипторов style или link (и если сценарий должен воспринимать те значения свойства style, которые были заданы таблицами стилей), вы должны получить свойства с помощью объекта current Style, доступного Только для чтения (это свойство поддерживается в ГЕ5+). Объект currentStyle возвращает присоединенную таблицу стилей, примененную к объекту элемента HTML. Свойства объекта currentStyle в Ш несколько отличаются от свойств объекта style. В объекте currentStyle отсутствуют свойства, содержащие комбинированные значения — border или borderBottom. С другой стороны, этот объект имеет такие специальные свойства, как расположение сторон прямоугольника обрезки (clipTop, clipRight, clipBottom и clipLef t), которые не поддерживаются свойством clip. Компания Microsoft разработала еще один объект стиля— runtimeStyle— в Ш5.5. Этот объект позволяет сценарию отменить любое свойство стиля, заданное в таблице стилей с помощью атрибута style. Иными словами, объект runtimeStyle является версией currentStyle, доступной для чтения и записи. Отличие состоит в том, что, задав новое значение одному из свойств этого объекта, вы не сможете изменить определение значения в атрибуте style таблицы стилей. В основном, сценарий будет модифицировать свойство style элемента для того, чтобы внести необходимые изменения, если только вы не изменяете стили, подключая и отключая таблицы стилей (или не изменяете свойство className элемента таким образом, чтобы его контролировал другой селектор). Свойства стиля Если вы перечислите все свойства объекта style, поддерживаемые браузерами, начиная с IE4 и NN6, то у вас получится список, состоящий примерно из 180 элементов. Примерно такой же список получится при перечислении свойств для всех версий браузеров; подобный список атрибутов таблиц стилей существует и в W3C CSS. Имена атрибутов CSS зачастую неудобны для использования в сценарии, поскольку содержат дефис (например, font-size). Идентификаторы же JavaScript не могут иметь дефис в имени. Поэтому атрибуты, состоящие из нескольких слов, преобразуются в стандарт interCap (например, f ontSize). Не все свойства поддерживаются в браузерах, воспринимающих такую модель объекта, как style. В частности, компания Microsoft разработала целый ряд свойств, уникальных для IE, а иногда — только для Ш для Windows. Компания Netscape, в свою очередь, предлагает свойства, которые будто поддерживаются объектом style, однако в действительности браузеры их не поддерживают. Например, в спецификации CSS определено несколько атрибутов, которые ускоряют процесс получения содержимого, вводящегося с помощью синтезатора речи. NN6 и NN7+ этого не уточняет, однако программа браузера Gecko в ядре браузера может быть адаптирована для такого объекта. Поэтому, если вы видите в списке свойство, имя которого ни о чем вам не говорит, проверьте его в совместимых браузерах, чтобы понять, как оно работает. Вы также обнаружите несколько свойств, характерных для Mozzilla-совмести- мых браузеров, — их имена начинаются с ключевого слова moz. Все они соответствуют еще полностью не отлаженной технологии CSS 3. Префикс moz гарантирует совместимость данных свойств с будущими свойствами браузеров (нетрудно догадаться, что в последних этот префикс будет отсутствовать). Некоторые браузеры также предлагают дополнительные свойства объекта style, которые в действительности браузерами не поддерживаются. Рассмотрим, например, свойство quote объекта style для Ш5/Мас и NN6, соответствующее атрибуту стиля quotes в спецификации W3C CSS2. Оказывается, свойство quote стиля не может использоваться сценарием для этих версий браузеров. Если вы видите, что определенное свойство поддерживается 828 Часть III. Объекты документа
только браузерами МасШ5 и NN6+, то проверьте свойство style (и атрибут таблицы стилей) в приложении The Evaluator, прежде чем применить его в своем проекте. С объектом связано такое количество свойств, что применить одно из них для достижения желаемого эффекта не так уж и просто. Чтобы облегчить вашу задачу, приведенный ниже список свойств разделен на функциональные категории, расположенные в соответствии с частотой их применения. Категория Описание Text & Fonts (Текст и шрифты) Inline Display & Layout (Вид и макет) Positioning (Расположение) Background (Фон) Borders & Edges (Границы и отступы) Lists (Списки) Scrollbars (Полосы прокрутки) Tables (Таблицы) Printing (Печать) Miscellaneous (Дополнительные) Aural (Акустика) Спецификация шрифта, отображение текста, выравнивание текста Вид элементов, выравнивание и изображение Явное расположение "слоев" Фоновые изображения и цвета Границы, отступы и поля вокруг элементов Параметры элементов ui или oi Цвет полосы прокрутки (только для IE5.5/Windows) Параметры элементов и компонентов table Разрывы страниц и выравнивание страниц при печати Вспомогательные атрибуты Воспроизведение содержимого, полученного из синтезатора речи Значения свойств Свойства объекта style имеют строковые значения. Более того, значения многих групп свойств стилей имеют общий формат. Поэтому полезно знать формат часто используемых значений. Задача этой главы заключается не в описании особенностей таблицы стилей, а в ознакомлении с процессом создание сценариев. Если вы встретите незнакомые вам термины, воспользуйтесь справочниками или найдите нужную информацию о таблицах стилей CSS во Всемирной сети. Длина Существует немало значений длины, каждое из которых определяет физический размер в документе. Содержимое документа может отображаться на мониторе или распечатываться на листе бумаги. Поэтому любое значение длины должно указываться в определенных единицах измерения. Некоторые единицы измерения (рх, em, ex) считаются относительными, поскольку соответствующие точные размеры зависят от ряда факторов, не зависящих от таблицы стилей Глава 26. Таблица стилей и объекты стилей 829
(например, плотность пикселей конкретного экрана). Существуют и такие единицы, которые заданы элементами глобального масштаба (например, размеры поля элемента р, заданные в em, зависят от настроек размера шрифта элемента body). Абсолютные единицы измерения (in, cm, mm, pi, pt) предпочтительнее использовать для документов, подлежащих печати. В сценарии единицы измерения длины следует использовать согласно следующей таблице. Единица измерения Пиксель Em Ex Дюйм Сантиметр Миллиметр Цицеро Точка В сценарии рх em ex in cm mm Pi Pt Пример 14px 1. 5em 1.5ex 3.0in 4 . Ocm 4 0mm 72pi 14pt Строковое значение длины может быть также представлено в процентах. Например, стилю абзаца lineHeight может задаваться размер шрифта, составляющий 120% обычного размера шрифта абзаца. Для этого необходимо записать следующее выражение. document.getElementById("myP").style.lineHeight = "120"; Наследование стиля — одна из основных характеристик CSS — зачастую существенно влияет на свойства стиля, значения которого выражают длину. Цвет Существует три типа значений цвета: ■ значения RGB (в нескольких форматах); ■ обычные названия цветов; ■ имена элементов пользовательского интерфейса системы. Значения RGB могут быть шестнадцатеричными. Чаще всего такие значения содержат в начале символ решетки, за которым следует шесть цифр, например #f fOOf f (можно использовать буквы как верхнего, так и нижнего регистра). Существуют специальные сокращения: вы задаете три цифры (подразумевается, что заданное значение будет расширено — каждая из цифр будет продублирована). Например, запись #f Of всегда расширяется до #f f OOf f. RGB-значение также может задаваться в виде префикса rgb () и трех цифр (от 0 до 255). Кроме того, цвет можно указать как процентное соотношение компонентов красного, зеленого и синего цветов. Ниже приведено несколько примеров. document.stylesheets[0].rules[0].style.color = "rgb(0, 255, 0)"; document.stylesheets[0].rules[0].style.color = "rgb(0%/ 100%, 0%)"; Браузеры поддерживают и полный список обычных названий цветов, разработанных компанией Netscape. Список с примерами цветов вы найдете по адресу: http://developer.netscape.com/library/manuals/1998/htmlguid/colortab.htm. Однако не все эти цвета Web-безопасны. Безопасные цвета вы можете определить, посетив страницу http: //www. lynda. com/hexh. html. 830 Часть HI. Объекты документа
Последняя категория значений цвета относится к элементам пользовательского интерфейса. Многие из этих элементов определяются настройками, заданными в папке Панель управления для монитора в системе. Строковые значения соответствуют распознаваемым компонентам пользовательского интерфейса — системным цветам. activeborder activecaption appworkspace background buttonface buttonhighlight buttonshadow buttontext captiontext graytext highlight highlighttext inact iveborder inactivecaption inactivecaptiontext i n f oba ckground infotext menu menutext scrollbar threeddarkshadow threedface threedhighlight threedlight shadow threedshadow window windowframe windowtext Использование таких настроек цвета при создании общедоступных Web-страниц нежелательно, поскольку в этом случае все зависит только от выбранных пользователем настроек. Работая над созданием корпоративного Web-узла (при условии, что системные настройки подлежат строгому контролю) вы вполне можете задать цвета таким образом. Это поможет вам назначить безопасную цветовую схему Web-страниц. Стороны прямоугольника Многие свойства стиля управляют видом сторон прямоугольников (например, толщина границы вокруг блокового элемента). В большинстве случаев значения стилей могут быть применены к отдельным сторонам или к комбинациям сторон прямоугольника, в зависимости от того, сколько значений может иметь то или иное свойство. Количество значений влияет на четыре стороны прямоугольника следующим образом. Количество значений Влияние 1 Всем четырем сторонам назначено одно и то же значение 2 Верхней и нижней стороне назначено первое значение; левой и правой — второе значение 3 Верхней стороне назначено первое значение; левой и правой - второе значение; нижней стороне—третье значение 4 Верхней, правой, нижней и левой сторонам назначены индивидуальные значения в указанном порядке Например, вы можете задать цвет границы элемента так, чтобы все его стороны были окрашены в красный цвет, — для этого используют следующее выражение. ссылкаНаЭлемент.style.borderColor = "red"; Если же вы хотите, чтобы верхняя и нижняя стороны были красного цвета, а левая и правая — зеленого, оператор должен выглядеть следующим образом. ссылкаНаЭлемент.style.borderColor = "red green"; Многие стили имеют свойства, в которых можно задавать множественные значения. Это могут быть цвета, длины или другие величины из списка допустимых значений. Глава 26. Таблица стилей и объекты стилей 831
Комбинированные значения Существует иная категория значений стиля, в которую входят свойства, являющиеся сокращениями для нескольких родственных свойств. Например, свойство border включает в себя свойства borderWidth, borderStyle и borderColor. Это возможно, поскольку три свойства-компонента представляют различные классы значений: borderWidth — ширина; borderStyle основано на списке возможных значений; borderColor— значение цвета. Следовательно, вы можете задать одно или более значений этого свойства (в произвольном порядке), и браузер поймет, как применить эти значения к назначенному подсвойст- ву. Каждому такому подсвойству можно назначить только одно значение. Это означает следующее: если для четырех сторон прямоугольника задано одно свойство, значение этого свойства применяется ко всем четырем сторонам. Например, если задать свойству border одно значение следующим образом. ссылкаНаЭлемент.style.border = "blue"; то это будет равносильно такому оператору. ссылкаНаЭлемент.style.borderColor = "blue"; Однако если вы задаете множественные элементы. ссылкаНаЭлемент.style.border = "groove blue Зрх"; f то это воспринимается, как эквивалент следующих трех операторов. ссылкаНаЭлемент.style.borderStyle = "groove"; ссылкаНаЭлемент.style.borderColor = "blue"; ссылкаНаЭлемент.style.borderWidth = "Зрх"; В описаниях свойств, которые приведены ниже, эти комбинированные значения отмечены своими названиями, употребляемыми в сценариях, с помощью оператора (| |) (оператор ИЛИ). border = "borderStyle || borderColor || borderWidth"; URL Формат свойства style отличается от формата остальных значений свойств, содержащих URL. Этот формат содержит приставку url (), где в скобках записан URL (относительный или абсолютный). Сам URL в кавычки не заключают, хотя остальные правила его задания соблюдаются строго. ссылкаНаЭлемент.style.backgroundlmage = "url(chainlink.jpg)"; URL не должен содержать пробелов. Если пробелы все же существуют, используйте URL- кодированную версию для задания адреса: преобразуйте пробелы в символы 20%. Этот формат помогает отличить значение URL от любого другого строкового значения в записях свойств. Свойства текста и шрифта color Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: цвет изображения элемента. Используется, в основном, для назначения цвета текста. При отображении в некоторых браузерах может влиять на цвет границы и выделенных участков других элементов. Значение: спецификация цвета. Пример: elementRef .style.color = "rgb (#22FFOO) "'; 832 Часть ///. Объекты документа
font Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: до шести свойств стиля, связанных со шрифтами. Значение: комбинированные f ontStyle | | f ontVariant | | f ontWeight | | fontSize | | lineHeight | | font Family. См. индивидуальные свойства для форматов их значений. Пример: elementRef . style. font = "bold sans-serif 16px"; fontFamily Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: семейство шрифтов, которое должно применяться к элементу в указанном порядке очередности. Значение: разделенный запятыми список семейств шрифтов, которые должны применяться к элементу, начиная с имени наиболее предпочтительного для данного контекста варианта. Вы можете использовать одно из родовидных имен семейств. В этом случае выбор оптимального шрифта, соответствующего классу, будет зависеть от браузера: serif | sans-serif [cursive | fantasy |monospace. He все браузеры поддерживают каждую из констант, однако serif, sans-serif и monospace поддерживают любой браузер. Пример: elementRef .style. fontFamily = "Bauhaus 93, Arial, monospace"; fontSize Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: размер символов текущего семейства шрифтов. Значение: длины (обычно значения выражаются в единицах рх и pt); константы относительных размеров: larger | smaller; константы абсолютных размеров: хх-small | х-small | smal1|medium|large|x-large|xx-large. Пример: elementRef.style.fontSize = "1брх" elementRef.style.fontSize = "small"; fontSizeAdjust Совместимость: Winffi-, Macffi5, NN6+, Mozl+, Safari- Контролирует: значение длины вторичного семейства шрифтов с тем, чтобы его символы имели ту же высоту, что и символы основного семейства шрифтов. Значение: число (включая значения с плавающей запятой) или попе. Пример: elementRef.style.fontSizeAdjust = "1.05"; fontStretch Совместимость: WinlE-, МасШ5, NN6+, Mozl+, Safari- Контролирует: ширину символов шрифта при отображении. Значение: константа ultra-condensed | extra-condensed | condensed | semi -condensed | semi-expanded | expanded | extra-expanded | ultra-expanded или wider | narrower | inherit|normal. Пример: elementRef.style.fontStretch = "expanded"; Глава 26. Таблица стилей и объекты стилей 833
fontStyle Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: курсивное начертание символов. Значение: константа normal | italic | oblique | inherit. Пример: elementRef.style.fontStyle = "italic"; fontVariant Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari- Контролирует: отображение букв в виде строковых символов. Значение: константа normal | small-caps | inherit. Пример: elementRef.style.fontVariant = "small-caps"; fontWeight Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Контролирует: отображение символов полужирным или слабым полужирным начертанием. Шрифты, поддерживающие нумерованную градацию, можно контролировать с помощью цифровых значений. Нормальный = 400; полужирный = 700. Значение: константа bold|bolder|lighter[normal|100|200|300|400|500|600| 700|800|inherit. Пример: elementRef.style.fontWeight = "bold"; letterSpacing Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1 + Контролирует: расстояние между символами. Используется для того, чтобы отменить собственные характеристики семейства шрифтов. Значение: длина (обычно в em, относительно размера текущего шрифта); константа normal|inherit. Пример: elementRef.style.letterSpacing = M1.2em"; lineBreak Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: правила разрыва строки для текстового содержимого на японском языке. Значение: константа normal | strict. Пример: elementRef.style.lineBreak = "strict"; lineHeight Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: высоту прямоугольного пространства, содержащего строку символов текста. Значение: длина (обычно в em, относительно размера текущего шрифта); число (множитель унаследованной высоты строки); процентное отношение (относительно унаследованной высоты строки); константа normal | inherit. Пример: elementRef.style.lineHeight = "1.1"; 834 Часть III. Объекты документа
quotes Совместимость: Winffi-, Macffi5, NN6+,.Mozl+, Safari- Контролирует: символы, используемые в качестве кавычек; Значение: разделенные пробелом символы открытых и закрытых кавычек; константа попе|inherit. Пример: elementRef.style.quotes = "« »"; rubyAlign Совместимость: WinIE5+, Macffi5, NN-, Moz-, Safari- Контролирует: выравнивание "рубинового" текста в элементе ruby. Значение: константа auto | left | center | right | distribute-letter | distribute- space|line-edge. Пример:RUBYelementRef.style.rubyAlign = "distribute=letter"; rubyOverhang Совместимость: Winffi5+, Macffi5, NN-, Moz-, Safari- Контролирует: отступ "рубинового" текста в элементе ruby. Значение: константа auto | whitespace | none. Пример: RUBYelementRef.style.rubyOverhang = "whitespace"; rubyPosition Совместимость: WinIE5+, Macffi5, NN-, Moz-, Safari- Контролирует: расположение "рубинового" текста относительно основного текста в элементе элемента ruby. Значение: константа above | inline. Пример:RUBYelementRef.style.rubyPosition = "inline"; textAlign Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Контролирует: горизонтальное выравнивание текста относительно элемента, в котором содержится этот текст. Значение: константа center] justify | left | right. Пример: elementRef.style.textAlign = "center"; textAlignLast Совместимость: Winffi5.5+, Macffi-, NN-, Moz-, Safari- Контролирует: горизонтальное выравнивание последней строки каждого абзаца. Значение: константа auto | center | justify | left | right. Пример: elementRef.style.textAlignLast = "justify"; Глава 26. Таблица стилей и объекты стилей 835
textAutospace Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: дополнительные пробелы между идеографическими и неидеографическими символами. Значение: константа none | ideograph-alpha | ideograph-numeric | ideograph- parenthesis |ideograph-space. Пример: elementRef.style.textAutospace = "ideograph-alpha"; textDecoration Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Контролирует: отображение подчеркивания, линии над строкой текста и линии зачеркивания. Значение: константа none | blink | line-through | over line | underline. Пример: elementRef.style.textDecoration = "underline"; textDecorationBlink textDecorationLineThrough textDecorationNone textDecorationOverline textDecorationUnderline Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Контролирует: индивидуальные характеристики оформления текста, позволяющие применить различные методы форматирования к одному и тому же тексту. Значение: булево выражение true | false. Пример: elementRef -. style. textDecorationUnderline = true; textlndent Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: величину отступа для первой строки блокового элемента текста (например, р). Значение: длина (отрицательные значения для втяжки); процентное соотношение (относительно унаследованного значения). Пример: elementRef.style.textIndent = "2.5em"; textJustify Совместимость: Winffi5+, Macffi5, NN-, Moz-, Safari- Контролирует: дополнительные отступы для элемента, свойство text Align которого имеет значение justify. Значение: константа auto | distribute | distribute-all-lines |distribute- center-last|inter-cluster|inter-ideograph|inter-word|kashida|newspaper. Пример: elementRef.style.textJustify = "distribute"; 836 Часть III. Объекты документа
textJustifyTrim Совместимость: Winffi5+, Macffi5, NN-, Moz-, Safari- Для использования в будущем. textKashidaSpace Совместимость: WinIE5.5+, МасГЕ-, NN-, Moz-, Safari- Контролирует: соотношение расширения протяжки и расширения пробелов для арабских систем письма. Значение: процентное соотношение. Пример: elementRef.style.textKashidaSpace = и90%"; textOverflow Совместимость: Winffi6+, Macffi-, NN-, Moz-, Safari- Контролирует: отображение троеточия в конце длинной строки текста, что указывает на ' доступность дополнительной информации. Значение: константа clip | ellipsis. textShadow Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari- Контролирует: отображение тени вокруг элементов текста. Внимание: атрибут стиля для этого свойства не поддерживается в МасШ5 и NN6/7, однако данное свойство действительно для объекта style. Значение: каждая спецификация тени состоит из цвета по выбору и трех разделенных пробелами значений длины (горизонтальное смещение тени, вертикальное смещение тени, длина радиуса тени). Множественные значения отделены запятыми. textTrans form Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, SafariJ+ Контролирует: регистр отображения текста на экране (имеется в виду — без изменения регистра исходного текста). Значение: константа none | capitalize | lowercase | uppercase. Пример: elementRef.style.textTransform = "uppercase"; textUnderlinePosition Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Контролирует: расположение линии в подчеркнутом начертании — над текстом или под текстом. Кажется сходным по значению с textDecorationUnderline и textDecorat ionOverline. Значение: константа above | below. Пример: elementRef.style.textUnderlinePosition = "above"; Глава 26. Таблица стилей и объекты стилей 837
unicodeBidi Совместимость: Winffi5+, МасГ£5, NN6+, Mozl+, Safari 1+ Контролирует: в двунаправленном тексте (например, английском и арабском), насколько блок текста, направленный в противоположную сторону, вложен во внешний элемент. Значение: константа normal | embed | bidi-override. Пример: elementRef.style.unicodeBidi = "embed"; whiteSpace Совместимость: WinIE5.5+, Macffi5, NN6+, Mozl+, Safaril+ Контролирует: интерпретацию символов пробела в коде источника элемента. Значение: константа normal] nowrap | pre. Пример:elementRef.style.whiteSpace = "nowrap"; wordBreak Совместимость: Winffi5+, Macffi-, NN-, Moz-, Safari- Контролирует: характеристики разрыва слова (в основном, для текстов на азиатских языках или содержащих как латинские, так и азиатские символы). Значение: константа normal | break-all | keep-all. Пример: elementRef.style.wordBreak = "break-all"; wordSpacing Совместимость: Winffi6+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: расстояние между словами. Значение: длина (обычно в единицах em); константа normal. Пример: elementRef.style.whiteSpacing = "lem"; wordwrap Совместимость: Winffi5.5+, Macffi-, NN-, Moz-, Safari- Контролирует: характеристики перехода слова на новую строку в блоковом элементе текста, элементе с внутренне определенными размерами или позиционируемом элементе. Значение: константа normal | break-word. Пример: elementRef.style.wordwrap = "break-word"; writingMode Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Контролирует: направление потока содержимого Web-страницы (слева направо/сверху вниз или сверху вниз/справа налево, как в некоторых азиатских языках). Значение: константа lr-tb | tb-rl. Пример: elementRef.style.writingMode = "tb-rl"; 838 Часть III. Объекты документа
Свойства вида и макета документа clear Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: расположение элемента относительно соседнего плавающего элемента. Значение: константа both | left | none | right. Пример: elementRef.style.clear = "right"; clip Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: прямоугольник обрезки элемента (т.е. прямоугольника, сквозь который пользователь видит содержимое элемента). Значение: rect(topLength, rightLength, bottomLength, leftLength)|auto. Пример:elementRef.style.clip = "rect(10px, ЗООрх, Орх)"; clipBottom clipLeft clipRight clipTop Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Контролирует: отдельные границы прямоугольника обрезки элемента. Эти свойства объекта current Style доступны Только для чтения. Значение: длина | auto. Пример:var leftEdge = elementRef.currentStyle.clipLeft; content Совместимость: WinlE-, МасШ5+, NN6+, Mozl+, Safari- Контрблирует: содержимое, отображаемое элементом. Внимание: атрибут стиля для этого свойства не поддерживается в Ш5/Мас и NN6, однако данное свойство действительно для объекта style. Значение: см. http:/ /www. w3. org/TR/REC- CSS2 /generate. html #propde f - content. counter-Increment Совместимость: WinlE-, МасШ5, NN6+, Mozl+, Safari- Контролирует: шаг изменения показаний счетчика, которые должны отображаться в свойстве content стиля. Внимание: атрибут стиля для этого свойства не поддерживается в МасГ£5 и NN6/7, но данное свойство действительно для объекта style. Значение: одна и более пар идентификатора счетчика и целых чисел. Глава 26. Таблица стилей и объекты стилей 839
counterReset Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari 1+ Контролирует: восстанавливает именованный счетчик содержимого, которое должно отображаться в свойстве content стиля. Внимание: атрибут стиля для этого свойства не поддерживается в МасШ5 и NN6/7, но данное свойство действительно для объекта style. * Значение: одна и более пар идентификаторов счетчика и целых чисел. cssFloat Совместимость: WinlE-, MacIE5, NN6+, Mozl+, Safari 1+ Контролирует: горизонтальное выравнивание элемента, при котором элемент содержимого заключается в другой элемент (обычно изображение заключается в текст). Соответствует атрибуту float стиля CSS. См. также свойство f loatStyle ниже. Плавающие (непозицио- нируемые) элементы следуют целому ряду правил. Подробности их использования вы найдете по адресу: http://www.w3.org/TR/REC-CSS2/visuren.html#propdef-float. Значение: константа lef 11 right | none. Пример: elementRef.style.cssFloat = "right",; cursor Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari- Контролирует: значок, который используется в качестве указателя мыши на экране. Выбрать значок можно из библиотеки системы. В спецификации CSS2 присутствует синтаксис, предназначенный для загрузки дополнительных значков указателя, но Ш5.5 и NN6/7 такой возможности не предоставляют. Значение: константа auto | crosshair | default | е-resize | help | move | n-resize | ne-resize|nw-resize|pointer|s-resize|se-resize|sw-resize|text|w-resize|wait. Пример: elementRef.style.cursor = "hand"; direction Совместимость: Winffi5+, Macffi5, NN6+, Mozl+, Safaril+ Контролирует: направление расположения (слева направо или справа налево) внедренного текста (то же, что и атрибут dir элемента.). Значение: константа ltr | rtl. Пример: elementRef.style.direction = "rtl"; display Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: отображение элемента на экране. Содержимое Web-страницы, окружающее неотображаемый элемент, располагается таким образом, чтобы занять место неотобра- жаемого элемента — так, будто этот элемент вовсе не должен отображаться на экране (еще один метод — см. свойство visibility). Обычно используется для того, чтобы скрыть или показать подразделы графической древовидной структуры. Может также указывать браузеру на необходимость отображения того или иного элемента как вложенного, так и блокового. Существуют специальные значения для особых типов элементов (например списков, таблиц, ячеек таблиц и т.д.). 840 Часть III. Объекты документа
Значение: константа block | compact | inline | inline-table) list-item) none | run-in)table|table-caption|table-cell|table-column-group|table-footer- group|table-header-group|table-row|table-row-group. Пример: elementRef.style.display = "none"; filter Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Контролирует: эффекты отображения статического содержимого Web-страницы и эффекты перехода от скрытого состояния к отображенному. Компания Microsoft пересмотрела синтаксис таблиц стилей filter для WinIE5.5 (используя элемент управления DXImage Transform ActiveX). Удобная утилита в режиме реального времени позволяет просмотреть результаты работы фильтра и предоставляет возможность копирования я вставки кода. С помощью этой утилиты вы сможете добавлять фильтры и контролировать их с помощью сценария. Добавить в сценарий код эффекта скрытия и отображения можно в несколько этапов. Сначала этот эффект нужно загрузить. Перед тем, как изображение будет показано, программа должна выполнить некоторые операции. Для получения и изменения спецификации фильтра используйте свойство style .filter. Для того чтобы использовать индивидуальные свойства фильтра, используйте объект el em. styles [i]. Подробнее объект filter рассмотрен далее в этой главе. Значение: спецификация фильтра как строки. Пример: var filterSpec = elementRef.style.filter = "alpha(opacity=50) flipHO"; layoutGrid Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: свойства сетки страницы (в основном, для страниц на азиатских языках). Значение: комбинированные значения layoutGridMode | | layoutGridType | | layoutGridLine | | layoutGridChar. См. индивидуальные свойства форматов значений. Пример: elementRef.style.layoutGrid = "2em strict"; layoutGridChar Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: размер сетки символов (азиатские языки). Значение: длина; процентное соотношение; константа none | auto. Пример: elementRef. style. layoutGridChar = "2em" ; layoutGridLine Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: линейную высоту сетки (азиатские языки). Значение: длина; процентное соотношение; константа none | auto. Пример: elementRef.style.layoutGridLine = "110%"; layoutGridMode Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Контролирует: одномерную или двухмерную сетку (азиатские языки). Значение: константа both | none | line | char. Пример:elementRef.style.layoutGridMode = "both"; Глава 26. Таблица стилей и объекты стилей 841
layoutGridType Совместимость: WinIE5+, МасШ-, NN-, Moz-, Safari- Контролирует: тип сетки для текстового содержимого (азиатские языки). Значение: константа loose | strict | fixed. _ Пример: elementRef . style. layoutGridType = "strict" ; markerOffset Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari- Контролирует: расстояние между границами прямоугольника с маркерами (выделение, которое отображается в виде прямоугольника с маркерами управления) и блоковым элементом текста. Внимание: атрибут стиля для этого свойства не поддерживается в МасШ5 и NN6/7, однако данное свойство действительно для объекта style. Значение: длина; константа auto. Пример: elementRef.style.markerOffset = "2em"; marks Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari- Контролирует: отображение меток обрезки и других подобных элементов при печати страницы. Внимание: атрибут стиля для этого свойства не поддерживается в Мас1Е5 и NN6/7, однако данное свойство действительно для объекта style. Значение: константа crop | | cross | none. Пример: elementRef .style, marks = "crop"; maxHeight maxWidth minHeight minWidth Совместимость: WinlE (см. текст), МасШ-, NN6+, Mozl+, Safari- Контролирует: максимальную и минимальную высоту и ширину элемента. В Ш6 поддерживается только свойство minWidth. Значение: длина; процентное соотношение; константа (только для максимальных свойств) попе. Пример: elementRef.style.maxWidth = "ЗООрх"; overflow Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: отображение содержимого блокового элемента текста, когда размеры его исходного прямоугольника превышают размеры самого большого внешнего прямоугольного пространства. Если задано значение hidden, остаток содержимого блокового элемента отсекается; scroll означает, что во внешнем прямоугольнике появляется полоса прокрутки, позволяющая пользователю просмотреть содержимое элемента полностью; значение visible приводит к тому, что содержимое блокового элементы выходит за пределы внешнего прямоугольника. Значение: константа auto | hidden | scroll | visible. Пример: elementRef.style.overflow = "scroll"; 842 Часть III. Объекты документа
overflowX overflowY Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Контролирует: отображение содержимого блокового элемента текста, когда ширина (overflowX) или длина (overflowY) его исходного прямоугольника превышают размеры самого большого внешнего прямоугольного пространства. Если задано значение hidden, остаток содержимого блокового элемента отсекается; scroll означает, что во внешнем прямоугольнике появляется полоса прокрутки, позволяющая пользователю просмотреть содержимое элемента полностью; значение visible приводит к тому, что содержимое блокового элемента выходит за пределы внешнего прямоугольника Значение: константа auto | hidden | scroll | visible. Пример: elementRef.style.overflow = "scroll"; stylePloat Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Контролирует: горизонтальное выравнивание элемента таким образом, чтобы его окружало содержимое Web-страницы (обычно изображение заключается в текст). Соответствует атрибуту float стиля CSS. См. также свойство cssFloat выше. Плавающие (непозицио- нируемые) элементы следуют целому ряду правил. Подробности вы найдете по адресу: http://www.w3 .org/TR/REOCSS2/visuren.html#propdef-float. Значение: константа lef 11 right | none. Пример: elementRef.style.styleFloat = "right"; verticalAlign Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: вертикальное выравнивание внутреннего содержимого и содержимого ячеек таблиц относительно окружающего их содержимого. Не все константы поддерживаются браузерами всех версий. Значение: константа baseline | bottom | middle | sub | super | text-bottom | text- top | top; длина; процентное соотношение. Пример: elementRef.style.VerticalAlign = "baseline"; visibility Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1 + Контролирует: отображение элемента на Web-странице. Если элемент скрыт, его место на странице остается свободным. Если вы хотите, чтобы свободное место было занято остальным содержимым, используйте свойство display. Это свойство часто применяют для скрытия и показа позиционируемых элементов, управляемых сценарием. Значение: константа collapse | hidden | visible. Пример: elementRef.style.visibility = "hidden"; Глава 26. Таблица стилей и объекты стилей 843
width Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safaril+ Контролирует: горизонтальные размеры блокового элемента текста. Браузеры более ранних версий могут отображать содержимое самым неожиданным образом, включая вложение элементов с заданными свойствами стиля width. Значение: длина; процентное соотношение; константа auto. Пример: elementRef.style.width = и200рх"; zoom Совместимость: WinIE5.5+, MacIE-, NN-, Moz-, Safari- Контролирует: кратность увеличения отображаемого элемента. Значение: константа normal; процентное соотношение (где 100% соответствует норме); число с плавающей десятичной запятой (масштабный множитель, где 1.0 соответствует норме). Пример: elementRef.style.zoom = ".9"; Свойства позиционирования В главе 39 приведены примеры кодов позиционируемых элементов и их свойства style. bottom right Совместимость: Winffi5+, МасШ5, NN6+, Mozl+, Safari 1+ Контролирует: степень смещения позиционируемого элемента по отношению к нижней и правой границам прямоугольника, содержащего этот элемент. На практике размер позиционируемого элемента задается посредством свойств height и width. Значение: длина; процентное соотношение; константа auto. Пример: elementRef.style.bottom = "20px"; left top Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: степень смещения позиционируемого элемента по отношению к верхней и левой границе прямоугольника, содержащего этот элемент. Используйте эти свойства для позиционирования элемента под управлением сценария. Для того чтобы расположить абсолютно позиционируемый элемент над внутренним элементом, задайте расположение внутреннего элемента с помощью свойств of f setTop и offset Left, однако учтите при этом особенности различных браузеров (см. главу 39). Значение: длина; процентное соотношение; константа auto. / Пример: elementRef.style.top = "250рх"; 844 Часть III. Объекты документа
height width . Совместимость: WinIE4+, МасЩ4+, NN6+, Mozl+, Safari 1+ Контролирует: высоту и ширину блока элемента. Чаще всего используется для настройки размеров позиционируемого элемента (см. главу 39). Значение: длина; процентное соотношение; константа auto. Пример: elementRef.style.height = "ЗООрх"; pixelBottom pixelHeight pixelLeft pixelRight pixelTop pixelWidth Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari 1+ Контролирует: целые значения, заданные в пикселях, расположения (первоначально позиционируемых) элементов. Непиксельные значения этих свойств представляют строки, в которых указаны единицы измерения (например 3 0 em). Целочисленные значения свойства позволяют проводить числовую обработку размера позиционируемого элемента. Того же эффекта можно добиться межплатформенно, применив метод parseInt () для непиксельных значений этих свойств. Свойства pixelBottom и pixelRight отсутствуют в МасШ4. Значение: целое число. Пример: elementRef .style. pixelTop = elementRef .style, pixel Top + 20; posBottom posHeight posLeft posRight posTop posWidth Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Контролирует: числовые значения расположения (первоначально позиционируемых) элементов. Непиксельные версии этих свойств возвращают строки, которые также содержат единицы измерения (например 1.2 em). Эти свойства позволяют вам работать исключительно с числовыми значениями в тех же единицах измерения, в которых стиль определен изначально. Того же эффекта можно добиться межплатформенно, используя метод parseFloat () в строковых версиях значений этих свойств. Значение: целое число. Пример: elementRef.style.posTop = elementRef.style.posTop + 0.5; Глава 26. Таблица стилей и объекты стилей 845
position Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: тип позиционируемого элемента. Элемент, который не позиционирован в явном виде, называется статическим. Относительно позиционируемый элемент появляется на странице в своем обычном месте, но может быть позиционирован в явном виде относительно текущего места расположения. Абсолютно позиционируемый элемент должен иметь атрибуты стиля top и left, заданные в качестве координат расположения элемента. МасШ5 и NN6/Moz/Safari предоставляют возможность фиксировать место расположения элемента. При этом элемент не изменяет своего положения даже при прокрутке страницы (например, для создания эффекта водяных знаков). В главе 39 приведена подробная информация о позиционировании элементов. Значение: константа absolute | fixed | relative | static. Пример: elementRef.style.position = "absolute"; zIndex Совместимость: WinIE4+, MacEE4+, NN6+, Mozl+, Safari 1+ Контролирует: уровень позиционируемых элементов относительно друг друга. Множественные элементы с одним и тем же значением z Index располагаются в порядке, заданном в исходном коде (первый элемент внизу). Значение: целое число; константа auto. Пример: elementRef . style. zlndex = "3"; Свойства фона background Совместимость: WinEE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: до пяти свойств фона элемента. Значение: комбинированные значения: backgroundAttachment | | background- Color] | backgroundlmage|| backgroundPosition|| backgroundRepeat. Пример: elementRef. style.background = "scroll url (bricks. jpg) repeat-x" ; backgroundAttachment Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: состояние фонового изображения: в фиксированном положении или прокручивается вместе с содержимым. По умолчанию scroll. Значение: константа fixed | scroll. Пример: elementRef.style.backgroundAttachment = "fixed"; backgroundColor Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: чистый, непрозрачный или полностью прозрачный цвет фона. Если вы расположите на странице фоновое изображение, цвет фона будет виден через любые прозрачные участки этого изображения. Значение: значение цвета; константа transparent. Пример: elementRef.style.backgroundColor = "salmon"; 846 Часть III. Объекты документа
backgroundlmage Совместимость: WinEE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: URL (если есть) изображение, которое используется в качестве фона изображения. Значение: значение URL; константа попе. Пример: elementRef.style.backgroundlmage = "url(bricks.jpg)"; backgroundPosition Совместимость: WinD34+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: расположение фонового изображения в левом верхнем углу. Любое смещение из левого верхнего угла (значение по умолчанию "0% 0%") позволяет цвету изображения просвечивать вдоль левой и верхней границы элемента. Значение: значения длины; процентные соотношения; константа left | center | right | | top | center | bottom. Можно задать единичные значения. Однако надежнее записать пары значений, разделив их пробелами. Пример: elementRef.style.backgroundPosition = "left top"; backgroundPositionX backgroundPositionY Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Контролирует: расположение левого (backgroundPositionX) и верхнего (backgroundPositionY) углов фонового изображения. Любое смещение из левого верхнего угла изображения (значение по умолчанию 0%) позволяет цвету изображения просвечивать вдоль левой и верхней границы элемента. Значение: значения длины; процентные соотношения; константа left | center | right (для backgroundPositionX); константа top | center | bottom (для backgroundPositionY). Пример: elementRef.style.backgroundPositionX = м5рх"; backgroundRepeat Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safaril+ Контролирует: параметр повторения фонового изображения. Изображение может повторяться вдоль одной оси. Значение: константа repeat | repeat-x | repeat-у | no- repeat. Пример: elementRef.style.backgroundRepeat = "repeat-у"; Свойства границ и полей border Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Контролирует: до трех характеристик границ (цвет, стиль и ширина) всех четырех границ элемента. Значение: комбинированные значения borderColor | | borderstyle | | borderWidth. Пример: elementRef.style.border = "green groove 2px"; Глава 26. Таблица стилей и объекты стилей 847
borderBottom borderLeft borderRight borderTop Совместимость: WinIE4+, MacBE4+, NN6+, Mozl+, Safari 1+ Контролирует: до трех характеристик (цвет, стиль и ширина) одной из границ элемента. Значение: комбинированные значения: (для borderBottom) borderBottomColor||borderBottomStyle||borderBottomWidth (для borderLef t) borderLeftColor||borderLeftStyle)|borderLeftWidth (для borderRight) borderRightColor||borderRightStyle||borderRightWidth (для borderTop) borderTopColor||borderTopStyle||borderTopWidth Пример: elementRef.style.borderLeft = "#3300ff solid 2px"; borderBottomColor borderLeftColor borderRightColor borderTopColor Совместимость: WinIE4+, MacIE4+> NN6+, Mozl+, Safari 1+ Контролирует: цвет границы одной из сторон элемента. Значение: значение цвета; константа transparent. Пример: elementRef.style.borderTopColor = "rgb(30%, 50%, 0%)"; borderBottomStyle borderLeftStyle borderRightStyle borderTopStyle Совместимость: WinEE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Контролирует: стиль границы одной из сторон элемента при отображении. Значение: константа none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset. Версии Ш для Windows более ранние, чем Ш5.5, не поддерживают значения dotted и dashed. MacIE не поддерживает значение hidden. Пример: elementRef.style.borderRightStyle = "double"; 848 Часть III. Объекты документа
borderBottomWidth borderLeftWidth borderRightWidth borderTopWidth Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: толщину границы элемента. Значение: значение длины; константа thin | medium | thick (точные размеры зависят от конкретного браузера). Пример: elementRef.style.borderBottomWidth = м5рх"; borderColor Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: цвет от одной до четырех сторон элемента при отображении. Значение: значения цвета от одной до четырех сторон прямоугольника. Пример: elementRef.style.borderColor = "green black"; borderStyle Совместимость: WinJE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: стиль от одной до четырех сторон элемента при отображении. Значение: от одного до четырех постоянных значений для сторон прямоугольника: попе | hidden | dotted | dashed | solid| double | groove | ridge | inset | outset. Версии Ш для Windows более ранние, чем IE5.5, не поддерживают значения dotted и dashed. Macffi не поддерживает значение hidden. Пример: elementRef.style.borderStyle = "ridge"; borderWidth Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: толщину границы от одной до четырех сторон элемента. Значение: значение длины от одной до четырех сторон прямоугольника или константы thin | medium | thick (точные размеры зависят от конкретного браузера). Пример: elementRef .style. borderWidth = "5рх 4рх 5рх Зрх"; margin Совместимость: WinIE4+, Macffi4+, NN6+, Mozl+, Safari 1+ Контролирует: толщину прозрачного поля за пределами границ от одной до четырех сторон элемента. Значение: значение длины от одной до четырех сторон прямоугольника. Пример: elementRef .style.margin = м10рх 5px" ; Глйва 26. Таблица стилей и объекты стилей 849
margixiBottom marginLeft marginRight marginTop Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Контролирует: толщину прозрачного поля за пределами границ одной стороны элемента. Значение: значение длины. Пример:elementRef.style.marginBottorn = и50рх"; mozBorderRadius mozBorderRadiusBottomLeft mozBorderRadiusBottomRight mozBorderRadiusTopLeft mozBorderRadiusTopRight Совместимость: Winffi-, Macffi-, NN7+, Mozl+, Safari Контролирует: радиус границы вокруг элемента. Вы можете отдельно задать радиус скругления каждого угла, воспользовавшись единым стилем mozBorederRadius, или определить каждый параметр с помощью собственного свойства. Значение: значение радиуса. Пример:elementRef.style.mozBorderRadius = п20рх Юрх 20 px lOpx"; mozOpacity Совместимость: Winffi-, MacIE-, NN7+, Mozl+, Safari Контролирует: степень прозрачности (непрозрачности) элемента, задаваемой в виде процентного числового значения. Чем меньше значение этого свойства, тем прозрачнее элемент. Значение: процентное или числовое значение, задаваемое в диапазоне от 0.0 до 1.0. Пример: elementRef.style.mozopacity = "75%"; outline Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari 1+ Контролирует: до трех характеристик контура, окружающего элемент (таких, как для границы; контур не должен смещать окружающее его содержимое). Этот стиль не имеет полной браузерной поддержки, хотя свойства отображены в объекте style. Значение: комбинированные значения outlineColor] | out lines tyle | |outlineWidth. Пример: elementRef.style.outline = "red groove 2px"; outlineColor Совместимость: Winffi-, Macffi5, NN6+, Mozl+, Safaril+ Контролирует: цвет всех четырех сторон контура. Этот стиль не имеет полной браузерной поддержки, хотя свойства отображены в объекте style. Значение: значения цвета; константа invert. Пример: elementRef.style.outlineColor = "cornflowerblue"; 850 Часть III. Объекты документа
outlineStyle Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safaril+ Контролирует: стиль всех четырех сторон контура элемента при отображении. Этот стиль не имеет полной браузерной поддержки, хотя свойства отображены в объекте style. Значение: константа none | hidden | dotted | dashed | solid | double | groove | ridge|inset|outset. Пример:elementRef.style.outlineStyle = "ridge"; outlineWidth Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari 1+ Контролирует: толщину всех четырех сторон контура элемента. Этот стиль не имеет полной браузерной поддержки, хотя свойства отображены в объекте style. Значение: значение длины от одной до четырех сторон прямоугольника или константы thin | medium | thick (точные размеры зависят от конкретного браузера). Пример: elementRef.style.outlineWidth = "4px"; padding Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: ширину отступа между содержимым элемента и границами от одной до четырех сторон. Значение: значение длины от одной до четырех сторон прямоугольника Пример: elementRef.style.padding = "5px"; paddingBottom paddingLeft paddingRight paddingTop Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: ширину отступа между содержимым элемента и границей одной стороны. Значение: значение длины. Пример: elementRef.style.paddingBottom = "20px"; Свойства списков listStyle Совместимость: WinIE4+, МасГ£4+, NN6+, Mozl+, Safari 1+ Контролирует: до трех характеристик представления содержимого страницы в виде списка (ol или ul). To же относится к элементам dd, dt и li. Значение: комбинированные значения liststylelmage | | listStylePositi- оп||listStyleType. Пример: elementRef.style.listStyle = "none inside lower-alpha"; Глава 26. Таблица стилей и объекты стилей 851
listStylelmage Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Контролирует: URL изображения, которое должно быть использовано в качестве маркера элемента списка. Значение: значение URL; константа попе. Пример: elementRef.style.listStylelmage = "url(custombullet.jpg)"; listStylePosition Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: форматирование маркера внутри текста, заключенного в список, или его расположение вне текста (по умолчанию). Значение: константа inside | outside. Пример: elementRef.style.listStylePosition = "inside"; listStyleType Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Контролирует: стандартный наборов маркеров, который должен использоваться для элементов списка. Изменение этого свойства для одного из элементов 1 i списка приводит к изменению стиля всех последующих элементов. Значение: для элементов ul константа circle [disc | square, для элементов ol константа decimal |lower-alpha|lower-roman|upper-alpha|upper-roman. Пример: elementRef.style.listStyleType = "upper-roman"; Свойства полосы прокрутки scrollbar3dLightColor scrollbarArrowColor scrollbarBaseColor scrolIbarDarkShadowColor scrollbarFaceColor scrollbarHighlightColor scrolIbarShadowColor scrolIbarTrackColor Совместимость: WinIE5.5+, МасШ-, NN-, Moz-, Safari- Контролирует цвета отдельных компонентов полосы прокрутки для таких элементов, как applet, body, div, embed, ob j ect или textarea. Если вы хотите узнать, как различные цвета влияют на отдельные компоненты, посетите Web-страницу http://msdn.microsoft.com/ workshop/samples/author/dhtml/refs/scrollbarColor.htm. Значение: значения цвета; константа попе. Пример: elementRef.style.scrollbarTrackColor = "hotpink"; 852 Часть III. Объекты документа
Свойства таблиц borderCollapse Совместимость: Winffi5+t MacffiS, NN6+, Mozl+, Safari- Контролирует: Соответствует ли элемент table модели раздельных границ CSS2 или модели совместных границ. В ffi5/Mac этот стиль не имеет полной браузерной поддержки. Значение: константа collapse | separate. Пример: elementRef.style.borderCollapse = "separate"; borderSpacing Совместимость: WinIE5+, МасШб, NN6+, Mozl+, Safari 1+ Контролирует: расстояние между прямоугольными ячейками в таблице соответствующей модели раздельных границ (подобно атрибуту cellspacing элементов table). В МасШ5 этот стиль не имеет полной браузерной поддержки. Значение: одно значение длины (для расстояния по горизонтали и по вертикали) или список из двух значений длины, разделенных запятыми (первое значение — по горизонтали, второе — по вертикали). Пример: elementRef. style. borderSpacing = " Юрх" ; captionSide Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safaril+ Контролирует: расположение элемента caption внутри элемента table. В Ш5/Мас этот стиль не поддерживается, а в NN6 поддерживается только частично. Значение: константа top | right | bottom | left. Пример: elementRef.style.captionSide = "bottom"; emptyCells Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari- Контролирует: отображение ячеек и их границ при отсутствии содержимого ячеек. По умолчанию границы вокруг пустых ячеек не отображаются. В МасГ£5 этот стиль не поддерживается. Значение: константа show | hide. Пример: elementRef. style.emptyCells = "show" ; tableLayout Совместимость: Winffi5+, MacEE5, NN6+, Mozl+, Safaril+ Контролирует: расширяется ли таблица в соответствии с заданной шириной первой строки ячеек или отображается только после задания ширины всех строк содержимого таблицы. Изменения, внесенные в это свойство после загрузки таблицы, на таблицу не влияют. Значение: константа auto | fixed. Пример: elementRef . style. tableLayout = "auto" ; Глава 26. Таблица стилей и объекты стилей 8S3
Свойства страницы и печати orphans widows Совместимость: WinlE-, MacIE5, NN6+, Mozl+, Safari- Контролирует: минимальное количество строк абзаца, которые должны отображаться внизу (orphans) или вверху (widows) страницы, если происходит обрыв страницы. Значение: целое число. Пример: elementRef.style.orphans = "4м; page Совместимость: WinlE-, Macffi5, NN6+, Mozl+, Safari- Контролирует: страницу (определенную в правиле ©page), к которой относится при печати текущий элемент. Значение: идентификатор, назначенный существующему правилу ©pageI Пример: elementRef.style.page = "landscape"; pageBreakAfter pageBreakBefore Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari- Контролирует: должна ли страница обрываться перед или после текущего элемента, а также тип разрыва страницы. Значение: константа auto | always | avoid | left | right. Пример: elementRef.style.pageBreakBefore = "always"; pageBreaklnside Совместимость: WinBE-, Macffi5, NN6+, Mozl+, Safari- Контролирует: допустим ли обрыв страницы внутри элемента. Значение: константа auto | avoid. Пример: elementRef.style.pageBreaklnside = "avoid"; size Совместимость: WinlE-, МасШ-, NN6+, Mozl+, Safari- Контролирует: размер или ориентацию страницы (заданную в правиле стиля с помощью свойства страницы). Используется для определения формата страниц. Значение: одно (одинаковое значение для ширины и высоты) или два значения длины, разделенные пробелом; константа auto | portrait | landscape. Пример: elementRef.style.size = "portrait"; 854 Часть III. Объекты документа
Дополнительные свойства accelerator Совместимость: WinIE5+, Macffi-, NN-, Moz-, Safari- Контролирует: определена ли для данного элемента ускоряющая клавиша. Значение: булево выражение. Пример: elementRef.style.accelerator = "true"; behavior Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- Контролирует: внешнее поведение, которое должно применяться к текущему элементу. Значение: список URL-адресов, разделенных пробелами. URL-адреса могут указывать место расположения файла, идентификатор элемента object или одно из встроенных поведений (по умолчанию). Пример: elementRef.style.behavior = "url(#default#anchorClick)"; cssText Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari- Контролирует: текст правила CSS (Только для чтения). Это свойство существует благодаря объектной модели браузера и не является частью спецификации CSS. Соответствующего атрибута CSS не существует. Значение: строка. Пример: var cssRuleText = elementRef.style.cssText; imeMode Совместимость: WinTE5+, Macffi-, NN-, Moz-, Safari- Контролирует: вводится ли текст в элемент input или элемент text area с помощью Input Method Editor (для таких языков, как китайский, японский или корейский). Значение: константа auto | active | inactive | disabled. Пример: elementRef.style.imeMode = "active"; Акустические свойства Эти свойства определены в спецификации CSS2, а в NN6 для них существуют заполнители. Однако такие свойства в NN6 не поддерживаются. Эквивалентные свойства сценария перечислены только для полноты изложения материала. Глава 26. Таблица стилей и объекты стилей 855
azimuth cue cueAfter cueBefore elevation pause pauseAfter pauseBefore pitch pitchRange playDuring richness speak speakHeader speakNumeral speakPunctuation speechRate stress voiceFcunily volume Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Контролирует: различные свойства, которые прежде всего рассчитаны на браузеры, поддерживающие синтез человеческой речи. Значение: подробную информацию об акустических таблицах стилей вы найдете по адресу: http://vynvw.w3 .org/TR/REC-CSS2/aural .html Объект фильтра Свойства Методы Обработчики событий См. текст Синтаксис Доступ к свойствам и методам объекта filter. (IE4+) document. all. obj ectID. stylef ilters [индекс] . свойство Iметод ([параметры]) (IE5.5+) document .all. obj ectID. stylef ilters [имяФимьтра] . свойство / метод ( [параметры] ) Совместимость: WinBE4+, MacIE-, NN-, Moz-, Safari- 856 Часть III. Объекты документа
Описание объекта В этой главе речь уже шла о свойстве style .filter, позволяющем получать и изменять строковое значение, назначенное свойству style .filter элемента. Фильтры используются только в системе Ш для Windows. Ш5/Мас это свойство не поддерживает, хотя и возвращает значение свойства style, filter. Задача данного раздела состоит в том, чтобы научить вас применять фильтры при написании сценария. Множественные фильтры — это только часть списка фильтров, элементы которого отделяются пробелами. Для некоторых типов фильтров существуют дополнительные спецификации. Например, фильтр glow () обладает тремя свойствами, которые позволяют более четко задавать; каким образом должен отображаться элемент с эффектом подсветки. Правило таблицы стилей для элемента с идентификатором glower выглядит следующим образом. #glower {filter:glow(color=yellow# strength=5/ enabled=true)} Свойство currentStyle. filter для этого элемента имеет следующее строковое значение. glow(color=yellow, strength=5, enabled=true) Попытка изменить единичное подсвойство фильтра glow () путем синтаксического разделения строки не даст положительных результатов. Не стоит, например, пытаться добавить к свойству strength данного фильтра значение 5. Получение и изменение подсвойств Работать с индивидуальными свойствами фильтра удобнее всего, обращаясь к фильтру как к объекту элемента, на который этот фильтр оказывает влияние. Каждый тип объекта фильтра имеет свои индивидуальные подсвойства, которые вы задаете в таблице стилей. Приведя в качестве примера фильтр glow (), заметим, что обратиться только к свойству color можно следующим образом. var currColor = document.all.glower.currentStyle.filters["glow"].color; Для получения значения ссылка задается с помощью свойства currentStyle, поскольку в данном случае фильтр задан в определении таблицы стилей, и только свойство currentStyle может показать воздействующие на данный элемент свойства стиля. Для изменения цвета необходимо задать новое значение свойству filter объекта с помощью свойства style элемента. document.all.glower.style.filters["glow"].color = "green"; Для того чтобы добавить к свойству strength фильтра glow () значение 5, используйте следующую синтаксическую конструкцию (какой бы громоздкой она вам ни казалась). document.all.glower.style.filters["glow"].strength = document.all.glower.currentStyle.filters["glow"].strength + 5; В табл. 26.1 перечислены имена объектов фильтра, которые поддерживаются браузерами версий Г£4 и более современными, а также свойства, относящиеся к каждому типу фильтра. Кроме статических типов фильтров, которые применяются к содержимому и изменяются в сценариях, объект filter IE4+ предоставляет ряд возможностей по преобразованию одного изображения в другое и изменению видимого элемента в скрытый. Задать преобразование изображения от видимого к скрытому можно в нескольких строках кода, используя при этом некоторые методы объекта filter. В табл. 26.2 представлен синтаксис фильтров преобразования. Глава 26. Таблица стилей и объекты стилей 857
Имя фильтра Описание и свойства alpha () blur О chroma() dropShadow() flipHO flipVO glow() gray() invert() light() mask () Степень прозрачности Свойства: opacity (ОТ О ДО 100) f inishopacity (ОТ 0 ДО 100) style (градиентная форма от 0 до 3) startx (координата, выраженная целым числом) startY (координата, выраженная целым числом) finishx (координата, выраженная целым числом) f inishY (координата, выраженная целым числом) Имитация размытого изображения Свойства: add (1 или 0) direction (0,45, 90,135,180, 225, 270, 315) strength (число пикселей) Прозрачность цвета Свойства: color (значение цвета) Эффект тени Свойства: color (значение цвета) of f х (горизонтально смещенные пиксели) of f у (вертикально смещенные пиксели) positive (1 ИЛИО) Горизонтально отраженное изображение Свойства: отсутствуют Вертикально отраженное изображение Свойства: отсутствуют Подсветка внешних граней Свойства: color (значение цвета) strength (интенсивность от 1 до 255) Удалить цвет Свойства: отсутствуют Контрастный цвет, насыщенность, уровень яркости Свойства: отсутствуют Добавить источник света (контролируется методами) Свойства: отсутствуют Наложение прозрачной маски Свойства: color (значение цвета) 858 Часть III. Объекты документа
Окончание табл. 26.1 Имя фильтра Описание и свойства shadow () Отобразить в виде силуэта Свойства: color (значение цвета) direction (0,45, 90,135,180, 225, 270, 315) wave () Добавить синусоидальное искажение Свойства: add(1 илиО) f req (целое число волн) light (интенсивность от 0 до 100) phase (процент смещения от 0 до 100) strength (интенсивность от 1 до 255) xRay () Отображать только грани Свойства: отсутствуют Имя фильтра Описание и свойства biendTrans () Постепенно исчезает старый элемент и проявляется новый Свойства: duration (количество секунд, заданных с плавающей запятой) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет преобразование) stop () (останавливает процесс преобразования) reveaiTrans () Показывает новый вид элемента Свойства: duration (количество секунд, заданных с плавающей запятой) transition (номер кода, соответствующий тому или иному эффекту) 0 Box in 1 Расширяющийся прямоугольник 2 Сужающийся круг 3 Расширяющийся круг 4 Стирание вверх 5 Стирание вниз. 6 Стирание вправо 7 Стирание влево 8 Вертикальные жалюзи 9 Горизонтальные жалюзи ю Шахматная развертка по ширине 11 Шахматная развертка по высоте 12 Произвольное растворение Глава 26. Таблица стилей и объекты стилей 859
Окончание табл. 26.2 Имя фильтра Описание и свойства 13 Вертикальное внешнее растрескивание 14 Вертикальное внутреннее растрескивание 15 Горизонтальное внешнее растрескивание 16 Горизонтальное внутреннее растрескивание 17 Смывание слева вниз 18 Смывание слева вверх 19 Смывание справа вниз 20 Смывание справа вверх 21 Произвольное горизонтальное испещрение 22 Произвольное вертикальное испещрение 23 Произвольный эффект Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет преобразование) stop () (останавливает процесс преобразования) Для того чтобы преобразование от одного элемента к другому происходило под контролем сценария, фильтр должен быть применен к тому элементу, с которого начинается процесс. Сделать это можно, записав соответствующий код или назначив элементу стиль фильтра. Если вы решили добавить преобразование в сценарий, примените метод apply О соответствующего объекта filter. Затем запишите проводимые изменения— например, назначьте новый URL свойству scr элемента img. Пока вы выполняете'эту операцию, метод apply () фиксирует изображение, оставляя его неизменным. Листинг 26.1 представляет шахматную развертку одного изображения вместо другого после щелчка на нем. <html> <head> <title>IE4+ Transition</title> <style type=Mtext/css"> img {filter:revealTrans(transition=10)} </style> <script type="text/javascript"> function doRevealO { document.all.myIMG.filters["revealTrans"].apply(); if (document.all.myIMG.src.indexOf("deskl") != -1) { document.all.mylMG.src = "desk3.gif"; } else { document.all.myIMG.src = "deskl.gif"; } document.all.mylMG.filters["revealTrans"].playO; } </script> </head> <body> <hl>IE4+ Transition</hi> 860 Часть III. Объекты документа
<hr /> <p>Click on the image to cause a reveal transition.</p> <img alt="image" id="myIMG" src="deskl.gif" height="90" width="120" onclick="doReveal()" /> </body> </html> Основываясь на примере, приведенном в листинге 26.1, в листинг 26.2 продемонстрируем, как сценарий может изменить свойство объекта filter, в том числе и фильтра преобразования. Перед применением метода apply () сценарий задает тип перехода на основе одно- го из элементов списка select, выбранного пользователем. <html> <head> <title>IE4+ Transition and Choices</title> <style type="text/ess"> img {filter:revealTrans(transition=10)} </style> <script type="text/javascript"> function doRevealO { document.all.myIMG.fiIters["revealTrans"].transition = document.forms[0].transChoice.value; document.all.mylMG.filters["revealTrans"] .apply 0; if (document.all.mylMG.src.indexOf("deskl") " != -1) { document.all.myIMG.srс = "desk3.gif"; } else { document.all.mylMG.src = "deskl.gif"; } document.all.myIMG.filters["revealTrans"].playO; } </script> </head> <body> <hl>IE4+ Transition and Choices</hl> <hr /> <form> <p>Choose the desired transition type: <select name= "transChoice"> <option value="0">Box in</option> <option value="l">Box out</option> <option value="2">Circle in</option> <option value="3">Circle out</option> <option value="4">Wipe up</option> <option value="5">Wipe down</option> <option value="6">Wipe right</option> <option value="7">Wipe left</option> <option value="8">Vertical blinds</option> <option value="9">Horizontal blinds</option> <option value="10">Checkerboard across</option> <option value="11'^Checkerboard down</option> <option value="12">Random dissolve</option> <option value="13">Split vertical in</option> <option value="14">Split vesical out</option> <option value="15">Split horizontal in</option> Глава 26. Таблица стилей и объекты стилей 861
<option value="16">Split horizontal out</option> <option value="17">Strips left down</option> <option value="18">Strips left up</option> <option value="19">Strips right down</option> <option value=n20">Strips right up</option> <option value="21">Random bars horizontally</option> <option value="22">Random bars vertically</option> <option value="23">Random effect</option> </selectx/p> </form> <p>Click on the image to cause a reveal transition.</p> <img alt="image" id="myIMG" src="deskl.gif" height="90" width="120" onclick="doReveal()" /> </body> </html> Изменение синтаксиса фильтров в 1Е5.5 WinIE5.5 не только поддерживает способ управления фильтрами, принятый в ГБ4, но и предлагает некоторые нововведения, которые Microsoft настоятельно рекомендует использовать (об этом свидетельствует тот факт, что на страницах Web-узла данной компании очень сложно найти документацию для синтаксиса ГЕ4). В результате указанных нововведений имена многих фильтров, как и их отдельных свойств, были изменены. Более того, изменился и метод применения компонентов фильтров в таблице стилей. Синтаксис таблицы стилей предполагает ссылку на новый компонент и имя фильтра. Вот как это выглядело для ГЕ4. #glower {filter:glow(color=yellow, strength=5, enabled=true)} Запись для ГЕ5.5 выглядит следующим образом. #glower {filter:progid:DXImageTransform.Microsoft.Glow(color=yellow/ strength=5, enabled=true)} He пропустите дополнительный указатель progid:. Этот программный идентификатор становится частью имени фильтра, которое используется в сценарии для ссылки на этот фильтр. document.all.glower.style.filters["DXIraageTransform.Microsoft.Glow"]. color - "green"; Некоторые имена фильтров остались неизменными (была добавлена только приставка), остальные — отнесены к категории новых фильтров, их свойства помогают получить специфические эффекты. Функции фильтра, ранее называемого reveal Trans (), в новой версии распределены между несколькими новыми фильтрами, которые создают эффект перехода от одного изображения к другому. В табл. 26.3 представлен синтаксис для ГЕ5.5+. / Использование синтаксиса IE5.5+ может привести к проблемам отображения /нааанпку вашей страницы браузерами (по крайней мере, браузерами более ранних версий). * ^^ Чаще всего трудности возникают при передаче эффекта преобразования одного изображения в другое. Если вы все же решили пользоваться синтаксисом IE6+, обязательно проверьте, как отображаются страницы разными версиями браузеров. 862 Часть III. Объекты документа
Имя фильтра Описание и свойства Alpha () Степень прозрачности Свойства: opacity (ОТ О ДО 100) f inishopacity (ОТ 0 ДО 100) style (градиентная форма от 0 до 3) startx (координата, выраженная целым числом) startY (координата, выраженная целым числом) finishx (координата, выраженная целым числом) finishY (координата, выраженная целым числом) ват () Эффект закрывающихся дверей Свойства: duration (количество секунд, заданное с плавающей запятой) движение (in или out) размещение (horisontal ИЛИ vertical) percent (ОТ 0 ДО 100) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) Basicimage () Вращение элемента, зеркальное отображение, цветовые эффекты и непрозрачность Свойства: grayscale (1 ИЛИ 0) invert (1 ИЛИ 0) mask (1 ИЛИ 0) maskcoior (значение цвета) mirror (1 ИЛИ0) opacity (ОТ 0.0 ДО 1.0) rotation 0 (нет вращения), 1 (90°), 2 (180°), 3 (270°) xRay (1 или 0) Bl inds () Эффект жалюзи Свойства: направление (up, down, right, left) squaresx (целое число столбцов) squaresY (целое число строк) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop о (останавливает процесс перехода) Глава 26. Таблица стилей и объекты стилей 863
Продолжение табл. 26.3 Имя фильтра Описание и свойства Checkerboard() Chroma() DropShadow() Fade() Glow() Iris () Эффект шахматной развертки Свойства: bands (ОТ 1 ДО 100) направление (up, down, right, left) duration (количество секунд с плавающей запятой) percent (от 0 до 100) slideStyle (HIDE, PUSH, SWAP) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) Прозрачность цвета Свойства: color (значение цвета) Эффект тени Свойства: color (значение цвета) of f х (горизонтально смещенные пиксели) of f у (вертикально смещенные пиксели) positive (1 ИЛИО) Плавный переход одного элемента в другой Свойства: duration (количество секунд с плавающей запятой) overlap (от 0.0 ДО 1.0) percent (ОТ 0 ДО 100) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) Подсветка внешних граней Свойства: color (значение цвета) strength (интенсивность от 1 до 255) Эффект изменения масштаба Свойства: duration (количество секунд с плавающей запятой) irisStyle (CIRCLE, CROSS, DIAMOND, PLUS, SQUARE, STAR) motion (in ИЛИ out) 864 Часть III. Объекты документа
Продолжение табл. 26.3 Имя фильтра Описание и свойства percent (от О ДО 100) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) Light () Добавление источника света (контролируется методами) Свойства: отсутствуют Методы: addAmbient (red, green, blue, strength) addCone (sourceLeft, sourceTop, sourceZAxis, targetLeft, targetTop, red, green, blue, strength, spreadAngle) addPoint (sourceLeft, sourceTop, sourceZAxis, red, green, blue, strength) changeColor (lightID, red, green, blue, absoluteColorFlag) changestrength (lightID, strength, absolutelntensityFlag) clear() moveLight (lightID, sourceLeft, sourceTop, sourceZAxis, absoluteMovementFlag) MaskFilter () Наложение прозрачной маски Свойства: color (значение цвета) MotionBlur () Имитация нечеткого изображения Свойства: add (1 или 0) direction (0, 45, 90,135,180, 225, 270, 315) strength (число пикселей) RandomDissoive () Эффект растворения Свойства: duration (количество секунд с плавающей запятой) percent (от 0 до 100) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) RandomBars () Эффект испещрения Свойства: duration (количество секунд с плавающей запятой) orientation(horisontalИЛИ vertical) percent (от 0 до 100) Глава 26. Таблица стилей и объекты стилей 865
Окончание табл. 26.3 Имя фильтра Описание и свойства Shadow() Stripes() Wave() xRay() status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play О (выполняет переход) stop () (останавливает процесс перехода) Отобразить в виде силуэта Свойства: color (значение цвета) direction (0, 45, 90,135,180, 225, 270, 315) Эффект нанесения полос Свойства: duration (количество секунд с плавающей запятой) motion (in ИЛИ out) percent (ОТ 0 ДО 100) status 0 (приостановлен), 1 (применен), 2 (в процессе) Методы: apply () (фиксирует текущее состояние изображения на экране) play () (выполняет переход) stop () (останавливает процесс перехода) Синусоидальное искажение Свойства: add (1 или 0) f req (целое число волн) light (интенсивность от 0 до 100) phase (процент смещения от 0 до 100) strength (интенсивность от 1 до 255) Отображение только границ Свойства: отсутствуют Более полную информацию об использовании фильтров в_ Г£ для Windows вы найдете по адресу: http://msdn.microsoft.com/workshop/author/filter/filters.asp. Поскольку большинство примеров требуют WinlE, рекомендуется просматривать указанные Web-страницы, используя браузер именно этой версии. 866 Часть III. Объекты документа
Объекты языка JavaScript
Объект string |^в\ главе 6 были представлены концепции значений и их "—^ типов, с которыми работает JavaScript: строки, числа и логические значения. В этой главе рассматривается строковый тип данных, а также его взаимосвязь с числовым типом. Кроме того, демонстрируются различные способы обработки текстовых строк. / Большинство синтаксических конструкций, с ко- /на заметку торыми вы встретитесь в этой главе, идентич- * „^-^ ны представленным в языке программирования Java. Поскольку область применения JavaScript несравненно уже, чем у Java, создание сценариев на JavaScript требует меньшего опыта, чем программирование на Java. В то же время определенные свойства строковых объектов можно применять только в сценариях (но не в Java). Усовершенствование методов строкового объекта в NN4 значительно упростило задачу по обработке текста. Однако, если разрабатываемая страница предназначена и для ранних версий браузеров, вам потребуются определенные навыки, присущие программистам на языке С. В этой главе приведено несколько функций общего назначения, которыми вы сможете пользоваться в своих сценариях. Типы данных string и number JavaScript не требует строгой типизации переменных, однако следует проявлять осторожность при работе с определенными типами данных. В этом разделе речь пойдет о строковых и двухчисловых типах данных. Простые строки Строка состоит из одного или более стандартных текстовых символов, заключенных в кавычки. JavaScript позволяет использовать (с обеих сторон строки) и одинарные, и двойные
кавычки. Достоинство этого подхода проявляется, например, при включении одной строки в кавычках в другую. Пусть, например, HTML-код записывается в переменную, которая затем выводится в новом окне, полностью управляемом сценарием JavaScript. Строка текста имеет следующий вид. <input type="checkbox" name="candy" />Chocolate Чтобы присвоить всю строку переменной, ее необходимо заключить в кавычки. По причине того, что кавычки присутствуют в самой строке, JavaScript (как и любой другой язык) не знает, где начинается или заканчивается строка. Присвоение будет проведено корректно, если воспользоваться другим типом кавычек. Представим два эквивалентных способа. result = '<input type="checkbox" name="candy" />Chocolate'; result = "<input type='checkbox' name='candy' />Chocolate"; Обратите внимание, что строка заключена в кавычки одного типа. Внутри содержатся еще две строки, заключенные в кавычки. Рекомендуется выбрать одну из форм и использовать ее повсеместно в сценариях. Создание длинных строковых переменных Объединение строк — конкатенация — позволяет получить длинную строку на основе нескольких подстрок. Это свойство является чрезвычайно важным при решении некоторых задач Web-программирования (например, если вся HTML-страница создается в одной переменной, которая выводится на другой странице или фрейме методом document. write ()). Рекомендуется использовать как можно более короткие выражения, чтобы улучшить читаемость текста. В этом случае используется оператор сложения с присвоением (+=); он добавляет выражение из правой части к выражению в левой части. Ниже приведен простой пример, в котором переменная инициализируется пустой строкой. var newDocument = ""; newDocument += "<htmlxheadxtitle>Life and Times</titlex/head>" ; newDocument += "<bodyxhl>My Life and Welcome to It</hl>"; newDocument += "by Sidney Finortny<hr />"; Начиная со второй строки, в каждом операторе переменной newDocument присваивается новый блок данных. ^Этот процесс можно продолжать до тех пор, пока в переменной newDocument не будет сохранена вся страница. Избегайте использования оператора сложения с присвоением, который существенно увеличивает длину текстовой строки. Если при управлении текстовыми строками наблюдается излишняя медлительность, то попробуйте разбить длинную строку на массив текстовых элементов (глава 30). Используйте метод join О массива для объединения массива текстовых элементов обратно в единую текстовую строку. Объединение строк и переменных В некоторых случаях возникает необходимость в создании строки на основе строк (символов, заключенных в кавычки) и строковых переменных. Методы конкатенации таких типов данных ничем не отличаются от конкатенации нескольких обычных строк. Операция обозначается символом "+". В следующем примере в переменной содержится имя, которое затем используется как часть более сложной строки. yourName = prompt("Please enter your name:",""); var msg = "Good afternoon, " + yourName + "."; alert(msg); / Ha Глава 27. Объект string 869
В подобных операциях конкатенации возникают такие проблемы. ■ Отсутствие (случайное) одной из кавычек, в которые должна быть заключена строка. ■ Отсутствие пробелов в строках (в результате строка и переменная конкатенируются без разделителя). ■ Отсутствие знака пунктуации в строке, следующей за значением переменной. Кроме того, помните, что переменная, приведенная в примере, может быть любым выражением, результатом которого является строка (в том числе ссылки на свойства и результаты выполнения некоторых методов). var msg = "The name of this document is " + document.title + "."; alert(msg); Специальные символы При управлении строками в языке JavaScript иногда возникают трудности с использованием определенных символов. В первую очередь, речь идет о кавычках, символе возврата каретки, апострофах и символе табуляции. К счастью, JavaScript обеспечивает механизм применения в строках и таких вспомогательных символов. Для этого перед специальным символов вводят символ обратной косой черты. Символ косой черты определяет место в строке, в котором введен невидимый в обычном представлении для JavaScript символ. Наиболее распространены следующие пары (обратная косая черта-символ). V V \\ \ь \t \п \г \f Двойная кавычка Одинарная кавычка (апостроф) Обратная косая черта Символ <Backspace> Табуляция Новая строка Возврат каретки Символ подачи страницы Эти "внутренние символы" (известные еще как знаки перехода — данная терминология приобрела дополнительное значение для строк, используемых в Internet) задают внутри строк, заключенных в кавычки. При создании блока текста, в котором необходимо определить новый абзац, вставьте в соответствующем месте пару символов \п. msg = "You\'re doing fine."; msg = "This is the first line.\nThis is the second line."; msg = document.title + "\n" + document.links.length + " links present."; Технически операция возврата каретки (как известно со времен печатных машинок) состоит из двух действий: перевода строки (т.е. прокрутки на одну строку) и возврата каретки (перемещения каретки к левому краю). В строках JavaScript символ новой строки (\п) рассматривается как полный возврат каретки, однако его можно задать в комбинации \г\п. Используемый формат зависит от средств обработки текста в CGI-программе. (О специальных требованиях к объекту text area вы можете узнать в главе 20.) Не путайте строки, отображаемые в объектах text are а или диалоговых окнах, со строками HTML-кода. В HTML-строках используйте стандартные дескрипторы (<br> — для перевода строки и <р> — в начале нового параграфа), а не внутреннее представление специальных символов. 870 Часть IV. Объекты языка JavaScript
Объект string Свойства constructor length prototype* Методы anchor() big() blink() bold() charAt() charCodeAt() concat() fixed() fontcolor() fontsize() fromCharCode()* indexOf() italics() lastlndexOf() linkO localeCompare() match() replace() search() slice() small() split() strike() sub() substr() substring() sup() toLocaleLowerCase() toLocaleUpperCase() toLowerCase() toStringO toUpperCase() valueOf() * Для статического объекта string Глава 27. Объект string 871
Синтаксис Создание строкового объекта. var myString = new String("characters"); Доступ к свойствам и методам статического объекта string. string. свойство \ метод{ [параметры] ) Доступ к свойствам и методам строкового объекта. строка. свойство \ метод ( [параметры] ) Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Описание объекта JavaScript различает строковые значения и строковые объекты. И те, и другие используют одинаковые методы, поэтому обычно для присвоения переменной строкового значения нет необходимости создавать объект (конструктором String О). Для этого требуется лишь обычная операция присвоения (var myString = "fred"). Различия проявляются там, где используется "объектность" строкового элемента. Подробно об этом рассказано при изучении свойства string.prototype (далее в этой главе). Кроме того, использование полноценного строкового объекта может понадобиться при передаче данных Java-аплету. Если оказывается, что аплет не воспринимает строковое значение как тип данных String, следует создать новый объект (с помощью конструктора JavaScript) и передать его аплету. В сценариях часто возникает необходимость обработки строковых данных. Кроме конкатенации строк, можно извлекать подстроки, удалять части строк или заменять их другим текстом. В отличие от многих языков написания сценариев, JavaScript практически не имеет встроенных средств обработки строк. Это значит, что методы обработки строки необходимо программировать самостоятельно (если только вы не воспользуетесь регулярными выражениями, поддерживаемыми в браузерах NN4+ и Ш4+). Далее в этой главе приведен исходный код нескольких функций, которые полностью совместимы с более ранними версиями браузеров. При работе каждое строковое значение необходимо представить в качестве объекта, имеющего свойства и методы (как и любой другой объект JavaScript). В последних версиях JavaScript определено несколько свойств и методов для работы со строковыми значениями (и одно дополнительное свойство статического объекта String, которое всегда присутствует в окне браузера). Синтаксис вызова строковых методов такой же, как и методов любого другого объекта. o6%eKTString.method() Частью ссылки на строковый объект может быть любое выражение, результатом выполнения которого является строка, содержащая обычные строки, переменные, методы или функции, возвращающие строки, или другие свойства объекта. Поэтому все приведенные ниже примеры вызова метода toUpperCase () работают одинаково. "george burns".toUpperCase() yourName.toUpperCase() // yourName — строковая переменная window.prompt("Enter your name" , " ")•toUpperCase() document.forms[0].entry.value.toUpperCase() // entry — текстовое поле объекта Важно помнить следующее: вызов строкового метода не изменяет объект, который является частью ссылки. Вместо этого метод возвращает значение, используемое как параметр вызова другого метода (функции) или для присвоения переменной. 872 Часть IV. Объекты языка JavaScript
Поэтому для изменения содержимого строковой переменной (влияющей на результат выполнения метода) необходимо воспользоваться оператором присвоения. yourName = yourName.toUpperCase(); // значение переменной теперь // включает только прописные буквы Свойства constructor Значение: ссылка на функцию Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Свойство constructor является ссылкой на функцию, вызванную для создания текущей строки. Для естественного строкового объекта в JavaScript функцией-конструктором является String (). При создании новой строки конструктором new String () типом значения, возвращаемым им, является object (т.е. оператор typeof возвращает значение object). Поэтому свойством constructor можно воспользоваться для проверки "строковое™" объекта. if (typeof someValue == "object" ) { if (someValue.constructor == String) { // операторы обработки объекта string } } Несмотря на то, что это свойство предназначено для чтения и записи, а свойству String.prototype можно присвоить другое значение конструктора, естественное поведение объекта string заключается в использовании старого конструктора. Пример Приложение The Evaluator (глава 13) можно использовать для изучения свойства constructor. Введите в верхнем текстовом поле следующее выражение. а = new String("abed") a.constructor == String a.constructor == Number См. также: свойство prototype. length Значение: целочисленное Только для чтения Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Наиболее часто используемым свойством строкового объекта является length. Оно содержит длину строки. Обращение к нему происходит так же, как к свойству length любого другого объекта. 1 string.length Это целочисленное значение равно количеству символов в строке. Символами также считаются пробелы и знаки пунктуации. Все специальные символы, начинающиеся с обратной' косой черты, считаются одиночными, включая символы новой строки и табуляции. Ниже приведено несколько примеров. "Lincoln".length // результат 7 "Four score".length // результат 10 Глава 27. Объект string 873
"One\ntwo".length // результат 7 "".length // результат О Свойство length часто используется, например, при обработке строк в циклах. prototype Значение: объект Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Строковые объекты, создаваемые конструктором new String("строка"), являются более значимыми объектами, чем обычные переменные, которым присвоены строковые значения. Разумеется, создавать такие объекты для всех строк в сценарии нет необходимости. Однако в некоторых случаях они могут оказаться полезными. Например, значения в переменных могут стать некорректными при попытке сохранения информации в других фреймах или окнах. Используя конструктор строкового объекта, можно быть уверенным в том, что строковое значение будет доступно другим фреймам. Еще одним достоинством строковых объектов является возможность присвоения прототипов свойств и методов всем строковым объектам документа. Прототип представляет собой свойство или метод, который становится частью каждого нового объекта при его создании. Для строк, например, можно создать метод, предназначенный для преобразования строки в новый тип дескриптора шрифта, который не встроен в JavaScript по умолчанию. В листинге 27.1 представлен процесс создания и использования прототипа. <html> <head> <title>String Object Prototype</title> <script type="text/javascript"> function makeltHotO { return "<font color='red'>" + this.toString() + "<\/font>"; } String.prototype.hot « makeltHot; </script> / </head> <body> <script type="text/javascript"> document.write("<hl>This site is on " + "FIRE".hot() + "!!<\/hl>"); </script> </body> </html> Функция (makeltHot ()) накапливает строковые данные, которые возвращаются в объект, когда она вызывается как метод. Ключевое слово this указывает на объект, вызвавший функцию, который преобразуется в строку для последующей конкатенации. В разделе тела страницы прототип метода вызывается так же, как и существующие методы объекта string, превращающие строки в дескрипторы HTML (они рассмотрены далее). В следующих разделах методы строкового объекта разделены на две категории. В первой описываются методы синтаксической обработки, во второй — методы форматирования, используемые для вывода текста в новые документы или другие фреймы. 874 Часть IV. Объекты языка JavaScript
Методы синтаксического анализа строка.charAt(индекс) Возвращаемое значение: односимвольная строка Совместимость: Winffi3+> МасЕЕЗ+, NN2+, Mozl+, Safari 1+ Метод строка. charAt () используется для чтения символа, находящегося в определенной позиции в строке. Аргументом метода является индекс. Индекс первого символа равен 0. Для получения последнего символа воспользуйтесь комбинацией строковых методов. myString.charAt(myString.length — 1) Используется метод строка, substring(), если сценарию требуется получить несколько символов, Попытка применения этого метода для извлечения одного символа является распространенной ошибкой — метод строка. charAt () работает гораздо эффективнее. Пример Введите каждое из приведенных далее выражений в верхнее текстовое поле приложения The Evaluator. а = "banana daiquiri" а.charAt(0) а.charAt(5) а.charAt(б) a.charAt(20) Эти методы возвращают Ь, а (третий символ а в слове banana), пробел и пустую строку, соответственно. См. также методы строка. lastlndexOf (), строка. indexOf (), строка. substring (). строка.charCodeAt([индекс]) строка.fromCharCode(ном! [, ном2 [, ... номп]]) Возвращаемое значение: целочисленный код символа; строка, конкатенированная из символов, коды которых указаны как аргументы. Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safari 1+ Преобразование символов в числовые эквиваленты представляет собой давнюю традицию в программировании. В течение долгого времени применялся стандарт ASCII, описывающий символы английского алфавита, буквенно-цифровые символы и символы пунктуации, — всего 128 значений (от 0 до 127). Расширенная версия этого стандарта включает 256 символов. Их точное значение зависит от операционной системы. Обычно это дополнительные символы других романских языков. Для того чтобы обеспечить поддержку нероманских и пиктографических языков, был разработан стандарт Unicode, поддерживающий несколько тысяч различных символов. В JavaScript преобразование символов в коды достигается с помощью строковых методов. Допустимые значения зависят от конкретной версии браузера. NN4 работает только с 256 символами стандарта ISO-Latin-I; NN6+ и DE4+ поддерживают систему Unicode. Два метода, выполняющих преобразование, синтаксически работают по-разному. Первый, строка. charCodeAt (), преобразует один символ строки в его числовой эквивалент. Конвертируемая строка указывается как объект перед именем метода — это может быть обычная строка в кавычках или любое выражение, результатом выполнения которого является строка. Если аргумент метода не указан, возвращается код первого символа строки. Для обработки другого символа следует указать его индекс (индекс первого символа равен 0). Глава 27. Объект string 875
"abc".charCodeAt() // результат 97 "abc".charCodeAt(0) // результат 97 "abc".charCodeAt(1) // результат 98 Если строка является пустой или значение индекса находится за пределами допустимого диапазона, результатом выполнения метода будет NaN. Для преобразования числовых значений в соответствующие им символы используется метод строка. f romCharCode (). Обратите внимание, что объект, вызывающий метод, является статическим объектом string, а не строковым значением. В качестве аргументов можно указать одно или несколько целочисленных значений, разделенных запятыми. В процессе преобразования метод объединяет все символы в одну строку, как в следующем примере. String.fromCharCode(97, 98, 99) // результат "abc" I Метод строка. charCodeAt () работает некорректно в первой подверсии брау- /назаигау зера MacNN4: он всегда возвращает значение NaN. Эта ошибка исправлена ' **** в последующих версиях. Пример Пример использования обоих методов приведен в листинге 27.2. Поскольку в этом примере выполняется захват выделенного на странице текста, то в сценарий включен код обработки событий выделения в различных браузерах. <html> <head> <title>Character Codes</title> <script type="text/javascript"> function showCharCode() { var theText = ""; if (window.getSelection) { theText = window.getSelection().toString(); } else if (document.getSelection) { theText = document.getSelection(); } else if (document.selection && document.selection.createRange) { theText = document.selection.createRange().text; if (theText) { document♦forms[0].charCodeDi splay.value = theText.charCodeAt(); } else { document.forms[0].charCodeDisplay.value = " "; } function showString(form) { form.result.value = String.fromCharCode(form.entryl.value, form.entry2.value,form.entry3.value); }• document.onmouseup = showCharCode; </script> \ </head>. <body> <b>Capturing Character Codes</b> <form> 876 Часть /V. Объекты языка JavaScript
Select any of this text, and see the character code of the first character. <p>Character Code:<input type="textn name="charCodeDisplay" size="3" /xbr /></p> <hr /> <b>Convertihg Codes to Characters</bxbr /> * Enter a value 0-255:<input type="textM name="entryl" size=n6n /xbr /> Enter a value 0-2 55:<input type=Mtext" name="entry2" size="6" /xbr /> Enter a value 0-255:<input type="text" name="entry3" size="6" /xbr /> <input type="button" value=MShow String" onclick=MshowString(this.form)" /> Result:<input type="text" name=Mresult" size="5" /> </form> </body> </html> После загрузки страницы выделите произвольный текстовый фрагмент. Если выделение начинается с символа а, то будет отображен код символа 97. Если же вы не выделите текст на странице, то будет возвращено значение NaN. Введите числовые значения в три текстовых поля в нижней части страницы. Значения меньше 32 представляют символы ASCII специального назначения, которые в большинстве шрифтов отображаются в виде пустотелых квадратиков. Но все же попробуйте ввести и эти числовые коды. Обратите внимание на то, что коды со всех трех значений подставляются в метод строка. f romCharCode как единое значение, поэтому в качестве результата возвращается комбинированная строка. На рис. 27.1 показан результат ввода во всех трех полях кодов для прописных символов. строка.coneat(строка2) Возвращаемое значение: комбинация строк. Совместимость: WinIE4+, MacEE4+, NN4+, Mozl+, Safaril+ Оператор сложения с присвоением (+=) в JavaScript обеспечивает удобный способ конкатенации строк. Современные браузеры поддерживают строковый метод, выполняющий ту же задачу. Строка, к которой добавляется текст, является объектом или значением, вызывающим метод. Добавляемая строка является аргументом метода. "abc".concat("def') // результат: "abedef" Как и оператор сложения с присвоением, метод concat () ничего не знает об окончаниях слов. Поэтому, если требуется добавить пробел, его следует указывать явно. См. также: оператор сложения с присвоением (+=). строка.indexOf(строкаПоиска [, иачИндекс]) Возвращаемое значение: индекс первого символа подстроки строкаПоиска в строке. Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Метод JavaScript indexOf (), как и строковые функции в других языках, возвращает индекс первого символа указанной подстроки в строке. Дополнительный аргумент метода указывает позицию начала поиска. Возвращаемое значение всегда отсчитывается от начала строки — от 0, как и для других строковых методов. Если в строке нет данной подстроки, метод возвращает -1. Этот метод используется для поиска экземпляров подстроки в строке. Глава 27. Объект string 877
М'ТШИИГШ F1U Edit View Favorites Toob Help Capturing Character Codei Select any of this text, and see die character Ц of the first character. Character Code-99 ; Converting Codes to Characters Enter a value 0-255:; 67 Enteravabe0-255:;65 Enter a value 0-255:84 [Show Siring J Result:; CAT [IpPone rrf^Lv.i^tet&f»i>^W.a;a>^ Снявшим ' Рис. 27.1. Преобразование символов в ASCII-коды и наоборот В браузерах NN2 и NN3 присутствует ошибка, которая приводит к некорректной работе этого метода. Если выполняется поиск пустой строки, то метод indexOf () возвращает ее, а не ожидаемое значение -1. Поэтому до применения этого метода необходимо убедиться, что строка не является пустой (см. примеры на компакт-диске). Во всех примерах результат метода присваивается переменной offset. Пример Введите каждое из следующих выражений (без комментариев, начинающихся с символов //) в верхнее текстовое тюле приложения The Evaluator. Пример использования indexOf () приведен на прилагаемом к книге компакт-диске. Сравните все полученные результаты. "bananas" .indexOf("b") .indexOf("a") indexOf{"a",1) indexOf("a" ,2) indexOf("a",4) indexOf("nan") indexOf("nas") indexOf("s") indexOf("z") // результат // результат // результат // результат // результат // результат // результат // результат // результат (индекс первой буквы — ноль) (начало со второй буквы) (начало с третьей буквы) (начало с пятой буквы) -1 (в строке нет символов "z") См. также: методы строка. last IndexOf (), строка. charAt (), строка. substring (). строка.lastIndexOf(строхаПоиска [, начИндекс] ) Возвращаемое Значение: индекс последнего символа подстроки searchString в строке. Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ 878 Часть IV. Объекты языка JavaScript
Метод строка. lastlndexOf () тесно связан с методом строка. indexOf (). Разница заключается в том, что этот метод начинает поиск с конца строки (строка. length — 1), поэтому поиск проводится в обратном направлении. Все значения индексов отсчитываются от 0 — начала строки. Для сравнения результатов в приведенных примерах используются те же значения, что и в примерах метода строка. indexOf (). В строках, которые содержат только один экземпляр требуемой подстроки, методы возвращают одинаковые результаты; там же, где присутствует несколько необходимых экземпляров, результаты методов существенно различаются. Пример Введите каждое из приведенных далее выражений (без комментариев, начинающихся с символов //) в верхнее текстовое поле приложения The Evaluator. Пример использования lastlndexOf () приведен на прилагаемом к книге компакт-диске. Сравните все полученные результаты. а = "bananas" a.lastlndexOf("b") // результат 0 (индекс первой буквы - ноль) a.lastlndexOf("а") // результат 5 a.lastlndexOf("а",1) // результат 1 (со второй буквы в начало) a.lastlndexOf("а",2) // результат 1 (с третьей буквы в начало) a.lastlndexOf("а",4) // результат 3 (начало с пятой буквы) a.lastlndexOf("nan") // результат 2 [в NN2.О результат -1 (ошибка)] a.lastlndexOf("nas") // результат 4 a.lastlndexOf("s") // результат 6 a.lastlndexOf("z") // результат -1 (в строке нет символов "z") См. также: методы строка. indexOf (), строка. charAt (), строка. substring (). строка.localeCompare(строка2) Возвращаемое Значение: целочисленное Совместимость: Winffi5.5+, MacIE-, NN6+, Mozl+, Safari 1+ Метод localeCompare () позволяет сценарию сравнить строки в кодировке Unicode, (с учетом используемого браузером языка общения с пользователями). Необходимость в этом методе возникает лишь в определенных языковых системах (например турецкой). Если строки являются равными, метод возвращает нулевое значение. Если находящееся слева от точки строковое значение, для которого вызван метод, меньше (подсчитывается сумма кодов символов), чем строка- аргумент, метод возвращает отрицательное целое число; в ином случае — положительное. Стандарт ЕСМА предполагает, что абсолютное значение отрицательного и положительного результата зависит от разработчиков браузера. NN6+ подсчитывает сумму Urficode- кодов символов исходной строки и строки аргумента, а затем вычисляет их разность. ГЕ5.5+ возвращает просто -1 или 1. См. также: методы строка. toLocaleLowerCase (), строка. toLocaleUpperCase (). строка. match (регВыражение) Возвращаемое значение: массив строк, удовлетворяющих шаблону Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safari 1+ Метод строка.match() использует объект RegExp (регулярное выражение), появившийся в JavaScript в NN4 и Ш4. Исследуемое строковое значение указывается слева от точки, а регулярное выражение — в аргументе метода. Параметр должен быть объектом, созданным одним из двух возможных способов. Если найдено хотя бы одно совпадение, метод возвращает массив строк. В ином случае он возвращает значение null. Каждый элемент массива является копией подстроки, удовлетво- Глава 27. Объект string 879
ряющей регулярному выражению. Этим методом можно воспользоваться для подсчета количества экземпляров определенной подстроки или последовательности символов в данной строке. Поиск позиций подстрок в строке требует применения других методов синтаксического анализа. Пример Чтобы помочь вам изучить метод строка. match (), мы создали документ, представленный листингом 27.3. Для ввода данных мы использовали два поля: первое принимает длинную строку, анализируемую методом, а второе — регулярное выражение. Если вы не знакомы с регулярными выражениями (глава 42), то во втором поле будет использоваться некое значение по умолчанию. С помощью флажка укажите на необходимость поиска в режиме чувствительности к регистру символов. После щелчка на кнопке Execute Match() сценарий создаст объект регулярного выражения, выполнит сам метод по отношению к длинной строке и выведет два результата. Первый результат— это массив возвращаемых методов значений, а второй — количество найденных элементов. <html> <head> <title>Regular Expression Match</title> <script type="text/'javascript"> function doMatch(form) { var str = form, entry, value,- var delim = (form.caseSens.checked) ? M/g" - M/gi"; var regexp = eval("/" + form.regexp.value + delim); var resultArray = str.match(regexp); if (resultArray) { form.result.value = resultArray.toStringO; form.count.value = resultArray.length; } else { form.result.value = "<no matches>"; form.count.value = ""; </script> </head> <body> <b>String Match with Regular Expressions</b> <hr /> <form> t Enter a main string:<input type="text" name="entry" size=f,60" value="Many a maN and womAN have meant to visit GerMAny." /xbr /> Enter a regular expression to match:<input type="text" name="regexp" size="25" value="\wa\w" /> <input type="checkbox" name="caseSens" />Case-sensitive <p><input type= "button" value="Execute matchO" onclick="doMatch(this.form)" /> <input type="reset" /></p> <p>Result:<input type="text" name="result" size="40" /xbr /> Count :<input type=Mtext" name="count" size="3" /xbr /x/p> </form> </body> </html> 880 Часть IV. Объекты языка JavaScript
По умолчанию в длинной строке прописные символы введены в произвольном порядке. Использование такой нестандартной строки в методе match () позволяет более глубоко изучить принципы работы последнего. В приведенной ниже таблице приведены примеры регулярных выражений, которые вы можете смело использовать при изучении этого метода. Регулярное выражение Описание man Как с учетом регистра, так и без учета регистра man\b man располагается в конце слова \bman man располагается в начале слова me*an Между т и а введено произвольное количество символов е (или ни одного) . а. Слева и справа от а введено по одному символу (пробел тоже рассматривается как символ) \ a s \ s Слева и справа от а введены пробелы z Символ z (в строке по умолчанию не встречается) Если в сценарии листинга 27.3 метод match () возвращает значение null, то на экран выводится соответствующее сообщение, а счетчик обнуляется. См. также: объект RegExp (глава 42). строка. rep lace (регВыражение, строкаЗамены) Возвращаемое значение: измененная строка. Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Регулярные выражения широко используются в операциях поиска и замены. Метод строка. replace в JavaScript обеспечивает простой способ выполнения таких операций. Процесс поиска и замены требует наличия трех компонент. Первой является исходная строка, второй — регулярное выражение, с которым проводится сравнение, а третьей — подстрока, заменяющая исходный блок текста. В методе строка. replace () исходная строка указывается слева от точки. Она может быть и обычной строкой в кавычках. Регулярное выражение задается в первом аргументе метода, а строка-заменитель — во втором. Определение регулярных выражений указывает, как проводить замену: только в одном совпадении или во всех. Если в конце регулярного выражения добавить параметр д, метод replace () проведет глобальный поиск и замену. Если вы знаете, как работать с регулярными выражениями, воспользуйтесь методом строка. replace (). Применение регулярных выражений делает операции поиска и замены более мощными. Рассмотрим монолог Гамлета. То be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer Если нужно заменить оба экземпляра "be" на "exist", то выполним это с помощью оператора. var regexp = /be/g; soliloquy.replace(regexp, "exist"); Однако такой подход не позволит узнать, является ли комбинация букв "Ь" и "е" отдельным словом. А что, если исходная строка содержит слова "being" или "saber"? Приведенный выше пример заменяет буквы "be "ив этих словах. Глава 27. Объект string 881
Регулярные выражения поддерживают специальные символы, которые упрощают решение этой задачи. В приведенном выше примере выполняется поиск слова "be". К искомому выражению необходимо добавить символы, ограничивающие слово (специальные символы \Ь). var regexp = /\bbe\b/g; soliloquy.replace(regexp, "exist"); В этом синтаксисе учитывается тот факт, что после первых двух символов "be" введены знаки пунктуации, а не только пробелы. Более подробно о синтаксисе регулярных выражений рассказано в главе 42. Пример Страница, представленная листингом 27.4, создана специально для демонстрации возможностей методов строка. replace () и строка. search (). В качестве исходного текста используется пять строк из бессмертного "Гамлета". В поля этого приложения можно вводить как регулярное выражение для поиска, так и заменяющее найденные элементы выражение. Обратите внимание, что сценарий создает объект регулярного выражения автоматически, поэтому вы можете смело вводить любые комбинации специальных символов. Замена текста выполняется на глобальном уровне, поскольку во введенное выражение автоматически добавляется параметр д. Значения по умолчанию в полях приложения позволяют заменить синтаксическую конструкцию ' tis на it' s. Запуск сценария выполняется по щелчку на кнопке Execute replace() (рис. 27.2). Учтите, что символ обратной косой черты перед апострофом делает последний частью регулярного выражения, а не символом определения текстового типа данных веденного значения. щит File Edit View Fevorltoa Toe* tfofp ШВ o*«~ о a a&ip^&N""- #*■*ф\@*% т -иВЧ** String Replace and Search with Regular Expressions Text wed for string. replaceO and string. searchO methods: To be, or not to be: that is the question: Whether 'tii nobler in the mind to suffer The sung* and arrows of outrageous fortune, Or to take arms against a sea ef troubles, And by opposing end them. Enter a regular expression to match.;\Bt Enter a rtrmg'to replace the matching strings^ ! □ Case-sensitive Result: :To be, or not to be: chat is cbe question: Whether it Is nobler in the mind to suffer jThe slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, ;And by opposing end the». ;ц»^айеМм< ■:!■.* J J№&'$v^££k Рис. 27.2. Использование регулярного выражения по умолчанию для замены текстового значения Вы можете самостоятельно изменить листинг сценария так, чтобы он заменял текст в HTML- документе, загруженном в браузере IE4+ или W3C. Для этого вам необходимо заключить абзац 882 Часть IV. Объекты языка JavaScript
в отдельный элемент (обычно span), а затем выполнить метод replace () по отношению к значению innerHTML элемента. <html> <head> <title>Regular Expression Replace and Search</title> <script type="text/javascript"> var mainString = "To be, or not to be: that is the question:\n"; mainString += "Whether \'tis nobler in the mind to suffer\n"; mainString += "The slings and arrows of outrageous fortune,\n"; mainString += "Or to take arms against a sea of troubles An"; mainString += "And by opposing end them."; function doReplace(form) { var replaceStr = form.replaceEntry.value; var delim = (form.caseSens.checked) ? "/g" : "/gi"; var regexp = eval("/" + form.regexp.value + delim); form.result.value = mainString.replace(regexp, replaceStr); function doSearch(form) { var replaceStr = form. replaceEntry. value,- var delim = (form.caseSens.checked) ? "/g" : "/gi"; var regexp = eval("/" + form.regexp.value + delim); form.result.value = mainString.search(regexp); } </script> </head> <body> <b>String Replace and Search with Regular Expressions</b> <hr /> Text used for string.replace() and string.search() methods:<br /> <b>To be, or not to be: that is the question:<br /> Whether 'tis nobler in the mind to suffer<br /> The slings and arrows of outrageous fortune,<br /> Or to take arms against a sea of troubles,<br /> And by opposing end them.</fc» <form> Enter a regular expression to match:<input type="text" name="regexp" size="25" value="\B't" /> <input type="checkbox" name="caseSens" />Case-sensitive<br /> Enter a .string to replace the matching strings:<input type="text" name="replaceEntry" size="30" value="it " /> <pxinput type="button" value="Execute replace ()" onclick="doReplace(this.form)" /> <input type="reset" /> <input type="button" value="Execute search()" onclick="doSearch(this.form)" /></p> <p>Result:<br /> <textarea name="result" cols="60" rows="5" wrap="virtual"> </textareax/p> </form> </body> </html> См. также: метод строка. match (); объект RegExp. Глава 27. Объект string 883
строка. search (регВыражение) Возвращаемое значение: целочисленное смещение. Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ Результаты метода строка. search () напоминают результаты метода строка. indexOf (). В обоих случаях возвращается индекс первого экземпляра подстроки в исходной строке или -1, если такового не обнаружено. Разница заключается в том, что метод строка. search () позволяет использовать в строке поиска регулярные выражения. Пример В листинге 27.4 приведен сценарий приложения, предназначенного для детального изучения метода строка. search (). См. также: метод строка.match (); объект RegExp. строка.slice(начИндекс [, конИндекс]) Возвращаемое значение: строка. Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Метод строка. slice () похож на метод строка. substring (): они оба позволяют извлечь из строки подстроку (не изменяя исходную). Преимущество метода строка.slice О заключается в том, что в этом методе можно указать индекс, отсчитываемый не от начала, а от конца строки. Для извлечения подстроки, которая заканчивается за 2 символа до конца строки, методом строка. substring () требуется провести дополнительные вычисления. строка.substring(4, (string.length-2)) Метод строка. slice () позволяет указать отрицательное значение во втором аргументе, т.е. отсчитать индекс от конца строки. строка.siice(4, -2) Второй аргумент не является обязательным. Если он опущен, метод возвращает подстроку, началом которой служит заданная позиция, а концом — конец строки. Пример Листинг 27.5 содержит код приложения, предназначенного для всестороннего изучения метода строка, slice О. Окно приложения представлено на рис. 27.3. В верхней части страницы показана исходная строка, а в нижней части документа — элементы управления для ввода аргументов метода. <html> <head> <title>String Slicing and Dicing, Part I</title> ocript type="text/javascript"> var mainString = "Electroencephalograph"; function showResults() { var form = document.forms[0] ; var paraml = parselnt(form.paraml.options[form.paraml. selectedlndex].value); var param2 = parselnt(form.param2.options[form.param2. 884 Часть IV. Объекты языка JavaScript
selectedlndex].value); if (!param2) { form.resultl.value = mainString.slice(paraml); } else { form.resultl.value = mainString.slice(paraml, param2); </script> </head> <body onload="showResults{)"> <b>String slice () Method</b> <hr /> Text used for the methods:<br /> <font size="+l"><ttxb>Electroencephalograph<br /> 5 5 5 5-</bx/ttx/font> <form> <table> <tr> <th>String Method</th> <th>Method Parameters</th> <th>Results</th> </tr> <tr> <td>string.slice()</td> <td rowspan="3" valign="middle"> (&nbsp;<select name="paraml" onchange="showResuits{)"> <option value="0">0</option> <option value="l">l</option> <option value="2">2</option> <option value="3">3</option> <option value="5">5</option> </select>, <select name="param2" onchange="showResuits()"> <option>(None)</option> <option value="5">5</option> <option value="10">10</option> <option value="-l">-l</option> <option value="-5">-5</option> <option value="-10">-10</option> </select>&nbsp;) </td> <tdxinput type="text" name="resultl" size="25" /></td> </tr> </table> </form> </body> </html> См. также: методы строка. substг (), строка. substring (). строка. spl i t ("разделитель " [, огргшичитель] ) Возвращаемое значение: массив элементов. Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Метод split по своей функциональности противоположен методу array, join () (см. главу 30). С точки зрения строкового объекта, JavaScript разбивает строку на элементы, Глава 27. Объект string 885
разделенные определенным символом, и создает из них массив. Инициализировать массив конструктором new Array () нет необходимости. Принимая во внимание наличие функциональных методов объекта array, например array. sort (), часто возникает необходимость преобразовать набор строковых элементов в массив, чтобы воспользоваться ими. Если вашей целью является преобразование строки в массив отдельных символов, метод split () вполне подойдет для выполнения этой задачи. В этом случае аргументом должна быть пустая строка. В NN3 и Г£4 метод использует только первый аргумент. g] и|ЩИШМЩИЩЩИ11И File Edit View Favorite Toole Help Ф String fliceQ Method Text used for the methods: Electroencephaloqraph 5 5 5 5. String Method Method Parameter! Remits string. sliceQ ([2"Slf^ S) ,ectroenc №-Pj5f. ^,....\-,-..^>.,к -аж: .«.& „«.«A.. f~ .fr>-txw^ ,^*tt««^WAM»^fl(i..«.flfa^^ Рис. 27.3. Страница изучения метода slice () В браузерах NN4+ и ГЕ4+ в качестве первого параметра можно применить объект регулярных вьфажений, что повышает возможности поиска символов-разделителей. Рассмотрим следующую строку. var nameList = "1.Fred,2.Jane,3.Steve"; Для преобразования этой строки в массив из трех элементов, содержащий лишь имена, без использования регулярных выражений потребуется провести определенный синтаксический анализ еще до начала метода string, split (). Применение регулярных выражений значительно упрощает задачу. var regexp = /,*\d.\b/; var newArray = nameList.split(regexp); // результат: массив "Fred", "Jane", "Steve"; Новый массив содержит только имена (без цифр или точек). Второй аргумент метода является дополнительным. Он позволяет указать максимальное количество элементов, сохраняемых в массиве. 886 Часть IV. Объекты языка JavaScript
Пример Используйте приложение The Evaluator для изучения метода строка. split О . Для начала сохраните текстовую строку со значениями, разделенными запятыми, в отдельной переменной, а = "Anderson,Smith,Johnson,Washington" Далее разделите эту строку по символам запятых, включив полученные элементы в массив, b = a.split(",") Чтобы доказать, что массив содержит четыре элемента, изучите значение его свойства length, b.length // результат 4 См. также: метод array. j о in (). строка. substr (начало [, длина]) Возвращаемое значение: строка. Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ Метод строка. substг () представляет собой вариант метода строка. substring (), который был частью языка JavaScript с момента его создания. Различие заключается в том, что аргументы метода строка. substг () указывают начальный индекс и количество символов в подстроке, тогда как в методе строка. substring () необходимо указывать начальный и конечный индексы. Как и для других методов, в строка. subs t г () первый аргумент, индекс, отсчитывается с нуля. Если второй аргумент не указан, то в подстроку включаются все символы от начальной позиции до конца строки. То же самое происходит и тогда, когда значение второго аргумента превосходит индекс последнего символа в строке. Пример Чтобы детально ознакомиться с методом строка. substг (), загрузите страницу, представленную листингом 27.6, и внимательно изучите ее возможности. <html> <head> <title>String Slicing and Dicing, Part II</title> <script type="text/javascript"> var mainString = "Electroencephalograph"; function showResults() { var form = document.forms[0]; var paraml = parselnt( form, paraml. opt ions [form.paraml.selectedlndex] .value) ; var param2 = parselnt (form.param2.options [form.param2. selectedlndex] .value) ; if (!param2) { form, result Lvalue = mainString.substr(paraml); } else { form.resultl.value = mainString.substr(paraml, param2); } } </script> </head> <body onload="showResuits()"> <b>String substr() Method</b> <hr /> 11 ■ ■"■■ ■■"■ ' ■ '■ "■■■"■ ■ ■■■■■!■■ I «llll ■ Глава 27. Объект string 887
Text used for the methods:<br /> <font size="+lfl><ttxb>Electroencephalograph<br /> 5 5 5 5-</-bx/ttx/font> <form> <table> <tr> <th>String Method</th> <th>Method Parameters</th> <th>Results</th> </tr> <tr> <td>string.substr()</td> <td rowspan="3" valign="middle"> (&nbsp;<select name="paraml" onchange="showResuits()"> N <option value="0">0</option> <option value="l">l</option> <option value="2">2</option> <option value="3">3</option> <option value="5">5</option> </s/elect>/ <select name="param2" onchange ="showResuits () '■ > <option>(None)</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select>&nbsp;) </td> <tdxinput type="text" name="resultl" size="25" /></td> </tr> </table> </form> </body> </html> См. также: метод строка. substring (). строка.substring(индексА, индексВ) Возвращаемое значение: подстрока, заданная начальным (индекстА) и конечным {индексе) индексами. Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safaril+ Метод строка. substring () позволяет выделить подстроку (т.е. группу символов) из строки. Аргументами этого метода являются начальный и конечный индексы (первый символ строки имеет индекс 0) подстроки в исходной строке. Важно отметить, что символ, заданный конечным индексом, не включается в подстроку. В каком порядке заданы индексы — не имеет значения: метод начинает с меньшего и заканчивает на большем (исключая последний символ). Если значения индексов совпадают, метод возвращает пустую строку, а если второй аргумент опущен, подстрока доходит до конца строки. Пример Чтобы детально ознакомиться с методом строка. substring (), загрузите страницу, представленную листингом 27.7, и внимательно изучите ее возможности. 888 Часть IV. Объекты языка JavaScript
<html> <head> <title>String Slicing and Dicing, Part III</title> <script type="text/javascript"> var mainString = "Electroencephalograph"; function showResults() { ( var form = document.forms[0]; var paraml = parselnt (form, paraml. opt ions [form, paraml. selectedlndex] .value) ; var param2 = parselnt (form.param2.options [form.param2. selectedlndex] .value); if (lparam2) { form.resultl.value = mainString.substring(paraml); } else { form.resultl.value = mainString.substring(paraml, param2); </script> </head> <body onload="showResults() " > <b>String substrO Method</b> <hr /> Text used for the methods:<br /> <font size="+l"xttxb>Electroencephalograph<br /> 5 5 5 5-</bx/ttx/font> <form> <table> <tr> <th>String Method</th> <th>Method Parameters</th> <th>Results</th> </tr> <tr> <td>string.substring()</td> <td>(&nbsp;<select name="paraml" onchange="showResults()"> <option value="0">0</option> <option value="l">l</option> <option value="2">2</option> <option value="3">3</option> <option value="5">5</option> </select>, <select name="param2" onchange="showResults()"> <option>(None)</option> <option value="3">3</option> <option value="5">5</option> <option value="10">10</option> </select>&nbsp;) </td> <tdxinput type="text" name="result 1" size="25" /></td> </tr> </table> </form> </body> </html> См. также: методы строка. substг (), строка. slice О . Глава 27. Объект string 889
строка.toLocaleLowerCase() строка.toLocaleUpperCase() Возвращаемое значение: строка. Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Два этих метода представляют собой варианты стандартных методов изменения регистра строки. Они учитывают определенные языковые системы, символы которых включают не только буквы латинского алфавита. См. также: методы строка. toLowerCase (), строка. toUpperCase (). строка.toLowerCase() строка.toUpperCase() Возвращаемое значение: строка в верхнем или нижнем регистре (в зависимости от метода). Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ В Internet (и в JavaScript) регистр имеет важное событие. URL на некоторых серверах (например, при обработке) требует учета регистра в именах файлов и папок. Два этих метода представляют собой простейшие строковые методы, цель которых — преобразование строки в верхний или нижний регистр. Строки со смешанным регистром преобразуются к единому типу. Если, например, текст, введенный пользователем в поле, необходимо сравнить с некоторой строкой без учета регистра, преобразуйте строки к одному регистру, а Затем проведите сравнение. Пример Вы можете смело использовать методы строка. toLowerCase (), строка. toUpperCase () в строковых выражениях. var newString = "HTTP://www.Netscape.COM".toLowerCase(); // результат "http://www.netscape.com" Эти методы также помогут сравнить строки, в которых регистр символов не имеет значения. if (guess.toUpperCase() == answer.toUpperCase()) {...} // сравнение строк без учета регистра символов См. также: методы строка. toLocaleLowerCase (), строка. toLocaleUpperCase (). строка.toString() строка.valueOf() Возвращаемое значение: строковое значение. Совместимость: WinIE4+, МасШ4+, NN4+, Mozl+, Safari 1+ Оба метода возвращают строковые значения (в отличие от полноценных строковых объектов). Если строковый объект создан конструктором new String (), то его тип определяется как ob j ect. Поэтому, если требуется определить тип сохраняемых в данном объекте значений, применяется метод valueOf () с последующим оператором typeof. Объект, в первую очередь, имеет метод toString (), так как он наследует этот метод от исходного объекта JavaScript. Пример Используйте приложение The Evaluator для изучения метода valueOf (). Введите в верхнее текстовое поле приложения следующее выражение, а затем изучите полученные результаты в области Results. а = new String("hello") typeof a 890 Часть IV. Объекты языка JavaScript
b = a.valueOf() typeof b Поскольку все остальные объекты языка JavaScript поддерживают метод indexOf (), вы можете создать общую функцию, которая принимает в качестве аргументов тип объекта и разветвляет сценарий в зависимости от последнего. См. также: оператор typeof (глава 32). Функции обработки строковых данных Использовать строковые методы для достижения той или иной цели непросто, особенно, если требуется обеспечить совместимость с ранними версиями браузеров. Кроме того, трудно предугадать, какие способы обработки строк могут понадобиться в сценариях. Листинг 34.8 содержит библиотеку строковых функций, предназначенных для вставки, удаления и замены блоков текста в строке. Если браузеры, на которые ориентирована страница, поддерживают подключение внешних файлов JavaScript (. j s), функции будут всегда доступны сценариям. // извлечение начала строки до searchString function getFront(mainStr,searchStr){ foundOffset = mainStr.indexOf(searchStr); if (foundOffset == -1) { return null; } return mainStr.substring(0,foundOffset); } // извлечение конца строки после searchString function getEnd(mainStr,searchStr) { foundOffset = mainStr.indexOf(searchStr); if (foundOffset == -1) { return null; } return mainStr.substring(foundOffset+searchStr.length, mainStr.length); } // вставка insertString перед searchString function insertString(mainStr,searchStr,insertStr) { var front = getFront(mainStr,searchStr) ; var end = getEnd(mainStr,searchStr); if (front != null && end != null) { return front + insertStr + searchStr + end; } return null; } // удаление deleteString function deleteString(mainStr,deleteStr) { return replaceString(mainStr,deleteStr,""); } // замена searchString на replaceString function replaceString(mainStr,searchStr,replaceStr) { var front = getFront(mainStr,searchStr); Глава 27. Объект string 891
} var end = getEnd(mainStr,searchStr); if (front != null ScSc end != null) { return front + replaceStr + end; } return null; Две первые функции извлекают подстроку в начале или конце строки и являются промежуточными функциями набора, ядро которого составляют три последние функции. Обратите внимание, что одни функции зависят от других, поэтому только включение всей группы из пяти функций позволяет им работать так, как запланировано. В современных сценариях, подобных приведенному в листинге 27.8, для замены текстовых данных в одном операторе используется комбинация строковых методов и методов массива. function replaceString(mainStr, searchStr, replaceStr) { return mainStr.split(searchStr).join(replaceStr); } Для дальнейшего улучшения предложенной концепции вы можете создать пользовательский метод управления строковыми данными или строковыми объектами. После загрузки страницы укажите сценарию выполнить следующее выражение. String.prototype.replaceString = function (mainStr, searchStr, replaceStr) { return mainStr.split(searchStr).join(replaceStr); } Впоследствии вы можете вызвать этот метод из любого строкового значения даже в других сценариях страницы. myString = myString.replaceString(" CD ", " МРЗ "); Методы форматирования Теперь мы подошли к рассмотрению следующей группы методов строкового объекта, которые облегчают процесс создания различных характеристик строк, необходимых для создания HTML-кода средствами JavaScript. Ниже приведен список этих методов. строка.anchor("anchorName") строка.link(locationOrURL) строка.blink() строка.big() строка.bold() строка.small() строка.fixed() строка.strike() строка.fontcolor(colorValue) строка.sub() строка.fontsize(integerlto7) строка.sup() строка.italics() Вначале рассмотрим методы, не требующие никаких аргументов. Это, в первую очередь, методы, устанавливающие атрибуты шрифтов строки. В HTML-документе их изменение достигается парой дескрипторов, например <Ь>. . . </Ь> для полужирного шрифта. Эти методы добавляют к строковому объекту необходимые дескрипторы и возвращают текст, готовый к добавлению в HTML-код. Например,/выражение иGood morning!".bold() превращается в <b>Good morning!</b> 892 Часть IV. Объекты языка JavaScript
HTML-код можно создать и без этих методов, вставив в него все необходимые дескрипторы. Одним из достоинств строковых методов — это сохранение закрывающего дескриптора пары. Листинг 27.9 демонстрирует пример использования простых строковых методов, которые создают значение переменной, отображаемое затем на странице. Internet Explorer не поддерживает дескриптор <blink> и поэтому игнорирует метод строка. blink (). <html> <head> <title>HTML by JavaScript</title> </head> , <body> <script type="text/javascriptM> var page = ""; page += "JavaScript can create HTML on the fly.<P>Numerous string object methods facilitate creating text that is " + "boldfaced".bold() + H, " + "italicized".italics() + ", or even the terribly annoying " + "blinking text".blink() + "."; document.write(page); </script> </body> </html> Два следующих метода {строка. font size () и строка. fontcolor ()) также влияют на характеристики шрифта текста, отображаемого на HTML-странице. Аргументы достаточно очевидны: целое число в диапазоне от 1 до 7, задающее относительный размер шрифта, и цвет (в виде шестнадцатеричного триплета или константы-имени цвета) текста. В листинге 27.10 к строке из листинга 27.9 добавляется определенная строка текста. Эта строка не только изменяет размер шрифта определенных частей текста, но и применяет вложенные атрибуты для задания цвета. Поскольку эти методы не изменяют содержимого строки, их можно смело использовать как вложенные. <html> <head> <title>HTML by JavaScript</title> </head> <body> <script type="text/javascript"> var page = ""; page += "JavaScript can create HTML on the fly.<P>Numerous string object methods facilitate creating text that is " + "boldfaced".bold() + ", " + "italicized".italics() + ", or even the terribly annoying " + "blinking text".blink ".<br />"; page += "We can make " + "some words big".fontsize(5) + " and some words both" + ("big and " + "colorful".fontcolor('coral')).fontsize(5) + " at the same time."; document.write(page); </script> </body> </html> О Глава 27. Объект string 893
Два заключительных строковых метода позволяют добавить для строки анкер и ссылку. Аргумент метода string. anchor () используется в качестве имени анкера. Поэтому выражение "Table of Contents".anchor("toe") преобразуется в <a name="toc">Table of Contents</a> Подобным образом метод string. link () принимает в качестве параметра URL. "Back to Home".link{"index.html") Это выражение преобразуется в следующее. <а href= "index.html">Back to Home</a> Этими методами пользоваться необязательно — ведь можно также установить дескрипторы HTML вручную. Методы применять удобнее, если аргументы являются переменными, значения которых зависят от введенных пользователем данных. Кодирование и декодирование строк URL При взаимодействии браузеров и серверов некоторые небуквенно-цифровые символы (например пробел) нельзя переслать в их естественной форме. Протоколы передачи данных позволяют отправить более узкий набор символов. Для представления всех остальных символов используется специальный символ (%), за которым следует шестнадцатеричныи код ASCII. Например, шестнадцатеричныи код пробела равен 20 (десятичный— 32). Соответственно, он преобразуется к виду %20. Такие символы часто встречаются в списке URL посещенных браузером документов. JavaScript поддерживает две функции, escape () и unescape (), которые позволяют преобразовывать в код отдельные строки. Для преобразования строки в закодированный формат используется оператор. escape("Howdy Pardner") // результат "Howdy%2 0Pardner" Функция une scape () выполняет обратное преобразование. Об этих функциях, а также некоторых других речь пойдет в главе 34. 894 Часть IV. Объекты языка JavaScript
Объекты Math, Number и Boolean Типы данных JavaScript были представлены в главе 6. В настоящей главе мы подробно рассмотрим, как JavaScript работает с числовыми и логическими данными. Математические операции иногда вызывают трудности у программистов, однако, как вы сможете убедиться, их программирование на JavaScript не представляет никаких сложностей. Если вы не очень хорошо помните основы математики, внимательно изучите применяемую далее терминологию. Важно помнить, что (как и в случае со строками) числа и значения логического типа являются одновременно и объектами, и значениями. К счастью, различие проявляется лишь в очень тонком и сложном программировании. Для тех же, кто создает интерпретаторы JavaScript для браузеров, такое различие является жизненно важным. Для большинства авторов сценариев информация о числовых типах данных, преобразованиях, а также объекте Math является важной. Другие подробные сведения о числовых и логических объектах будут представлены лишь с целью общего ознакомления, поскольку редко применяются в Web-программировании. Числа в JavaScript Более мощные языки программирования включают довольно много числовых типов, каждый из которых занимает определенный объем памяти компьютера. Но эффект от их использования при быстром создании несложных сценариев невелик. Поэтому числа в JavaScript принадлежат лишь к одному из двух возможных типов: целому или с плавающей точкой. Целыми являются числа, не имеющие десятичной части (и, соответственно, не содержащие десятичной точки в своем представлении). Числа с плавающей точкой включают целую и дробную части. Если вы имеете опыт в программировании, обратитесь к описанию объекта Number далее в этой главе, где речь пойдет о том, как числовые типы данных в JavaScript соотносятся с типами данных в других средах программирования.
Целые числа и числа с плавающей точкой Микропроцессор намного быстрее выполняет операции с целыми числами, чем с числами с плавающей точкой. Операции с последними требуют дополнительных действий. Разработчикам сценариев необходимо следить за тем, какие числа используются в расчетах. Большинство внутренних значений, которые применяются в JavaScript (например, индексы или длины объектов), являются целочисленными. Числа с плавающей точкой используются, как правило, при выполнении операции деления, при работе со специальными константами (например, число я) или при обработке введенных пользователями данных (например, денежных значений). К счастью, JavaScript позволяет проводить операции со смешанными типами данных. Обратите внимание, как получен результат в следующих примерах. 3+4=7 // целое число 3 + 4.1 = 7.1 // число с плавающей точкой 3.9 + 4.1 = 8 // целое число В этих трех примерах, пожалуй, только последний результат оказался неожиданным. Если два числа с плавающей точкой дают результат с нулевой дробной частью, то такое число считается целочисленным. При работе с числами с плавающей точкой необходимо помнить, что не все версии браузеров возвращают абсолютно точное значение до последней цифры после запятой. Например, в следующей таблице показан результат операции деления числа 8 на число 9, выполненной в различных браузерах (на платформе Windows) после преобразования в строковый тип. NN2 0.88888888888888884 NN3 .8888888888888888 NN4 .8888888888888888 NN6+/Mozilla 1 +/Safari 1 + 0.8888888888888888 IE3 0.888888888888889 IE4+ 0.8888888888888888 Очевидно, что браузеры с поддержкой JavaScript не подходят для расчета траекторий космических полетов. Применяя JavaScript для несложных ежедневных расчетов, необходимо не забывать об ошибках, характерных для операций с нецелочисленными данными. В NN язык JavaScript использует математику самой ОС. Системы, поддерживающие такую точность, которую обеспечивает JavaScript, встречаются нечасто. Как можно увидеть в таблице, современные браузеры (и Netscape, и Microsoft) отображают одинаковое количество чисел после запятой и подобным образом проводят округление. Это хорошо для расчетов, но не очень удобно, когда числа нужно выводить в определенном формате. В версиях, предшествующих Ш5.5 и NN6, JavaScript не поддерживает методов форматирования числовых результатов с плавающей точкой (см. методы форматирования объекта Number в современных браузерах далее в этой главе). В листинге 28.1 представлена универсальная процедура форматирования положительных значений, а также специальная процедура для преобразования числа к денежному формату. <title>Number Formatting</title> <script type="text/javascript"> function format(expr, decplaces) { 896 Часть IV. Объекты языка JavaScript
var str = "" + Math.round(eval(expr) * Math.pow(10,decplaces) ) ; while (str.. length <= decplaces) { str = "0" + str; } var decpoint = str.length - decplaces; return str.substring(0,decpoint) + "." + str.substring(decpoint,str.length); function dollarize(expr) { return "$" + format(expr, 2) ; } . </script> </head> <body> <hl>How to Make Money</hl> <form> Enter a positive floating point value or arithmetic expression to be converted to a currency format: <pxinput type="text" name="entry" value="l/3" /> <input type="button" value="&gt;Dollars and Cents&gt;" onclick="this.form.result.value=dollarize(this.form, entry.value)" /> <input type="text" name="result" /></p> </form> </body> </html> Процедура может показаться сложной, но она чрезвычайно полезна, если Web-приложение запрашивает значения с плавающей точкой и требует определенного форматирования во всех браузерах. Числа с плавающей точкой можно записать и в экспоненциальной форме. На это указывает буква е (нижнего или верхнего регистра), за которой следует знак (+ или -) и значение. Приведем примеры некоторых значений, представленных в экспоненциальной форме. 1еб // 1,000,000 (знак "+" необязателен при положительном // показателе степени) 1е-4 // 0.0001 (плюс некоторая ошибка далее после запятой) -4е-3 // -0.004 Значения в диапазоне от 1е-5 до 1е15 JavaScript отображает в виде чисел неэкспоненциальной формы (хотя в браузерах Ш5.5, NN6 и W3C можно использовать и экспоненциальную форму). Значения вне этого диапазона отображаются в экспоненциальной форме во всех браузерах. Шестнадцатеричные и восьмеричные целые числа JavaScript позволяет работать со значениями в десятичном (основание 10), шестнадцате- ричном (основание 16) и восьмеричном (основание 8) форматах. При этом необходимо следовать нескольким правилам. Десятичные значения никогда не начинаются с 0. Поэтому, если пользователь введет десятичное число с начальным нулем, то до выполнения каких-либо операций сценарий должен устранить его из строки или воспользоваться глобальными функциями обработки чисел (они описаны в следующем разделе). Шестнадцатеричные значения начинаются с Ох или 0Х (нуль, а не буква " о"). Цифры от А до F могут быть представлены в любом регистре. Представим несколько чисел в шестна- дцатеричном формате. Глава 28. Объекты Math, Number и Boolean 897
0Х2В OXla Oxcc He путайте шестнадцатеричные числа, используемые в арифметике, с теми значениями, которые применяются при указании цвета в Web-документах. Они записываются в специальном шестнадцатеричном триплетном формате, на который указывает начальный символ решетки (например, #с0с0с0). Восьмеричные значения начинаются с 0. За ним следуют цифры от 0 до 7. Восьмеричные значения могут быть только целыми. В арифметических выражениях можно смешивать значения различных типов. JavaScript приводит результат к десятичной форме. Чтобы преобразовать числа к другой системе, необходимо воспользоваться определенными функциями. В листинге 28.2 приведен пример функции, преобразующей десятичное число в диапазоне от 0 до 255 в шестнадцатеричный формат. function toHex(dec) { hexChars = "0123456789ABCDEF" if (dec > 255) { return null } var i = dec % 16 var j = (dec - i) /16 result = "OX" result += hexChars.charAt(j) result += hexChars.charAt(i) return result } Функция преобразования toHex () предполагает, что значение, передаваемое ей, является десятичным целым. Если требуется шестнадцатеричное представление числа в строковом формате, то используйте метод toString (), описанный в главе 34. Преобразование строк в числа В этой главе еще не обсуждался вопрос о том, как преобразования числа, представленного строкой, в формат, используемый для арифметических операций. Многие операторы и математические методы JavaScript воспринимают строковое представление чисел и позволяют выполнять действия с ним. Несовместимость типов данных проявляется чаще всего при попытке выполнить сложение оператором + (который для строк служит оператором конкатенации). Кроме того, при выполнении операций помните, что значения, поступающие из текстовых полей форм, являются строками. Таким образом, зачастую их следует преобразовывать в числа. Преобразование строк в числа выполняется с помощью одной из двух функций JavaScript. parseInt(строка [, сисИсчисления]) parseFloat(строка [,сисИсчисления]) Эти функции заимствованы из языка Java. Термин синтаксический анализ имеет несколько значений в программировании. Одно из них — извлечение. Функция parselnt () возвращает целочисленное значение, извлеченное из строки. Функция parseFloat () выполняет эту же операцию для чисел с плавающей точкой. Ниже приведено несколько примеров. 898 Часть IV. Объекты языка JavaScript
parselnt("42") // результат 12 parselnt("42.33") // результат 42 parseFloat("42.33") // результат 42.33 parseFloat("42") // результат 42 parseFloat("fred") // результат NaN Поскольку функция parseFloat () работает и с целыми числами, в сценариях, где приходится обрабатывать разные типы данных, предпочтительнее использовать ее как универсальный способ обработки. Второй, дополнительный, аргумент каждой функции позволяет указать систему исчисления. Это удобно, например, в случае, если в строке содержится десятичное число, начинающееся с нуля, так как обычно такие значения трактуются как восьмеричные. Только при явном указании системы исчисления функция преобразует число так, как ожидается. parselnt("010") // результат = 8 parselnt("010",10) // результат = 10 parselnt("F2") , // результат = NaN parselnt("F2", 16) // результат = 242 Эти функции используются везде, где требуется применить целые числа или числа с плавающей точкой. var result = 3 + parselnt("3") // результат = б var ageVal = parselnt(document.forms[0].age.value) Последний приведенный метод позволяет удостовериться, что строковое значение свойства правильно преобразовано в число (хотя перед выполнением математических операций над введенными пользователем значениями следует провести более тщательную проверку—см. главу 43). Оба метода parselnt () и parseFloat () работают следующим образом: они обрабатывают первый символ строки и продвигаются по значению далее до тех пор, пока не закончатся цифры или десятичные символы. Поэтому их можно использовать в таких строках, как возвращаемая свойством navigator. appVersion (например 4.0 (compatible; MSIE 5.5; Windows95)), для извлечения только числовой части строки. Если строка не начинается с допустимого символа, методы возвращают значение NaN (not a number — не число). Преобразование чисел в строки Если одному из строковых методов, рассмотренных в главе 27, передать значение числового типа, JavaScript вьщаст ошибку. Поэтому до того, как определить, например, сколько цифр содержит число, его необходимо преобразовать в строку. Для этого применяют несколько способов. Один из способов предполагает конкатенацию пустой строки и числа. Предположим, что переменная dollars содержит число 2500. Чтобы воспользоваться свойством length строкового объекта (см. далее) для подсчета количества цифр, необходимо построить следующую конструкцию. (ии + dollars).length // результат = 4 Скобки указывают JavaScript, что конкатенация выполняется до обращения к свойству length. Более элегантный способ заключается в использовании метода toString (). Формат его вызова такой же, как и для любого другого метода объекта. Например, для преобразования переменной dollars в строку используется выражение. dollars.toString() // результат = "2500" Этот метод обладает дополнительными возможностями в браузерах NN3+ и Ш4+: Его вторым аргументом является система исчисления. Приведем пример преобразования шестна- дцатеричного числа в строку. var х = 30; var у = х.toString(16); // результат = "1е" Глава 28. Объекты Math, Number и Boolean 889
Аналогично, для двоичной системы используется аргумент 2, а для восьмеричной— 8. По умолчанию применяется десятичная система исчисления (10). Не путайте эти представления с реальными числовыми преобразованиями. Результат метода toString () нельзя использовать как числовой операнд в каких-либо выражениях. Браузеры Ш5.5+, NN6 и W3C поддерживают три дополнительных метода объекта Number — toExponential (), toFixed () и toPrecision (). Эти методы возвращают строки с представлением чисел, определяемым принимаемыми параметрами. Когда число совсем не число В нескольких примерах предыдущего раздела результатом определенных операций было значение NaN. Оно не является строкой, а обозначает специальное значение — Not a Number (не число). Например, попытка преобразовать строку "joe" в целое число методом parseFloat () не приведет к успеху. Метод сообщит, что исходная строка не является числом. Когда приложение получает данные от пользователя или из базы данных, расположенных на сервере, не всегда то значение, которые должно быть числовым, действительно является таковым. Поэтому перед выполнением математических операций его необходимо проверить. JavaScript поддерживает специальную глобальную функцию isNaNO, позволяющую проверить строковое представление числа. Она возвращает true, если значение не является числом, и false в ином случае. Например, так выглядит проверка поля формы, которое должно содержать число. var ageEntry = parselnt(document.forms[0].age.value) if (isNaN(ageEntry)) { alert("Try entering your age again."); } Объект Math Если необходимо выполнить более сложные операции, чем простые арифметические действия, применяют методы объекта Math. Синтаксис Доступ к свойствам и методам объекта Math. Math, свойство Math.метод{значение[, значение]) Совместимость: Winffi3+, МасГ£3+, NN2+, Mozl+, Safari 1+ Описание объекта Кроме обычных арифметических операций (о которых подробно рассказано в главе 32), JavaScript включает в себя более широкие математические возможности, применение которых может показаться странным для тех, кто не программировал в объектно-ориентированной среде. Несмотря на то, что большая часть арифметических преобразований выполняется "на ходу" (например var result = 2 + 2), сложные операции требуют применения в JavaScript объекта Math (с прописной буквы М). Объект Math имеет несколько свойств (похожих на константы других языков программирования) и довольно много методов (похожих на математические функции других языков). 900 Часть IV. Объекты языка JavaScript
Объект Math исцользуется в операторах так же, как и любой другой объект JavaScript: ссылка начинается с имени объекта Math, затем следует точка и имя требуемого свойства или метода. Math, свойство {метод ( [параметр] . . . [, параметр]) Свойства в качестве значений содержат константы (например число я). Методы, как правило, требуют одного или нескольких аргументов. Каждый метод возвращает результат. Свойства Свойства объекта Math в JavaScript представляют собой набор математических констант. Они приведены в табл. 28.1 с точностью 16 знаков после запятой. .t „■■-<■,- '•' - ■'\v,*'V- 'iKv,. {Л^4Я Свойство Значение Описание Math.E Math.LN2 Math.LNIO )Math.LOG2E Math.LOGlOE Math.PI Math.SQRTl_2 Math.SQRT2 2.718281828459045091 0.6 9314718 05599452 862 2.302585092994045901 1.442695040888963387 0.4342944819032518167 3.141592653589793116 0.7071067811865475727 1.414213 562373095145 Постоянная Эйлера (е) Натуральный логарифм числа 2 Натуральный логарифм числа 10 Двойной логарифм числа е Десятичный логарифм числа е Число к Квадратный корень из 0,5 Квадратный корень из 2 Эти значения используются во многих арифметических операциях. Например, для вычисления периметра окружности диаметром d применяется формула. circumference = d * Math.PI; Наиболее распространенной ошибкой разработчиков сценариев является то, что не учитывается регистр в имени объекта Math и в именах его свойств. Методы Методы — это основа возможностей объекта Math в JavaScript. За исключением метода Math. random (), все они имеют один или более аргументов. Тригонометрические методы, как правило, запускаются с одним параметром; другие методы определяют наибольшее или наименьшее из группы чисел. Метод Math. raridom () не имеет аргументов и возвращает случайное число в интервале от 0 до 1 (этот метод не поддерживается в версиях NN2 для Windows и Macintosh). Все методы объекта Math, их синтаксис и описание приведены в таблице 28.2. Метода объекта Math Метод Возвращаемое значение Math.abs(val) Math.acos(val) Math.asin(val) Абсолютное значение val Арккосинус (в радианах) val Арксинус (в радианах) val Глава 28. Объекты Math, Number и Boolean 901
Окончание табл. 28.2 Метод Math.atan(val) Math.atan2(vail Math.ceil(val) Math.cos(val) Math.exp(val) Math.floor(val) Math.log(val) Math.max(vail, Math:min(vail, Math.pow(vail, Math.random() Math.round(val) Math.sin(val) Math.sqrt(val) Math.tan(val) , val2) val2) val2) val2) Возвращаемое значение Арктангенс (в радианах) val Угол в полярных координатах между х и у Целое числр, большее или равное val Косинус val Постоянная Эйлера в степени val Целое число, меньшее или равное val Натуральный логарифм (с основанием е) val Большее из двух чисел val 1 и val2 Меньшее из двух чисел val 1 и val2 vail В Степени val2 Случайное число в интервале от о до 1 N+i, когда val >= п. 5; иначе N Косинус (в радианах) val Квадратный корень val Тангенс (в радианах) val HTML не является средой для дизайнеров графических систем, поэтому в нем редко применяют тригонометрические функции для вычисления расположения объектов. Лишь после появления позиционируемых элементов авторы сценариев получили возможность вычислять траекторию движущихся элементов. Для тех, кто не силен в программировании, математика является сложной наукой. Однако JavaScript позволяет ограничиться имеющимися знаниями в области арифметики и логики, оставляя сложные математические функции тем, кто любит ими пользоваться. Генерирование случайных чисел Метод Math. random () возвращает число с плавающей точкой в интервале от 0 до 1. Если сценарий, например, реализует карточную игру, то в ней требуются генерировать случайные значения в диапазоне от 1 до 52; для имитации игральной кости — от 1 до 6. Для генерирования случайного целого числа от нуля до заданного значения используется следующая формула. Math.floor(Math.random() * n) Максимальным значением является п. Для генерирования чисел из заданного диапазона применяется формула Math.floor(Math.random() * (n - m'+ 1)) + m где m — наименьшее возможное целое число, an — наибольшее. При игре в кости для каждой из них используется такая формула. newDieValue = Math.floor(Math.random() * 6) + 1; Сокращенный вариант использования объекта Math В главе 31 подробно описана конструкция JavaScript, позволяющая упростить обращение к различным свойствам и методам объекта Math. Для этого существует оператор with. 902 Часть IV. Объекты языка JavaScript
Оператор with указывает JavaScript, что следующая за ним группа операторов (в фигурных скобках) ссылается на определенный объект. Для объекта Math основная конструкция выглядит таким образом. with (Math) { //операторы } Во всех внутренних операторах можно опустить ссылку на объект Math. Сравните длинный способ подсчета площади круга (с радиусом шесть единиц) result = Math.pow(6,2) * Math.PI; с короткой ссылкой with (Math) { result = pow(6,2) * PI; } Последний пример содержит больше строк кода, однако ссылки на объект короче, а читаемость кода лучше. Для длинной последовательности расчетов использование оператора with для обращения к свойствам и методам объекта Math позволяет сократить вводимый код, а также уменьшить вероятность ошибок в ссылках. Конструкцию with можно использовать и с другими полноценными объектами, при этом JavaScript присоединяет имя объекта лишь к тем ссылкам, где оно отсутствует. С другой стороны, такой подход не очень эффективен, поскольку интерпретатору JavaScript приходится выполнять немало внутренних операций для отслеживания всех ссылок. Объект Number Свойства Методы constructor toExponential() MAX_VALUE toFixedO MIN_VALUE toLocaleString() NaN' toStrihgO NEGATIVE_INFINITY toPrecision() POSITIVE_INFINITY valueOf() prototype Синтаксис Создание числового объекта. var val = new Number(number) Доступ к свойствам и методам объекта Number. число. свойство | метод ( [параметры] ) Number. свойство \ метод{ [параметры] ) Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Глава 28. Объекты Math, Number и Boolean 903
Описание объекта Объект Number используется редко, поскольку в большинстве случаев возможностей JavaScript вполне хватает для несложных расчетов. Однако объект Number содержит определенную информацию и обладает определенными преимуществами для опытных программистов. Первыми в списке идут свойства, определяющие числовые диапазоны в языке. Наибольшее число (и в NN, и в Ш) равно 1.79Е+308, наименьшее — 2.22Е-308. Любое число, большее максимального, равно POSlTIVE_INFINITY, а меньшее минимального— NEGATIVE^ INFINITY. Однако эти значения встречаются редко. Наиболее полезным свойством этого объекта JavaScript является prototype. В главе 27 было показано, как добавить метод к прототипу объекта String, чтобы его содержал каждый новый создаваемый объект. То же самое относится и к свойству Number. prototype. Если к каждому числовому объекту необходимо добавить определенную функциональность, это свойство оказывается полезным. Оно применяется к числовым объектам, но не к числовым значениям. Для опытных программистов следует отметить, что числовые объекты и числовые значения в JavaScript внутренне определяются браузером как 64-битовые значения двойной точности ШЕЕ. Свойства constructor См. string. constructor (глава 27) MAXJVALUE MINJVALUE NEGATIVE_INFINITY POSITIVE_INFINITY Значение: число Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN3+, Mozl+, Safari 1+ Свойства Number. MAX_VALUE и Number. MIN_VALUE принадлежат статическому объекту Number. Они равны наибольшему и наименьшему допустимому в JavaScript (и ECMAScript) значению: 1,7976931348623157 х 10308 и 5 х 10"324 соответственно. Числа, находящиеся за пределами этого диапазона, равны Number.POSITIVE_INFINITY или Number. NEGATIVE_INFINITY. Пример Введите каждое из приведенных далее выражений в верхнее поле приложения The Еvaluator, чтобы ознакомиться со значениями этих свойств. Number.MAX_VALUE Number.MIN_VALUE Number.NEGATIVE_INFINITY Number.POSITIVE_INFINITY См. также: свойство NaN; глобальная функция i sNaN (). 904 Часть IV. Объекты языка JavaScript
NaN Значение: NaN Только для чтения Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Свойство NaN представляет собой константу, посредством которой JavaScript сообщает, что аргумент, результат функции или метода, не является числом. Чаще всего значение NaN присутствует в сценарии как результат выполнения функции parseInt () или parseFloat (), когда преобразуемая строка начинается не с цифры. Для проверки, является ли значение NaN, используется глобальная функция isNaN (). Пример См. описание функции isNaN () в главе 34. См. также: глобальная функция isNaN (). prototype См. строка .prototype (глава 27). Методы число.toExponential(количество) число.toFixed(количество) число.toPrecision(точность) Возвращаемое Значение: строка. Совместимость: WinIE5.5+, MacIE-, NN6+, Mozl+, Safari 1+ Последнее дополнение стандарта ЕСМА (а значит, и браузеров с поддержкой JavaScript) — три метода объекта Number, предназначенных для форматирования строковых представлений чисел. Каждый метод имеет свой тип аргумента, но все они возвращают строки. Все математические операции необходимо проводить над числовыми объектами, поскольку они имеют наибольшую точность. После того, как результат получен, одним из этих методов следует преобразовать число в строку для отображения в теле страницы или текстовом поле. Метод toExponential () отображает число в экспоненциальной форме, даже если оно принадлежит тому диапазону, в котором JavaScript применяет стандартную форму. Целочисленным параметром является количество знаков после запятой (отображаются даже нули). Например, если переменная содержит значение 345, метод toExponential (3) преобразует его в строку 3 .450е+2, т.е. представление числа 3,45x102 в JavaScript. Метод toFixed () используется для форматирования числа с определенным количеством цифр после запятой. Этот метод применяется, например, для отображения результатов финансовых расчетов в единицах и сотых долях (например, долларах и центах). Целочисленным аргументом является количество цифр после запятой. Если число имеет больше цифр, чем требуется отобразить, метод округляет его с учетом неокругленного значения соседней цифры. Например, значение 123.455 с учетом двух цифр после запятой выводится как 123 .46, а 123 .4549 — как 123 .45. Метод toFixed () нельзя считать точным в округлении, однако его возможностей вполне достаточно в большинстве случаев. Метод toPrecision () позволяет определить общее количество цифр (до и после запятой) в отображаемом числе. Другими словами, он определяет точность числа. Следующий список демонстрирует результаты, полученные при разных значениях аргумента. Глава 28. Объекты Math, Number и Boolean 905
var num = 123.45 num.toPrecision(l) // результат le+2 num.toPrecision(2) // результат 1.2e+2 num.toPrecision(3) // результат 123 num.toPrecision(4) // результат 123.5 num.toPrecision{5) // результат 123.45 num.toPrecision(6) // результат 123.450 Обратите внимание, что метод toPrecisionO проводит такое же округление, как и toFixed(). Пример Вы можете использовать приложение The Evaluator для изучения методов число .toExponential(), число.toFixed(), число.toPrecision(precisionDigits), подставляя в них самые разные параметры. Перед вызовом этих методов назначьте числовое значения одной из встроенных глобальных переменных. а = 10/3 a.toFixed(4) м$м + a.toFixed(2) Ни один из этих методов не вызывается по отношению к текстовой строке (например, 123.toExponencial (2)). См. также: объект Math. число.toLocaleString() Возвращаемое значение: строка. Совместимость: Winffi5.5+, МасШ5+, NN6+, Mozl+, Safaril+ Согласно стандарту ЕСМА версии 3, браузеры обладают некоторой свободой действий в определении того, как метод toLocaleString О возвращает строковое значение, соответствующее языковому стандарту клиентской системы или браузера. Ш5.5 возвращает то же значение, что и метод toFixed (2). См. также: методы число. toFixed (), число. toString (). число. toString ( [сисИсчисления] ) Возвращаемое значение: строка. Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ Метод число.toString() возвращает строковое представление заданного числа. По умолчанию используется десятичная система исчисления (10), даже если аргумент задан в другой системе. Можно указать и другую систему исчисления (например, 2 для двоичной, 16 — для шестнадцатеричной), и число будет преобразовано в соответствующий формат. Пример Запустите приложение The Evaluator для изучения метода число. toString (). Назначьте значение 12 переменной а, чтобы увидеть, как число преобразуется в строку с разной основой числа. а = 12 a.toString() // base 10 a.toString(2) a.toString(16) См. также: метод toLocaleString (). 906 Часть IV. Объекты языка JavaScript
число. valueOf () См. число.valueOf () (глава27). Объект Boolean Свойства Методы constructor toStringO prototype valueOf() Синтаксис Создание объекта Boolean. var val = new Boolean{булевоЗначение) Доступ к свойствам объекта Boolean. булевОбъект.свойство\метод Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safaril+ Описание объекта В JavaScript приходится часто работать со значениями логического типа, особенно в условных операторах. Так же, как строковые значения дополняются свойствами строковых объектов, значения логического типа обладают дополнительными свойствами благодаря объекту Boolean. Например, когда логическое значение выводится в текстовом поле, строки "true" и "false" представляют метод tost ring () объекта Boolean. Объект Boolean может понадобиться лишь в случае, когда ко всем логическим объектам, создаваемым конструктором new Boolean (), необходимо добавить свойство или метод. Аргументами конструктора могут быть строковые версии значений, числа (0 — false; любое целое— true), а также выражения, результатом которых является значение логического типа. Каждый новый объект Boolean будет обладать новыми свойствами или методами, добавленными к свойству prototype этого объекта. Подробнее о свойствах и методах объекта Boolean можно узнать из листингов для соответствующих свойств и методов объекта String (глава 27). Глава 28. Объекты Math, Number и Boolean 907
Объект Date озможно, нечасто используемой, но чрезвычайно полез-, ной задачей JavaScript является обработка даты и време-^ ни. Программисты избегали управления объектом Date в ранних версиях JavaScript, поскольку наличие многочисленных ошибок в браузерах на разных платформах сделали программирование даты и времени опасным без общего тестирования. Даже после уменьшения числа ошибок работа со значениями дат требует знания мировых временных зон и их взаимосвязей со стандартной точкой отсчета — GMT (Greenwich Mean Time — время по Гринвичу) или UTC (Coordinated Universal Time — всеобщее скоординированное время). В последних версиях браузеров обработка даты и времени значительно улучшилась, поэтому есть надежда, что авторы будут чаще использовать подобные расчеты на своих страницах. В главе 54 приведен пример приложения, позволяющего выделить области Web-узла, обновленные с момента последнего посещения. Такое приложение основано на арифметических операциях с датами и зональным распределением времени. Перед тем как рассмотреть методы управления датами в JavaScript, мы опишем основные принципы образования временных зон и их влияние на обработку даты и времени в браузере. Следующий раздел посвящен тем, кто мало знаком с такими понятиями, как GMT и UTC. Временные зоны и GMT По международному соглашению, Земной шар разделен на временные зоны. Например, если солнце находится в зените, то это указывает на середину дня. Текущее время зоны мы устанавливаем на своих часах — это и есть локальное время. Замечательно, если вся активность происходит в пределах одной временной зоны. Однако быстрый информационный обмен между различными частями Земного шара зачастую требует выхода за пределы локальной зоны. Живя в Нью-Йорке, например, вряд ли вам захочется разбудить кого-то в Лос-Анджелесе ранним телефонным звонком. Если рассмотреть временную зону, над которой солнце находится в данный момент, то во всех временных зонах
к востоку от нее полдень уже пройдет, а время в каждой последующей зоне на один час больше (за исключением тех зон, где оно сдвинуто на определенные доли часа). Поэтому в телепрограммах в США, которые одновременно показывают в восточной и центральной зонах, анонсы выглядят примерно так: "10 по восточному времени, 9 по центральному". I В данном разделе мы будем говорить Солнце "движется" по отношению к Земле, /назаметку поскольку это более привычно для нашего восприятия. Разумеется, исходя из # <^*" теории Коперника, все происходит наоборот. Многим международным компаниям приходится координировать расписания и график работы. Учесть разницу времени в различных зонах (не говоря уже о таких сезонных отклонениях, как перевод времени) непросто. Чтобы спасти ситуацию, была определена стандартная точка отсчета: временная зона, проходящая через обсерваторию в городе Гринвич в Англии. Эту временную зону называют Средним временем по Гринвичу (Greenwich Mean Time или GMT). "Среднее" означает буквально следующее: точно с противоположной стороны Земного шара (в Тихом океане) находится меридиан, принятый за точку начала дня, — еще один международный стандарт. Таким образом, зона GMT расположена посередине полного цикла календарного дня. Недавно GMT получила еще одну аббревиатуру — UTC (произносится: ю-ти-си). Ее английская версия — Coordinated Universal Time (Всеобщее скоординированное время). Таким образом, UTC — это то же самое, что и GMT. Если системные часы компьютера установлены правильно, то отсчет проводится по времени GMT. Но поскольку в папке Панель управления, как правило, выставлена локальная временная зона, все значения времени создания и изменения файлов отображаются в локальном времени. Компьютер знает разницу между локальным временем и GMT. При переходе на летнее/зимнее время необходимо проверить корректность сделанных установок. В Windows операционная система автоматически осуществляет перевод часов и запрашивает подтверждение этой операции. Если вы путешествуете с ноутбуком из одной зоны в другую, необходимо изменить установки временной зоны, а не часов компьютера. Обработка даты и времени в JavaScript выполняется, как и в системных часах (от которых зависит работа программ). Значения дат, генерируемых в сценарии, сохраняются во внутреннем формате GMT, однако для пользователя (не Web-серверу) все значения выводятся, как правило, в локальном представлении. Кроме того, помните, что значения дат генерируются сценариями в компьютере пользователя, а не пересылаются с сервера. Это довольно сложная для понимания концепция, которая используется при работе с датой и временем в JavaScript. При обработке даты и времени в JavaScript необходимо придерживаться общемирового взгляда: предполагается, что средства компьютера конечного пользователя правильно преобразуют локальное время в GMT. При тестировании иногда приходится изменять настройки системных часов, имитируя, таким образом, местонахождение в другой временной зоне. Объект Date Как и для других объектов в JavaScript, существует различие между единичным статическим объектом Date, который присутствует в каждом окне (или фрейме) и объектом даты, содержащим определенную дату и время. Статический объект Date (с прописной буквы D) используется только в нескольких случаях: в первую очередь, для создания нового объекта даты или для вызова нескольких методов, поддерживаемых объектом Date. Большая часть процесса обработки даты и времени затрагивает копии объекта Date. Эти копии называют объектами даты. Каждый такой объект представляет собой "моментальный снимок" времени, выраженный в миллисекундах. Если вам требуется получить "идущие" часы, Глава 29. Объект Date 909
сценарий должен периодически создавать новые объекты даты — моментальные снимки текущего состояния системных часов. Для вывода времени на странице из объекта даты необходимо извлечь часы, минуты и секунды, а затем отобразить их (например, в виде электронных часов или гистограммы). Фактически, копия объекта даты, предназначенная для чтения или изменения компонент (например, месяца или часа), вызывает различные методы этого объекта. Несмотря на свое имя, объект даты содержит информацию не только о дате, но и о времени. Оба элемента присутствуют в каждом объекте. Создание объекта даты В операторе, создающем объект в JavaScript, используется ключевое слово new. Для этого применяется следующий синтаксис. var имяОбъектаДаты - new Date([параметры]); В описанном случае объект становится объектом даты, а не строкой или числовым значением. Когда переменная содержит ссылку на объект даты, доступ ко всем его методам осуществляется обычным образом. var result = имяОбъектаДаты.метод О ; Переменные, подобные возвращаемому результату, сценарий использует для проведения расчетов или применяет их для отображения даты (некоторые методы позволяют извлечь компоненты даты или времени). Если же объекту даты нужно присвоить новое значение (например, добавить один год), для этого используется соответствующий метод. имяОбъ ектаДа ты. ме тод (нов оеЗна чение) ; Это выражение не похоже на стандартное присвоение в JavaScript с оператором =, однако именно так работают методы объекта даты. Программирование операций обработки дат в сценарии требует знания арифметики временных зон. Несмотря на то, что JavaScript может выразить объект даты в локальном времени, внутренним форматом всегда является GMT. Для добавления одного года к текущей дате используются следующие методы. var oneDate = new Date О // Создание объекта, содержащего // текущую дату в GMT var theYear = oneDate.getYearO //В переменной theYear теперь // содержится значение 98 theYear = theYear +1 // Переменная theYear становится // равной 99 oneDate.setYear(theYear) // В объекте устанавливается новое // значение года После окончания последовательности действий объект oneDate автоматически корректирует другие компоненты даты, например, день недели, который, очевидно, через год будет другим. Теперь значение даты из объекта oneDate можно извлечь как строку и отобразить в поле страницы или отправить CGI-программе на сервере. Вопрос аргументов при создании нового объекта даты достаточно сложен (во многом из- за той гибкости, которую обеспечивает JavaScript). Вспомните, что оператор new Date () предназначен для создания области в памяти, в которой хранятся все компоненты даты. Но не ясно, какой датой и временем необходимо заполнить новый объект. В данном случае в силу вступают аргументы. Если оставить аргументы пустыми, JavaScript присвоит новому объекту текущую дату и время. Естественно, JavaScript воспользуется значением часов компьютера пользователя. Если эти значения не являются корректными, JavaScript не узнает об этом ничего. 910 Часть IV. Объекты языка JavaScript
/ Помните, что новый объект даты содержит также и текущее время, например, /назамту 16:03:19 (в 24-часовом формате). Этот факт нужно учитывать при таких расче- * ^>" тах, как количество дней между датами и т.д. Для создания нового объекта даты можно воспользоваться одним из пяти способов присвоения ему даты и времени. Речь идет об аргументах функции конструктора new Date (). new Date("Месяц дд, гггг чч:мм:сс") new Date("Месяц дд, гггг") new Date(гг,мм,дд,чч,мм,ее) new Date(гг,мм,дд) new Date(миллисекунды) Четыре первых способа можно разбить на две группы — с длинными строками и списком значений, разделенных запятой (причем параметры времени не являются обязательными). Если они опущены, метод устанавливает их значения равными 0 (полночь). Аргументы даты опустить нельзя — каждый объект даты при создании требует их указания. В строковых версиях необходимо указывать полное английское название месяца. Аббревиатуры не поддерживаются. Далее следует число, год, часы, минуты и секунды (именно в такой последовательности). Для значений, меньших 10, используется одно- или двухеим- вольная версия (например, 4:05:00). Часы, минуты и секунды разделяются двоеточием. В коротких версиях параметров методов указывается список целочисленных аргументов в приведенном выше порядке. Аргументом последней версии параметров метода является значение даты и времени, выраженное в миллисекундах. Такой формат часто используется при арифметических расчетах дат (об этом рассказано далее). Для его преобразования в объект даты применяется конструктор new Date (). Впоследствии объект даты позволяет получить более удобные значения. Естественные свойства и методы объекта Как и объекты String и Array, объект Date поддерживает небольшой набор свойств и методов, характерных для всех объектов JavaScript. В браузерах NN3+ и IE3/J2+ объект Date имеет свойство prototype, позволяющее добавить к объекту новые свойства или методы. Примеры его использования описаны при рассмотрении свойства prototype объектов String и Array (в главах 27 и 30, соответственно). Кроме того, каждый объект даты в IE4+/W3C имеет свойство constructor, указывающее на функцию, с помощью которой был создан объект. Объект даты имеет несколько методов для преобразования значений своих компонент в строки. Они являются более специфическими, чем toStringO. Метод valueOf () возвращает значение в миллисекундах, кЬторое совпадает с результатом метода getUTCMilliseconds () (см. следующий раздел). Методы объекта Date Набор методов объекта даты используется для чтения и изменения информации о дате и времени, сохраненной в объекте. Две категории этих методов легко различить, поскольку они начинаются со слов get и set, соответственно. Методы статического объекта Date, наследуемые всеми его копиями, перечислены в табл. 29.1. Список впечатляет, однако в нем легко выделить общее. Большинство методов работает с одной компонентой даты или времени: годом, месяцем, числом и т.д. Каждый блок методов get и set подразделяется на два набора: для локального формата и для формата UTC. Если не указано другое, метод является частью объекта Date, начиная с первого поколения браузеров, поддерживающих сценарии. Глава 29. Объект Date 911
Метод dateObj .getFullYearO dateObj.getYear() dateObj.getMonth() dateObj.getDate() dateObj.getDay() dateObj.getHours() dateObj.getMinutes 0 dateObj.getSeconds 0 dateObj.getTime() dateObj.getMilliseconds() dateObj.getUTCFullYear() dateObj.getUTCMonth() dateObj.getUTCDate() dateObj .getUTCDayO dateObj.getUTCHours() dateObj.getUTCMinutes() dateObj.getUTCSeconds() dateObj.getUTCMilliseconds() dateObj.setYear(val) dateObj.setFullYear(val) dateObj.setMonth(val) dateObj.setDate(val) dateObj.setDay(val) dateObj.setHours(val) dateObj.setMinutes(val) dateObj.setSeconds(val) dateObj.setMilliseconds(val) dateObj.setTime(val) dateObj.setUTCFullYear(val) dateObj.setUTCMonth(val) dateObj.setUTCDate(val) dateObj.setUTCDay(val) dateObj.setUTCHours(val) Диапазон значений 1970-... 70-. . . 0-11 1-31 0-6 0-23 0-59 0-59 0-. . . 0- . . . 1970-. . . 0-11 1-31 0-6 0-23 0-59 0-59 0-. . . 1970-... 1970-... 0-11 1-31 0-6 0-23 0-59 0-59 0-. . . 0-. . . 1970-... 0-11 1-31 0-6 0-23 Описание Год (NN4+, IE3+) (См. текст) Месяц (Январь = 0) Число День недели (Воскресенье = 0) Часы в 24-часовом формате Минуты Секунды Миллисекунды с 1/1/70 00:00:00 GMT Миллисекунды с 1/1/70 00:00:00 GMT (NN4+, IE3+) Год UTC (NN4+, IE3+) Месяц UTC (Январь = 0) (NN4+, IE3+) Число UTC (NN4+, IE3+) День недели UTC (Воскресенье = 0) (NN4+, IE3+) Часы UTC в 24-часовом формате (NN4+, IE3+) Минуты UTC (NN4+, IE3+) Секунды UTC (NN4+, IE3+) Миллисекунды UTC с 1/1/70 00:00:00 GMT (NN4+, IE3+) Установка года (четырехзначного) Установка года (NN4+, IE3+) Установка месяца (Январь = 0) Установка числа Установка дня недели (Воскресенье = 0) Установка часов в 24-часовом формате Установка минут Установка секунд Установка миллисекунд с 1/1/70 00:00:00 GMT (NN4+, IE3/J2+) Установка миллисекунд с 1/1/70 00:00:00 GMT Установка года UTC (NN4+, IE3+) Установка месяца UTC (Январь = 0) (NN4+, IE3+) Установка числа UTC (NN4+, IE3+) Установка дня недели UTC (Воскресенье = 0) (NN4+, IE3+) Установка часов UTC в 24-часовом формате (NN4+, IE3+) 912 Часть IV. Объекты языка JavaScript
Окончание табл. 29.1 Метод Диапазон значений Описание dateObj.setUTCMinutes(val) 0-59 dateObj.setUTCSeconds(val) 0-59 dateObj.setUTCMilliseconds(val) 0- . . . dateObj.getTimezoneOffset() 0-... dateObj.toDateString() dateObj.toGMTString() dateObj.toLocaleDateString() dateObj.toLocaleString() dateObj.toLocaleTimeString() dateObj.toString() dateObj.toTimeString() dateObj.toUTCString() Date.parse("dateString") Date.UTC(date values) Установка минут UTC (NN4+, IE3+) Установка секунд UTC (NN4+, IE3+) Установка миллисекунд UTC с 1/1/70 00:00:00 GMT (NN4+, IE3+) Разница в минутах по отношению к GMT/UTC Строка с датой (без времени) в формате браузера (IE5.5+) Строка с датой и временем в глобальном формате Строка с датой без времени в локализованном формате системы (NN6+, IE5.5+) Строка с датой и временем в локализованном формате системы Строка со временем без даты и в локализованном формате системы (NN6+, IE5.5+) Строка с датой и временем в формате браузера Строка со временем без даты в формате браузера (IE5.5+) Строка с датой и временем в глобальном формате (NN4+, IE3+) Преобразование строки с датой в число миллисекунд Преобразование строки с датой GMT в число миллисекунд Выбор между UTC и локальными версиями методов зависит от нескольких факторов. Если страница предназначена для поддержки ранними версиями браузеров, в любом случае придется ограничиться локальными версиями. В новых браузерах операции, подобные вычислению разницы между двумя датами или созданию счетчика времени, оставшегося до наступления события, выполняются с помощью любого набора методов (важно использовать во всех расчетах методы только одного типа). При смешанном применении различных методов получится неправильный результат. UTC-версии методов оказываются полезными при расчетах, учитывающих временную зону пользователя и некоторое абсолютное значение другой зоны. JavaScript представляет информацию о дате в виде количества миллисекунд (тысячных долей секунд), прошедших с 1 января 1970 года GMT (UTC). Даты до этого момента хранятся как отрицательные значения (см. раздел об ошибках далее в этой главе). Независимо от локализации формата даты, миллисекунды являются универсальными единицами измерения времени в JavaScript. Для получения необходимой точности все действия по сложению или вычитанию даты следует проводить в формате миллисекунд. Несмотря на то, что значения в миллисекундах редко отображаются пользователю, сценариям часто приходится проводить вычисления с ними. Для получения даты и времени в формате миллисекунд используется метод dateObj . getTime (). var startDate = new Date(); var started = startDate.getTime0; Глава 29. Объект Date 913
В имени метода присутствует слово time (время), поскольку он возвращает общее число миллисекунд с 1 января 1970 года; в этом же значении содержится и дата. Другие методы get объекта даты возвращают определенные ее компоненты. При их обработке следует проявлять осторожность, так как некоторые значения начинаются с 0. Например, январь в JavaScript имеет номер 0, а декабрь— 11. Часы, минуты и секунды начинаются с нуля (это вполне логично). В числах календаря используются реальные единицы — первый день имеет номер 1. Значение года, принадлежащего двадцатому веку, равно разности между реальным годом и 1900. Например, год 1996 обозначается как 96. Годы до 1900 и после 1999 в JavaScript отображаются в полном четырехзначном формате. Таким образом, если значение меньше 100, к нему нужно добавить 1900. var today = new Date(); v var thisYear = today.getYear0; if (thisYear < 100) { thisYear += 1900; } В данном случае предполагается, что не используются даты до 100 года до нашей эры. Если страница предназначена для ГЕЗ+ и NN4+, воспользуйтесь методом get Full Year (), который возвращает четырехсимвольное значение года. Для изменения какой-либо компоненты даты применяется соответствующий метод set. Если изменение одного значения требует корректировки других, JavaScript выполняет все операции автоматически. Рассмотрим, как изменяются связанные значения в следующей последовательности. myBirthday = new Date("September 11, 2001"); result = myBirthday.getDay0; // результат 2, вторник myBirthday.setYear(2002); // переход к следующему году result = myBirthday.getDay(); // результат 3, среда То же число является другим днем недели — JavaScript сам отслеживает это изменение. Учет временных зон Понимание работы метода dateOb j . getTimezoneOf f set () требует знакомства с настройками операционной системы и международным форматом (по крайней мере, в компьютерном мире) представления даты и времени. Если в папке Панель управления значения для локальной временной зоны не установлены, соответствующие свойства будут пустыми для большинства дат. В восточной части Северной Америки, например, применяется стандартная восточная временная зона, которая на пять часов отстает от GMT. Результатом метода getTimezoneOf f set () является разница в минутах между временем, установленным в локальном компьютере и GMT, т.е. 300 минут в данном случае. На платформе Windows значение автоматически изменяется при переходе на летнее или зимнее время. Смещения к востоку от GMT (точки отсчета) представлены отрицательными значениями. Строковые даты После создания объекта даты при попытке ее отображения на странице JavaScript автоматически применяет метод toString О . Формат строки зависит от браузера и операционной системы. Например, в Ш6 для Windows XP строка имеет следующий формат. Mon Jan 5 14:11:49 CDT 2004 В NN7 для Windows XP эта строка принимает такой вид. Mon Jan 05 2004 14:11:49 GMT-0500 (Central Standard Time) 914 Часть IV. Объекты языка JavaScript
Internet Explorer возвращает свои собственные версии этой строки. Поэтому не стоит полагаться на определенный формат строки и расположение компонент даты в ней. Для их чтения следует пользоваться методами объекта даты. Тем не менее, JavaScript поддерживает два метода, результатом которых является стандартный строковый формат даты. Один из них, объект Даты, toGMTString (), преобразует дату и время в эквивалент GMT. Формат выглядит так. Моп, 05 Jan 2004 19:11:49 GMT Если вы не слишком хорошо знакомы с форматом GMT, тщательно тестируйте работу своих сценариев. Восемь вечера зимой в пятницу в Калифорнии соответствуют четырем часам утра в субботу по GMT. Если зональные преобразования времени проводить не требуется, то можно воспользоваться методом объектДаты. toLocaleStringO. В NN7 для пользователей Windows в Северной Америке он возвратит значение. Monday, January 05, 2004 14:11:49 Начиная с версий Ш5.5 и NN6, JavaScript позволяет преобразовать объект даты в отформатированные строковые значения даты или времени, что достигается благодаря методам toLocaleDateString () и toLocaleTimeString (). Они возвращают наиболее важные для пользователя значения, основываясь на настройках операционной системы и браузера. Удобные форматы даты в ранних версиях браузеров Если страница предназначена не только для IE5.5+/NN6+/W3C, то вам нужно создать собственные методы, форматирующие дату, для различных версий браузеров. Один из способов создания строки из объекта даты (совместимый с ГЕ4+ и NN4+) приведен в листинге 29.1. <html> <head> x <title>Date String Maker</title> <script type="text/javascript"> monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; function customDateString(oneDate) { var theDay = dayNames[oneDate.getDay()]; ч var theMonth = monthNames[oneDate.getMonthO]; var theYear = oneDate.getFullYear(); return theDay + ", " + theMonth + " " + oneDate. getDateO + ", " + the Year; } </script> </head> <body> <hl> Welcome! </hl> Глава 29. Объект Date 915
<script type="text/javascript"> document.write(customDateString(new Date())) </script> <hr /> </body> </html> Если часы в пользовательском компьютере установлены правильно, в заголовке страницы выводится текущая дата так, будто документ обновлен сегодня. Недостатком этого подхода (который отсутствует у более современного метода toLocaleDateStringO) является отображение даты в заданном формате, который может отличаться от локального, привычного для пользователей. Еще раз о преобразованиях Два последних метода, приведенных в листинге 29.1, принадлежат статическому объекту Date. Они преобразуют дату из строковой или числовой формы в количество миллисекунд. Это значение используется в качестве параметра метода dateOb j . set Time О . Последний удобен для задания в объекте даты нового значения. Аргументом метода Date .parse () является строка, подобная той, которая была приведена в этом разделе (включая и международный формат). Date. UTC () использует список значений, разделенных запятой (в формате: уу, mm, dd, hh, mm, ss) в зоне GMT. Метод Date. UTC () обеспечивает совместимость снизу вверх для преобразования времени в формате GMT (в браузерах NN4+ и Ш4+ для этого применяются методы UTC). Ниже приведен пример создания объекта даты со значением 6 часов пополудни 4 марта 2004 года GMT в браузере WinIE6. var newObj = new Date(Date.UTC(2004,2,4,18,0,0)); result = newObj . toStringO ; // результат "Thu, Mar 04 10:00:00 PST 2004" Второй оператор возвращает время в локальной временной зоне, поскольку не все UTC- методы автоматически преобразуют время в формате GMT (Сохраняемое в объекте) в локальное. Арифметика даты и времени По ряду причин с датой и временем приходится выполнять различные вычисления. Например, подсчитать дату через определенное число дней или недель в будущем или количество дней между двумя датами. Для расчетов такого рода в JavaScript наиболее удобными единицами исчисления являются миллисекунды. В сценариях, где проводятся вычисления, целесообразно ввести набор переменных, содержащих количество миллисекунд в минуте, часе, дне и т.д., а затем использовать его в расчетах. Ниже приведен пример присвоения нужных значений. var oneMinute = 60 * 1000; var oneHour = oneMinute * 60; var oneDay = oneHour * 24; var oneWeek = oneDay * 7; С их помощью легко подсчитать, например, дату через одну неделю. var targetDate = new Date(); var datelnMs = targetDate.getTime(); datelnMs += oneWeek; targetDate.setTime(datelnMs); В другом примере компоненты объекта даты используются для вывода приветственного сообщения (по локальному времени). Листинг 29.2 дополняет листинг 29.1. 916 Часть IV. Объекты языка JavaScript
<html> <head> <title>Date String Maker</title> <script type="text/javascript"> monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; function customDateString(oneDate) { var theDay = dayNames[oneDate.getDay()]; var theMonth = monthNames[oneDate.getMonth()]; var theYear = oneDate.getFullYear(); return theDay + ", " + theMonth + " " + oneDate.getDate() + ", " + theYear; } function dayPart(oneDate) { var theHour = oneDate.getHours0; if (theHour < 6 ) return "wee hours"; if (theHour < 12) return "morning"; if (theHour < 18) return "afternoon"; return "evening"; } </script> </head> <body> <hl>Welcome!</hl> <script type="text/javascript"> today = new Date(); var header = (customDateString(today)).italics(); header += "<BR>We hope you are enjoying the "; header += dayPart(today) + "."; document.write(header); </script> <hr /> </body> </html> Сценарий делит день на четыре части и в зависимости от текущего момента времени выводит приветственное сообщение. Оно зависит от часа, содержащегося в объекте даты (значение последнего определяется временем загрузки страницы в браузер). После вывода на странице сообщение уже не изменяется, сколько времени она ни была бы загружена в браузере. Подсчет дней Арифметические операции с датой часто оказываются полезными. Например, для вывода числа рабочих дней, оставшихся до Рождества (во временной зоне пользователя), или таймера обратного отсчета до 2100 года. Глава 29. Объект Date 917
Листинг 29.3 демонстрирует, как подсчитать разницу между текущей датой и заданной датой в будущем. Все вычисления относятся к локальной временной зоне. Пример выводит количество рабочих дней до Рождества (25 декабря). Сценарий следует такому алгоритму: текущая дата и ближайшее 25 декабря преобразуются в формат миллисекунд, затем вычисляется их разность. В преобразованиях JavaScript автоматически учитывает високосные годы. Особенность заключается в правильной установке года следующего рождественского дня. Вы не сможете задать фиксированную дату этого года, так как программа, запущенная 26 декабря, будет считать ближайшим рождественским днем Рождество в следующем году. Поэтому конструктор объекта даты Рождества использует специальные компоненты при инициализации объекта. <html> <head> <title>Christmas Countdown</title> <script type="text/javascript"> function getDaysUntilXmas() { var oneMinute = 60 * 1000; var oneHour = oneMinute * 60; var oneDay = oneHour * 24; var today = new Date(); var nextXmas - new Date() nextXmas.setMonth(ll); nextXmas.setDate(25) ; if (today.getMonthO == 11 && today.getDate() > 25) { nextXmas.setFullYear(nextXmas.getFullYear() + 1); } var diff = nextXmas.getTime() - today.getTime(); diff = Math.floor(diff/oneDay); return diff; } </script> </head> <body> <hl> <script type="text/javascript"> var header = "You have <i>" + getDaysUntilXmas() + "< header += "shopping days until Christmas."; document.write(header); </script> </hl> <hr /> </body> </html> Л/Ь В другом варианте определения времени, оставшегося до некоторой даты, учитываются временные зоны. Страница выводит счетчик времени до точного начала Летних Олимпийских игр в Пекине в 2008 году. Это событие происходит в определенной временной зоне, поэтому необходимо правильно учесть разницу во времени с зоной пользователя. В листинге 29.4 приведена упрощенная версия, где таймер выводится в текстовом поле. Вывод, естественно, можно организовать различными способами на свой вкус. Точным временем считается 11:00 GMT 8 августа 2008 года (дата, конечно же, точная, но время начала может измениться). 1 918 Часть IV. Объекты языка JavaScript
Сценарий устанавливает значения глобальных переменных, которые вычисляются только один раз, чтобы постоянно вызываемая для обновления таймера функция работала эффективно. Метод Date. UTC () возвращает дату и время начала Игр по GMT. Функция getTimeUnt il (), аргумент которой задан в миллисекундах (переменная targetDate) подсчитывает разницу между датой начала и текущим внутренним значением миллисекунд часов персонального компьютера. Функция getCountDown () вычисляет количество дней, часов, минут и секунд в полученном числе миллисекунд <html> <head> <title>Summer Games Countdown</title> <script type="text/javascript"> // глобально - вычисляется только один раз // целевая дата - 1100GMT on August 8, 2008 var targetDate = Date.UTC(2008, 7, 8, 11, 0, 0, 0) ; var oneMinute = 60 * 1000; var oneHour = oneMinute * 60; var oneDay = oneHour * 24; function getTimeUntil(targetMS) { var today = new Date(); var diff = targetMS - today.valueOf(); return Math.floor(diff); } function getCountDown() { var ms « getTimeUntil(targetDate); var output = ""; var days, hrs, mins, sees; if (ms >= 0) { days = Math.floor(ms/oneDay); ms -« oneDay * days; hrs = Math.floor(ms/oneHour); ms -= oneHour * hrs,- mins = Math.floor(ms/oneMinute); ms -= oneMinute * mins; sees = Math.floor(ms/1000); output += days + " Days, " + hrs + " Hours, " + mins + " Minutes, " + sees + " Seconds"; } else { output += "The time has passed."; } return output; function. updateCountDownO { document.forms[0].timer.value = getCountDown(); setTimeout("updateCountDownO", 1000); } </script> </head> <body onload="updateCountDown()"> <hl>Beijing Games Torch Lighting Countdown</hl> <p> <script type="text/javascript"> document.write("(" + (new Date(targetDate)). Глава 29. Объект Date 919
toLocaleStringO ) ; document.write(" in your time zone.)"); </script> </p> <form> <input type="text" name="timer" size="60" /> </form> <hr /> </body> </html> Ошибки, связанные с управлением датой Каждое новое поколение браузеров повышает надежность обработки объектов даты в сценариях. К сожалению, NN2 имеет ряд ошибок, связанных с управлением датой, на многих платформах, что делает создание сложных приложений просто невозможным. Это относится и к версии для Macintosh. Рекомендуется избегать программирования действий управления датой и временем в NN2 на всех платформах. Ситуация значительно улучшилась в NN3, однако некоторые ошибки остались. Одна из них проявляется на платформе Macintosh. При создании нового объекта, если учесть переход на летнее/зимнее время в аплете Дата и время панели управления, браузер автоматически добавит один час. Пример того, как следует обходить типичные ошибки, приведен в главе 54. Кроме того, NN3 для Macintosh неправильно вычисляет смещения временных зон к востоку от GMT. Вместо того чтобы генерировать отрицательные значения (уменьшающиеся для каждой следующей зоны к востоку), положительная разница во времени просто нарастает при переходе от зоны к зоне к западу от Гринвича. Для Западного полушария это справедливо, однако после пересечения линии полудня значения продолжают расти, вместо того чтобы становиться отрицательными. Проблемы присутствуют и в ГЕЗ. Этот браузер не способен работать с датами до 1 января 1970 года (GMT). Попытки установить меньшие даты приводят к этому же значению. ШЗ также неверно рассчитывает разницу во времени между зонами, следуя ошибочному алгоритму NN2. Браузеры NN3 и NN4 все еще испытывают трудности при обработке дат до 1 января 1 года до нашей эры. В ТЕЛ проблем с такими датами не наблюдается. Необходимо помнить о различиях между версиями NN для Мае и Windows вплоть до версии 4. В Windows при создании объекта, содержащего дату в другой (не текущей) части этого года, браузер устанавливает смещение временной зоны объекта для указанного времени года. На платформе Мае переход на летнее или зимнее время независимо от реальной даты в году настраивается в панели управления. Такая несогласованность присутствует в NN3 и NN4, в результате чего вычисления иногда оказываются смещенными на один час. Таким образом, программирование способов управления объектом Date требует тщательного планирования и активного тестирования на всех возможных комбинациях браузеров и платформ. Проверка дат, вводимых в формы При проверке дат, вводимых в формы, проблема заключается не столько в вычислениях, сколько в большом количестве допустимых форматов, применяющихся в мире. К сожалению, нет никаких возможностей установить, например, соответствует ли значение 03/04/2002 дате 4 марта 2002 года по североамериканскому стандарту или 3 апреля 2002 года по европейскому. 920 Часть IV. Объекты языка JavaScript
Рекомендую разделить поле даты на три компоненты: месяц, день и год. Пользователь введет значения, которые будут проверяться отдельно. Пример такого подхода приведен в листинге 29.5. Страница включает в себя форму, которая проверяется до отправки на сервер. Для каждой компоненты даты проводится своя проверка. Кроме того, дополнительный тест осуществляется в обработчике события onsubmit формы. Если в каком-либо поле содержатся неверные данные, отправка не происходит. <html> <head> <title>Date Entry Validation</title> <script type="text/javascript"> // **Начало общих функций проверки данных** // проверка того, вводились ли входные данные function isEmpty(inputStr) { if (inputStr == "" || inputStr == null) { return true; } return false; } // проверка попадания данных в допустимый диапазон function inRange(inputStr, lo, hi) {. var num = parselnt(inputStr, 10); if (num < lo || num > hi) { return false; } return true,- } // **Конец общих функций проверки данных** function validateMonth(field, bypassUpdate) { var input = field.value; if (isEmpty(input)) { alert("Be sure to enter a month value."); select(field); return false; } else { input .= parselnt(field.value, 10); if (isNaN(input)) { alert("Entries must be numbers only."); select(field); return false; } else { if (!inRange(input,1,12)) { alert("Enter a number between 1 (January) and 12 (December)."); select(field); return false; if (!bypassUpdate) { calcDate 0 ; } Глава 29. Объект Date 921
return true; } function validateDate(field) { var input = field.value; if (isEmpty(input)) { alert("Be sure to enter a date value."); select(field); return false; } else { input = parselnt(field.value, 10); if (isNaN(input)) { alert("Entries must be numbers only."); select(field); return false; } else { var monthField = document.birthdate.month; if (IvalidateMonth(monthField, true)) return false; var monthVal = parselnt(monthField.value, 10); var monthMax = new Array(31,31,29,31,30,31,30,31,31, 30,31,30,31); var top = monthMax[monthVal]; if (!inRange(input,1,top)) { alert("Enter a number between 1 and " + top + "."); select(field); return false; } } } -calcDate 0 ; return true; } function validateYear(field) { var input = field.value; i f (i sEmpty(input)) { alert("Be sure to enter a year value."); select(field); return false; } else { input = parselnt(field.value, 10); if (isNaN(input)) { alert("Entries must be numbers only."); select(field); return false; } else { if (linRange(input,1900,2005)) { alert("Enter a number between 1900 and 2005."); select(field); return false; } } } calcDateO ; return true; 922 Часть IV. Объекты языка JavaScript
function select(field) { field.focus(); field.select(); } function calcDateO { var mm = parselnt(document.birthdate.month.value, 10); var dd = parselnt(document.birthdate.date.value, 10); var yy = parselnt(document.birthdate.year.value, 10); document.birthdate.fullDate.value = mm + "/" + dd + "/" + УУ; } function checkForm(form) { if (validateMonth(form.month)) { if (validateDate(form.date)) { if (validateYear(form.year)) { return true; } } } return false; } </script> </head> <body> <form name="birthdate" action="mailto:fun@dannyg.com" method="P0ST" onsubmit="return checkForm(this)"> Please enter your birthdate< ..<br /> Month:<input type="text" name="month" value="l" size="2" onchange="validateMonth(this)" /> Date:<input type="text" name="date" value="l" size="2" onchange="validateDate(this)" /> Year:<input type="text" name="year" value="1900" size="4" onchange="validateYear(this)" /> <p>Thank you for entering:<input type="text" name="fullDate" size="10" /></p> <pxinput type="submit" /> <input type= "Reset" /></p> </form> </body> </html> На странице присутствуют три поля для ввода, а также одно скрытое поле формы. Данные пересылаются CGI-программе на сервере, которая реагирует только на скрытое поле, содержащее полную дату в формате, пригодном для обработки, например, в базе данных Informix. Не все программы проверяют дату подобным образом. Некоторые приложения более требовательны к дате, вводимой пользователем. Поэтому для введения даты может использоваться только одно поле, но в этом случае требуется другой вариант синтаксического анализа, а не тот, что приведен в листинге 29.5. Процедура проверки даты, введенной в одном поле, представлена в главе 43. Глава 29. Объект Date 923
Объект Array ассив представляет собой единую структуру в JavaScript, предназначенную для хранения упорядоченных наборов данных. В отличие от других языков программирования, массивы JavaScript позволяют хранить данные самых разных типов. Такой подход позволяет, например, создать массив массивов — аналог многомерного массива. Если вы еще не знакомы с программированием, тема массивов может показаться сложной. Важно понимать, что без свойств, которыми обладают массивы, решить некоторые задачи просто невозможно. Перед тем, как начать работу над новым сценарием, следует обдумать, прежде всего, как приложение будет управлять данными и как его можно усовершенствовать, применяя массивы. Прочтите эту главу, чтобы ознакомиться со свойствами и методами массивов JavaScript, изучить способы их применения для решения свои задач. Структурированные данные В программировании массивом называют упорядоченный набор данных. Проще всего представить себе массив как таблицу, подобную создаваемым в процессорах электронных таблиц. В JavaScript возможны только массивы, подобные таблицам с одним столбцом данных и некоторым числом строк. Как отмечалось в части Ш, браузеры с поддержкой JavaScript создают несколько внутренних массивов для объектов в документах HTML и свойств самого браузера. Например, если в документе содержится пять ссылок, браузер создает для них таблицу. Доступ к ссылкам осуществляется по индексу — так же, как и в массиве (начиная с 0): после имени массива в квадратных скобках указывается индекс, например, document. links [0]. Этот элемент соответствует первой ссылке в документе. Во многих приложениях JavaScript массив используется как хранилище данных, с которыми взаимодействуют пользователи страницы. Например, в приложении, приведенном в главе 50, показано, как применять массивы: страница позволяет пользо-
вателям проводить поиск в небольшой таблице по трем первым цифрам номера социального страхования и штату регистрации. Массивы JavaScript позволяют страницам частично воссоздать поведение более сложных CGI-программ, запускаемых на серверах. Если набор данных, используемый в сценарии, не больше по размеру, чем типичное изображение в формате .gif, пользователь задержек при загрузке страницы не заметит. При этом он сможет работать с небольшой базой данных, не обращаясь к серверу. Такие массивы, эмулирующие работу баз данных, очень часто применяются в приложениях JavaScript. Назовем их бессерверными. При создании приложения поищите потенциальное применение массивам. Если среди используемых данных есть несколько объектов или блоков данных, взаимодействующих со сценарием одинаковым образом, скорее всего, массив окажется подходящей структурой для их сохранения. Например, во всех браузерах текстовым полям формы можно присвоить одинаковые имена. В этом случае объекты трактуются как элементы массива. Для управления этими данными в сценарии используется синтаксис доступа к массиву. Таким образом, решение задачи сводится к написанию нескольких операторов JavaScript, а также исключается необходимость в создании специального кода для каждого отдельного поля. Пример такого приложения приведен в главе 51. Кроме того, можно создавать массивы, подобные кэшированным таблицам в языке Java, когда элементу данных поставлено в соответствие имя (ключ), а не числовой индекс. Если данные можно представить в формате таблицы, без сомнения, следует использовать массивы. Создание пустого массива Полноценный объект массива позволяет работать с ним так, как с любым встроенным массивом JavaScript. От вас не требуется определять функцию-конструктор, так как она не позволяет создавать объекты JavaScript. Достаточно создать новый объект массива, воспользовавшись следующей командой. var myArray = new Array(); Объект массива имеет свойство length (для пустого массива оно равно 0). Важно, что оно не содержится в самом массиве, т.е. последний полностью предназначен для сохранения данных. Если требуется создать массив определенного размера (и заполнить его, например, значениями null), в аргументе конструктора задается исходный размер. Например, именно так создается новый массив из 500 элементов, содержащий информацию о коллекции компакт-дисков. var myCDCollection = new Array(500); Создание массива предварительного размера не дает никаких преимуществ, поскольку в любой момент всякому массиву можно добавить новое значение: значение свойства length корректируется автоматически. К примеру, если в массив myCDCol lection [700] добавить новое значение, объект массива изменит свойство length (счетчик начинается с 0). myCDCollection [700] = "Gloria Estefan/Destiny"; collectionSize = myCDCollection.length; // результат 701 Объект массива имеет несколько методов, а также позволяет добавлять пользовательские свойства к прототипу (см. далее в этой главе). Заполнение массива данными Ввод данных в массив так же прост, как присвоение значений переменным. В листинге 30.1 (отсутствует на прилагаемом компакт-диске) предполагается, что с помощью объекта массива нового типа требуется создать список девяти планет Солнечной системы. Глава 30. Объект Array 925
solarSys = new Array(9); solarSys[0] = "Mercury"; solarSys[1] = "Venus"; solarSys[2] = "Earth"; solarSys[3] = "Mars"; solarSys[4] = "Jupiter"; solarSys[5] = "Saturn"; solarSys[6] = "Uranus"; solarSys[7] = "Neptune"; solarSys[8] - "Pluto"; Такой способ заполнения массива несколько утомителен при написании кода, однако последующий доступ к информации становится очень простым и унифицированным. onePlanet = solarSys[4]; // результат "Jupiter" Если известен желаемый порядок расположения данных (как в примере с массивом solarSys), можно воспользоваться более компактным способом создания массива. Вместо использования набора операторов присвоения (как в листинге 30.1) можно создать компактный массив, указав все данные в аргументах конструктора Array (). solarSys = new Array("Mercury","Venus","Earth","Mars","Jupiter", "Saturn",Uranus'\ "Neptune","Pluto"); Термин компактный массив означает, что данные размещаются в массиве подряд, начиная с позиции 0. В листинге 30.1 показан так называемый вертикальный набор данных. Каждый элемент содержит такой же тип данных, что и другие (название планеты), и их порядок следования совпадает с порядком расположения планет (по расстоянию от солнца). Расширенные возможности создания массивов в JavaScript JavaScript в браузерах NN4+ и Ш4+ поддерживает еще один способ создания компактного массива. Кроме того, в них исправлена ошибка, связанная со старым вариантом. Новый, более простой способ создания компактного массива не требует применения конструктора объекта Array. Вместо этого JavaScript воспринимает так называемое буквенное обозначение. Чтобы понять разницу, рассмотрим стандартный оператор с применением конструктора в NN3. solarSys = new Array("Mercury","Venus","Earth","Mars","Jupiter", "Saturn","Uranus","Neptune","Pluto");. JavaScript полностью поддерживает такой синтаксис, однако возможен вариант и с буквенной записью. solarSys = ["Mercury","Venus","Earth","Mars","Jupiter", "Saturn","Uranus","Neptune", "Pluto"]; Квадратные скобки эквивалентны вызову конструктора Array. Перед тем как использовать такой способ создания массива, нужно определить, для каких версий браузеров разрабатывается страница. Исправление ошибки обусловлено тем, как должен работать конструктор компактного массива, если в его аргументе указано значение 1 — new Array (1). В NN3 и IE4 JavaScript 926 Часть IV. Объекты языка JavaScript
ошибочно создает массив длиной 1 с неопределенным элементом. В NN4 и во всех последующих браузерах (Ш5+, NN6+, W3C) тот же оператор создает массив с одним элементом и размещает в нем некоторое значение. Удаление элементов массива Элементу массива всегда можно присвоить значение nul 1 или пустую строку, в результате чего произойдет очистка данных, занимающих этот элемент. Но полностью удалить элемент массива в NN4 и ГЕ4 позволяет только оператор delete. Удаление элемента массива делает соответствующее ему значение недоступным, однако не уменьшает длины. Рассмотрим следующую последовательность операторов. myArray.length // результат 5 delete myArray[2] myArray.length // результат 5 myArray[2] // результат неопределен Процесс удаления элемента массива не всегда освобождает память, в которой находились данные. Внутренний механизм интерпретатора JavaScript сам заботится об этом (подробнее см. оператор delete в главе 32). Современные браузеры поддерживают метод splice () массива» который позволяет удалить элемент (или набор элементов) массива. В результате выполнения длина массива автоматически изменяется. Этот метод рассмотрен далее в этой главе. Параллельные массивы Использование массива для хранения данных часто предполагает проверку сценарием наличия в нем определенного значения (например, можно убедиться, что информация, введенная пользователем в текстовое поле, доступна для обработки). Еще намного важнее оказывается (при нахождении элемента) получение информации в другом массиве. Один из подходов заключается в использовании двух или более параллельных (реляционных) массивов: элементы с одинаковыми индексами содержат связанную информацию. Рассмотрим три следующих массива. var regionalOffices = new Array("New York", "Chicago", "Houston", "Portland"); var regionalManagers = new Array("Shirley Smith", "Todd Gaston", "Leslie Jones", "Harold Zoot"); var regOfficeQuotas = new Array(300000, 250000, 350000, 225000); В данном случае предполагается, что Ширли Смит (Shirley Smith) является региональным менеджером офиса в Нью-Йорке; предельная норма выработки ее офиса составляет 300,000. В таком виде данные включены в документы. Возможно, они получены CGI-программой на сервере из базы данных SQL и вставлены в конструкторы массивов. Листинг 30.2 демонстрирует, как эти данные отображаются на странице в элементе select для поиска менеджера и значений выработки его офиса. Порядок элементов в списке select является не случайным: для удобства поиска порядок следования элементов во всех массивах совпадает. Поиск в листинге 30.2 осуществляет функция get Data (). Поскольку индексы опций в элементе select совпадают с индексами параллельных массивов, свойство selectedlndex элемента select обеспечивает удобный способ прямого обращения к нужным данным в разных массивах. > Глава 30. Объект Array 927
<html> <head> <title>Parallel Array Lookup</title> <script type="text/javascript"> // дата var regionalOffices = new Array("New York", "Chicago", "Houston", "Portland"); var regionalManagers = new Array("Shirley Smith", "Todd Gaston", "Leslie Jones", "Harold Zoot"); var regOfficeQuotas = new Array(300000, 250000, 350000, 225000); // просмотр в параллельных массивах function getData(form) { var i « form.offices.selectedIndex; form.manager .value = regionalManagers[i]; form.quota.value = regOfficeQuotas[i]; } </script> </head> <body onload="getData(document.officeData)"> <hl>Parallel Array Lookup</hl> <hr /> <form name="officeData"> <p>Select a regional office: <select name="offices" onchange="getData(this.form)"> <option>New York</option> <option>Chicago</option> <option>Houston</option> <option>Portland</option> </selectx/p> <p>The manager is: <input type="text" name="manager" size="35" /xbr /> The office quota is: <input ч type="text" name="quota" size="8" /></p> </form> </body> </html> С другой стороны, если содержимое, которое нужно найти, введено пользователем в текстовое поле, в цикле необходимо провести поиск в одном из массивов и найти индекс совпадающего элемента. Листинг 30.3 представляет собой вариант листинга 30.2, но вместо элемента select для ввода названия региона используется текстовое поле. Предположив, что пользователи правильно указали регион (что не всегда правда), новая версия функции getData () в листинге 30.3 проводит действия, больше похожие на поиск: нахождение соответствия в одном массиве и отображение результатов из параллельных массивов. Цикл for итеративно просматривает все элементы массива regionalOf f ices. Условный оператор if сравнивает введенное значение и текущий элемент массива (преобразовав оба значения к верхнему регистру). После нахождения соответствия цикл for прерывается (при этом переменная i будет содержать индекс нужного элемента). За пределами цикла for другой условный оператор if проверяет, не достигло ли значение индекса длины массива (это значит, что совпадения не найдено). Лишь в том случае, когда i указывает на какой-либо элемент массива, сценарий получает значения элементов (с тем же индексом) из двух других массивов. 928 Часть IV. Объекты языка JavaScript
<html> <head> <title>Parallel Array Lookup II</title> <script type="text/javascript"> // данные var regionalOffices = new Array("New York", "Chicago", "Houston", "Portland"); var regionalManagers = new Array("Shirley Smith", "Todd Gaston", "Leslie Jones", "Harold Zoot"); var regOfficeQuotas = new Array(300000, 250000, 350000, 225000); // просмотр в параллельных массивах function getData(form) { // копирование содержимого текстового поля var inputText = form.officelnp.value; // просмотр всех записей массива regionalOffices for (var i = 0; i < regionalOffices.length; i++) { // сравнение версий в верхнем регистре с записями // в массиве regionalOffices if (inputText.toUpperCase О == regionalOffices[i].toUpperCase()) { // если найдено совпадение, то выход из цикла break; } } // проверка не превышения счетчиком i максимального индекса if (i < regionalOffices.length) { // вывод соответствующих записей параллельных массивов form.manager.value = regionalManagers[i]; form.quota.value = regOfficeQuotas[i]; } else { //в цикле не найдено совпадений // очистка всех предыдущих значений form.manager.value = ""; form.quota.value = ""; // вывод совета пользователю alert("No match found for " + inputText + "."); , > </script> </head> <body> <hl>Parallel Array Lookup II</hl> <hr /> <form name="officeData"> <p>Enter a regional office: <input type="text" name= "officelnp" size=*"35" /> <input type= "button" value="Search" onclick="getData(this.form)" /></p> <p>The manager is: <input type="text" name="manager" size="35" /xbr /> The office quota is: <input type="text" name="quota" size="8" /></p> </form> </body> </html> Глава 30. Объект Array 929
Многомерные массивы Альтернативой параллельным могут служить многомерные массивы. Несмотря на то, что массивы JavaScript являются одномерными, можно создать одномерный массив массивов или объектов. Логически правильнее создать массив определенных объектов, так как последние позволяют без особых проблем обращаться к своим свойствам, делая ссылки на данные из многомерных массивов более понятными при чтении кода (создание пользовательских объектов обсуждается в главе 33). Используя данные из предыдущего примера, представленная далее последовательность операторов создает конструктор объекта для каждой "записи данных". Каждому элементу основного массива присваивается новый объект. // Конструктор пользовательского объекта function officeRecord(city, manager, quota){ this.city = city; this.manager = manager; this.quota = quota; } // Создание основного массива var regionalOffices = new Array (); // Заполнение массива объектами regionalOffices [0] = new officeRecord("New York", "Shirley Smith", 300000); regionalOffices[1] = new officeRecord("Chicago", "Todd Gaston", 250000); regionalOffices[2]. = new officeRecord("Houston", "Leslie Jones", 50000); regionalOffices [3] = new officeRecord("Portland", "Harold Zoot", 225000); Функция-конструктор объекта (officeRecordO) присваивает значения аргументов свойствам объекта. Поэтому для доступа к данным в массиве используется, во-первых, запись массива, указывающая на нужный элемент, и, во-вторых, обращение к имени свойства объекта. var eastOfficeManager = regionalOffices[0].manager; Индекс в таком массиве может быть не только числовым, но и строковым. regionalOffices["east"] = new officeRecord("New York", "Shirley Smith", 300000); Тогда доступ к элементу выглядит следующим образом. var eastOfficeManager = regionalOffices["east"].manager; Если вы привыкли работать с обычными многоуровневыми массивами (в других языках программирования), то можете воспользоваться массивом массивов. // Создание нового основного массива var regionalOf f ices = new Array О; // Заполнение его массивами regionalOffices [0] = new ArrayC'New York", "Shirley Smith", 300000); regionalOffices[1] = new Array("Chicago", "Todd Gaston", 250000); regionalOffices [2] = new Array("Houston", "Leslie Jones", 350000); regionalOffices[3] = new Array("Portland", "Harold Zoot", 225000); Для краткости можно применить сокращенную запись. // Создание нового основного массива var regionalOffices = [ ["New York", "Shirley Smith", 300000], ["Chicago", "Todd Gaston", 250000], 830 Часть IV. Объекты языка JavaScript
["Houston", "Leslie Jones", 350000], ["Portland", "Harold Zoot", 225000] ]; Обращение к элементу данных в массиве массивов требует применения двойной ссылки. Например, для получения имени менеджера из офиса в Хьюстоне используется следующий синтаксис. var HoustonMgr = regionalOffices[2][1]; Первый индекс в квадратных скобках соответствует внешнему массиву (regionalOf f ices), а второй — массиву, заданному ссылкой regionalOf f ices [2]. Свойства объекта Array constructor См. строка. constructor (глава 27). length Значение: целочисленное Чтение/Запис Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Свойство length настоящего объекта массива содержит количество элементов в массиве. Элемент может содержать любой тип значений в JavaScript, включая null. Если в 10-м элементе массива содержится значение, а остальные равны null, то длина равна 10. Обратите внимание на следующее: поскольку индекс массива начинается с нуля, индекс последней ячейки на единицу меньше длины массива. Поэтому таким свойством удобно пользоваться для добавления к массиву нового элемента. myArray [myArray. length] = значениеДобавляемогоЭлемента; Универсальной функции необязательно знать конкретное значение индекса, чтобы добавить новый элемент. prototype Значение: переменная или функция Чтение/Запис Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safaril+ В JavaScript объект массива содержит набор методов и свойство length— элементы, присущие всем объектам массивов. Свойство prototype позволяет сценарию добавить новые свойства или методы всем массивам, созданным в загруженном документе. Свойство prototype можно изменить в любом отдельно взятом объекте. Пример Чтобы продемонстрировать применение свойства prototype, в листинге 30.4 указывается одно и то же свойство prototype для всех массивов объектов, созданных из статического объекта Array. Когда в сценарии создаются новые массивы (копии объекта Array так же, как и объекты даты, являются копиями объекта Date), это свойство становится их частью автоматически. В одном из массивов, с, прототип свойства sponsor изменяется. Однако это изменение не влияет на прототипы свойств других объектов Array. Поэтому созданный далее массив d включает исходное значение свойства sponsor. Глава 30. Объект Array 831
<html> <head> <title>Array prototypes</title> <script type="text/javascript"> // добавление прототипа во все объекты Array Array.prototype.sponsor = "DG"; a = new Array(5); b = new Array(5); с = new Array(5); // замена свойства prototype для одного 'экземпляра' с.sponsor = "JS"; // выбор исходного свойства prototype d = new Array(5); </script> </head> <body> <h2> <script type="text/javascript"> document.write("Array a is brought to you by: " + • a.sponsor + "<br />"); document.write("Array b is brought to you by: " + b.sponsor + "<br />"); document.write("Array с is brought to you by: " + c.sponsor + "<br />"); document.write("Array d is brought to you by: " + d.sponsor + "<br />"); </script> </h2> </body> </html> Прототипу можно присвоить свойства или функции. В последнем случае функция определяется обычным для JavaScript образом. После этого ее имя присваивается свойству prototype. function newFunc(paraml) { // операторы } Array.prototype.newMethod = newFunc; // здесь скобки не используются Для вызова функции (теперь она является новым временным методом объекта Array) используется обычный синтаксис метода объекта. Например, вызов прототипа метода show- Coverlmage () для десятого элемента массива CDCollection выглядит следующим образом. CDCol1ееtion.showCoverImage(9); Параметром функции является индекс (он используется, к примеру, для доступа к изображению, URL которого содержится в свойстве объекта, хранимого в десятом элементе массива). Методы объекта Array Если информация сохранена в массиве, JavaScript позволяет воспользоваться несколькими методами, определенными для управления данными. Эти методы, принадлежащие создаваемым объектам массивов, со временем изменяются, поэтому нужно следить, какие из них поддерживаются конкретной версией браузера. 932 Часть IV. Объекты языка JavaScript
массив.concat(масснв2) Возвращаемое значение: объект массива. Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Метод массив. concat () позволяет объединить два объекта, создав третий объект массива. Это действие никак не влияет на содержимое или поведение двух исходных массивов. Для конкатенации массивов первый указывается слева от точки, а второй — в аргументе метода. var arrayl = new Array(1,2,3); , var array2 = new Array("a","b","c"); var аггауЗ = array1.concat(array2); // результат: массив со значениями 1,2,3,"а","b","с" Если элементом массива является строка или число (но не объект строки или числа), значения из исходных массивов копируются в новый. После этого любая связь значений из нового массива с исходными прерывается. Если элементами исходного массива являются ссылки на объекты (любого типа), JavaScript копирует в новый массив только ссылки. Поэтому внесение изменений в одном из массивов влияет на объект, а значит, это отражается в обоих массивах. Пример Листинг 30.5 несколько сложнее предыдущих, однако в нем продемонстрировано сразу два принципа: использование метода массив. concat () для объединения массива и принятие решения об обработке или не обработке данных массива в зависимости от их типа. Страница, отображаемая в окне браузера после загрузки кода листинга 30.5, показана на рис. ЗОЛ. ЕЕ FHa Edh View Favor*** Totlt ©**- о & а<й|р^^^ь'#— ф|£~& в -ош1з**: arrayOne arrayTwo array Throe jJerry I Elaine ) Kramer : Ross ; Rache1 ; [object] Enter new value for array Three[0]:JerTy Current arrayOnefO] щ Jerry j Current ■rrayThree[03 »УвПУ j * V iJerry jElaine ! Kramer IRoaa IRachel ^[object] ^ 1 1 J ш jUwiaiiMiiiaiiabyJ textObj untried to arrayTwo[2][Phpebe Enter new value for anwyTh£eej5|: [Phoebe Current arrayTwo[2]. value ujPhoebe Current arrayThree[5]. value issPhpebt l^aiiifi^iwThfftfilki^ii [ 11 [Ami tftM-frkibMdi :&i*nUe>&+,-U: btbxii!i$heb*L*bbi&a>ii*l.*. Puc. 30А. Ссылка на объект сохраняется и в объединенном массиве После загрузки документа вы можете ознакомиться со всеми тремя массивами. Первый массив содержит только строковые значения, второй— два строковых значений и одну Глава 30. Объект Array 933
ссылку на объект формы (текстовое поле original). Сценарий этой страницы не только создает эти массивы, но и объединяет их с помощью метода массив. concat (); полученный результат отображается в третьем массиве. Чтобы отобразить содержимое массивов в виде столбцов данных, используется метод массив. j о in (), который преобразует элементы массива в текстовую строку, разделенную символами возврата каретки. Две группы текстовых полей в нижней части страницы помогают разобраться с текущим содержимым массивов. Если в первом разделе вы введете значение элемента arrayThree [0], то оно заменит строковое значение в объединенном массиве. Поскольку это значение никак не связано с данными исходных двух массивов, то в них соответствующий элемент изменен не будет. Воспользовавшись методом showArray (), вы сможете удостовериться в том, что изменился только третий массив, но никак не первый или второй. Более сложной является взаимосвязь между объектами. Ссылка на первое текстовое поле второго раздела назначается третьему элементу второго массива (а г ray Two). После объединения массивов эта же ссылка отображается последней в третьем массиве. Если ввести значение для последнего элемента третьего массива в соответствующем поле страницы, то это приведет к обратным изменениям в исходных объектах, в том числе и в объекте arrayTwo [2]. При этом список элементов массива не изменится, поскольку в них по-прежнему указана ссылка на тот же объект. <html> <head> <title>Array Concatenation</title> <script type="text/javascript"> // глобальные переменные var arrayOne, arrayTwo, arrayThree, textObj; // инициализация после загрузки для доступа // к текстовым объектам формы function initialize() { var form = document.forms[0] ; textObj = form.original; arrayOne = new Array("Jerry", "Elaine","Kramer"); arrayTwo = new Array("Ross", "Rachel",textObj); arrayThree = arrayOne.concat(arrayTwo); updatel(form); update2(form); showArrays(); } // отображение текущих значений всех трех массивов function showArrays() { var form = document.forms[0]; form.arrayl.value = arrayOne.join("\n"); form.array2.value = arrayTwo.join("\n"); form.аггауЗ.value = arrayThree.join("\n"); } // изменение значения первого элемента массива Array Three function updatel(form) { arrayThree [0] « form, source Lvalue; form.resultl.value = arrayOne[0]; form.result2.value = arrayThree[0]; showArrays(); } // изменение значения свойства объекта, i ■ ■ ■ ' 934 Часть IV. Объекты языка JavaScript
// указывающего на Array Three function update2(form) { arrayThree[5].value = form.source2.value; form.result3.value = arrayTwo[2].value; form.result4.value = arrayThree[5].value; showArrays(); } </script> </head> <body onload="initialize()"> <form> <table> <tr> <th>arrayOne</th> <th>arrayTwo</th> <th>arrayThree</th> </tr> <tr> <td><textarea name="arrayl" cols="25" rows="6"> </textareax/td> <tdxtextarea name="array2" cols=H25" rows="6"> </textareax/td> <tdxtextarea name="array3" cols=H25" rows="6"> </textareax/td> </tr> </table> <b>Enter new value for arrayThree[0]:</bxinput type="text" name="soureel" value="Jerry" /> <input type="button" value= "Change arrayThree[0]" onclick="updatel(this.form)" /> <br /> Current arrayOne[0] is:<input type="text" name="result 1" /xbr /> Current arrayThree [0] is :<input type="text" name="result2" /xbr /xhr /> textObj assigned to arrayTwo[2]:<input type="text" name= "original" onfocus="this.blur () " /xbr /> <b>Enter new value for arrayThree [5] :</bxinput type=Mtext" name="source2" value="Phoebe" /> <input type="button" value="Change arrayThree[5].value" onclick="update2 (this.form) " /xbr /> Current arrayTwo[2].value is:<input type="text" name="result3" /xbr /> Current arrayThree[5].value is:<input type="text" name="result4" /> <p><input type="button" value="Reset" onclick="location.reload()" /></p> </form> </body> </html> См. также: метод ма ссив. j о in (). , array, join (разделитель) Возвращаемое значение: строка элементов массива, разделенных значением разделитель. Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safaril+ Данные массива в их естественной форме нельзя просмотреть. Также нельзя и передать их CGI-программе на сервер. Чтобы перейти от дискретных элементов массива к строке, применяется Глава Ш Объект Array 935
метод массив. join (). Без него решение такой задачи требовало бы применения множественных операций над строками. Единственным аргументом метода является строка из одного или нескольких символов, действующих как разделители элементов. Например, чтобы перечислить элементы массива через запятую, используется следующий оператор. var arrayText = myArray.j oin(" ,"); Вызов метода не изменяет исходный массив. Поэтому результат метода необходимо присвоить переменной или, например, свойству элемента формы. Пример Сценарий листинга 30.6 преобразует массив названий планет в текстовую строку. На странице отображается поле, в котором можно ввести разделитель элементов массива в текстовой строке. <html> <head> <title>Array. join (.) </title> cscript type="text/javascript"> solarSys = new Array(9); solarSys[0] solarSys[1] solarSys[2] solarSys[3] solarSys[4] solarSys[5] solarSys[6] solarSys[7] solarSys[8] "Mercury"; "Venus"; "Earth"; "Mars"; "Jupiter"; "Saturn"; "Uranus"; "Neptune"; "Pluto"; // объединение элементов массива в строку function convert(form) { var delimiter = form.delim.value; form.output.value = unescape(solarSys.join(delimiter)); } </script> </head> <body> <h2>Converting arrays to strings</h2> This document contains an array of planets in our solar system. <hr /> <form> Enter a string to act as a delimiter between entries: <input type="text" name="delim" values"," size="5" /> <pxinput type= "button" value= "Display as String" onelick="convert(this.form)" /> <input type="reset" /> <textarea name="output" rows="4" cols="40" wrap= "virtual" ></textareax/p> </form> </body> </html> См. также: метод строка. split (). Часть IV. Объекты языка JavaScript
массив.pop() массив.push(зиачениеИлиОбъект) массив.shift() массив. unshi £ t (зиачениеИлиОбъект) Возвращаемое значение: значение одного элемента массива. Совместимость: Winffi5.5+, МасШ-, NN4+, Mozl+, Safaril+ Понятие стека хорошо знакомо опытным программистам, особенно тем, кто работал с языком ассемблера на уровне процессора. Даже если вы не программировали стек, то наверняка встречали такой принцип в жизни. Классическую аналогию представляет собой стопка подносов в кафетерии. Когда она создается, каждый поднос кладется поверх предыдущего. Посетитель забирает самый верхний поднос (т.е. последний, добавленный в стек). Таким образом, последний элемент, добавленный в стек, извлекается из него первым. JavaScript в браузерах NN4+ и Ш5.5+ позволяет превратить массив в подобный стек. К такому стеку с любого конца (посредством одного из методов) можно добавить или извлечь данные. Часто используется следующая терминология: добавлять (push) и извлекать (pop). В результате добавления в массив методом push () значение размещается в последнем элементе массива. При вызове метода массив.pop.() последний элемент извлекается из массива и возвращается методом. При этом он удаляется, а длина массива уменьшается на единицу. Рассмотрим, что происходит с массивом, используемым как стек в приведенной ниже последовательности операторов. var source = new Array("Homer","Marge","Bart","Lisa","Maggie"); var stack = new Array(); // стек = -<пустой> stack.push(source[0]); // стек = "Homer" stack.push(source[2]); // стек = "Homer","Bart" var Simpsonl = stack.pop(); // стек = "Homer" ; Simpsonl = "Bart" var Simpson2 = stack.pop(); // стек = <пустой> ; Simpson2 = "Homer" Кроме методов push () и pop (), обрабатывающих конечный элемент массива, существуют и два метода, которые управляют начальным элементом. Их имена не настолько описательны, как push () и pop (). Для вставки значения в начале массива применяется метод массив, unshi ft (), для его удаления— массив.shift (). Конечно же, эти методы не обязательно использовать в паре. Можно поместить один набор значений в конец массива методом push (), а другой — удалить из начала методом shift (). Выбор метода зависит от поставленной задачи. См. также: метод массив. concat (), массив. slice (). массив.reverse() Возвращаемое значение: массив элементов в обратном порядке. Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ В некоторых ситуациях можно изменить порядок следования элементов в массиве. Вы вправе создать цикл, обрабатывающий массив в порядке убывания индекса, однако CGI-программе на сервере может понадобиться массив, упорядоченный не так, как это выполняет сценарий. JavaScript позволяет изменить порядок элементов в массиве на противоположный: последний элемент становится первым (индекс 0). Помните, что такая операция изменяет исходный массив, а не его копию, хотя сам метод и возвращает копию реверсивного массива. Только перезагрузка документа восстанавливает исходный порядок. Глава Ш Объект Array 937
Пример Листинг 30.7 представляет собой улучшенную версию листинга 30.6. Страница документа, представленного этим листингом, содержит дополнительные кнопку и функцию, которые изменяют порядок следования элементов в массиве и отображают полученный результат в текстовой области. <html> <head> <title>Array.reverse 0 </title> <script type="text/javascriptM> solarSys = new Array(9); solarSys[0] solarSys[1] solarSys[2] solarSys[3] solarSys[4] solarSys[5] solarSys[6] solarSys[7] solarSys[8] "Mercury"; "Venus"; "Earth"; "Mars"; "Jupiter"; "Saturn"; "Uranus"; "Neptune"; "Pluto"; // отображение массива, находящегося в памяти function showAsIs(form) { var delimiter * form. delim.value- form, output.value = unescape(solarSys.join(delimiter)); } // изменение направления массива и представление его строкой function reverselt(form) { var delimiter = form.delim.value; solarSys.reverse(); // изменение направления массива form.output.value « unescape(solarSys.join(delimiter)); } </script> </head> <body> <h2>Reversing array element order</h2> This document contains an array of planets in our solar system. <hr /> <form> Enter a string to act as a delimiter between entries: <input type="text" name="delim" value="," size="5" /> <pxinput type= "button" value= "Array as-is" onclick="showAsIs(this.form)" /> <input type="button" value*"Reverse the array" onclick="reverselt(this.form)" /> <input type^"reset" /> <input type="button" value="Reload" onclick="self.location.reload()" /> <textarea name="output" rows="4" cols="60"> </textareax/p> </form> </body> </html> См. также: метод массив. sort (). Часть /V. Объекты языка JavaScript
массив.slice(начИндехс [, конИндекс]) Возвращаемое значение: массив. Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Метод массив. slice () (подобный по своему действию одноименному строковому методу) позволяет извлекать из массива набор соседних элементов. Полученный сегмент становится новым объектом массива. Значения и объекты из исходного массива ведут себя так же, как, например, массивы, созданные методом массив. concat (). Один аргумент является обязательным — индекс начального извлекаемого элемента. Если второй аргумент не указан, то метод обрабатывает массив до конца. В ином случае он извлекает все элементы до указанного индекса, исключая последний. Например, для получения имен планет, соседних с Землей, используется следующий код. var solarSys = new Array("Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus", "Neptune","Pluto"); var nearby = solarSys.slice(1,4); // результат: новый массив "Venus", "Earth", "Mars" См. также: методы массив. splice (), строка. slice (). массив.sort([функцияСравнения]) Возвращаемое значение: массив значений, упорядоченных с помощью функции compareFunction. Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Сортировка массивов является мощным средством JavaScript, однако она сложна в использовании, если вы не знакомы с ее особенностями. Она становится возможной исключительно благодаря использованию методу сортировки по любому критерию. Для записей, состоящих из строк, таким критерием может быть алфавитный порядок или их длина. Для числовых элементов, как правило, критерием является числовой порядок. Вначале рассмотрим, как сортирует элементы сам метод массив. sort () (без использования функции, выполняющей сравнение). Если аргумент не указан, JavaScript преобразует элементы массива в строки, затем он выполнит сортировку строк. При этом используются ASCII-коды символов. Это значит, что числа, например, сортируются как строки, а не как числовые значения. Это существенно влияет на конечный результат, содержащий числовые данные: значение 201 считается меньшим 88, поскольку в процессе сортировки при определении порядка сравниваются первые символы строк ("2" и "8"). Таким образом, в чистом виде метод массив. sort (У подходит только для простой сортировки строк. К счастью, этот метод можно усовершенствовать, добавив функцию, которая выполнит сравнение элементов массива. Ей передается два элемента массива (метод массив. sort () не пересылает все значения массива этой функции для сортировки). Функция сортировки показывает методу sort (), какой из элементов предшествует другому. Для этого она возвращает значение определенного знака. Предположим, что функция сравнивает два значения, а и Ь. Типы возвращаемых методу sort () значений представлены в табл. 30.1. Возвращаемое значение Описание <0 0 >0 ь следует после а Порядок а и ь не меняется а следует после ь *. Глава 30. Объект Array 939
Рассмотрим следующий пример. myArray = new Array(12, 5, 2 00, 80); function compare(a,b) { return a — b; } myArray.sort(compare) Массив содержит четыре числовых значения. Для правильной их сортировки (в порядке возрастания) определена функция сравнения с именем compare (), которую вызывает метод sort (). Обратите внимание, что, в отличие от обычного вызова функций, аргументом метода sort () является указатель на нее (т.е. синтаксис исключает использование скобок). При вызове функции compare () JavaScript автоматически посылает ей два аргумента, проводя сравнение каждого элемента со всеми остальными. При каждом вызове compare () JavaScript передает переменным а и b два элемента массива. В предыдущем примере функция возвращает разность а и Ь. Если а больше Ь, метод sort () получает положительное значение, т.е. а должно следовать после b (индекс элемента а должен быть больше индекса Ь). Поэтому b в итоге может оказаться элементом myArray [0], а а — элементом с большим индексом. Если же а меньше Ь, тогда возвращаемое значение отрицательно и метод sort () делает индекс элемента а меньшим, чем Ь. Сравнения с помощью внешней функции иногда оказываются довольно долгими (это зависит от типов значений, сохраняемых в массивах). Например, вместо числовых сравнений, которые были только что показаны, можно выполнить и строковые сравнения. Следующая функция сортирует строки по последнему символу (в алфавитном порядке). function compare(a,b) { // последний символ строки массива var aComp = a.charAt(a.length — 1); var bComp = b.charAt(b.length — 1) ; if (aComp < bComp) return -1; if (aComp > bComp) return 1; return 0 } Вначале функция извлекает последний символ из каждой строки, переданной ей. Затем их ASCII-коды сравниваются, и функция возвращает значение, которое указывает методу sort (), что необходимо делать со сравниваемыми элементами массива. Когда элементами массива являются объекты, их можно отсортировать даже по свойствам. Если аргументы а и b функции сортировки являются ссылками на элементы массива, тогда их можно использовать для доступа к свойствам объектов. Например, пусть в массиве содержатся объекты с информацией о служащих, и одним из свойств объекта является возраст, представленный в строковой форме. Тогда массив можно отсортировать, основываясь на числовом эквиваленте свойства age, применяя следующую функцию сравнения. function compare(a,b) { return parselnt(a.age) — parselnt(b.age) Сортировка массивов, в отличие от подобных процедур в других языках сценариев, не является однозначной. "Неоднозначность" заключается в том, что последующие процедуры сортировки одного и того же массива некумулятивные. Кроме того, помните, что сортировка изменяет исходный массив. Если его требуется сохранить в исходном состоянии, создайте копию массива или перезагрузите страницу. Если элемент массива равен null, метод размещает его в конце массива. Сортировка массивов в JavaScript представляет собой очень удобное средство с большими возможностями. Поэтому часто при загрузке страницы, содержащей данные XML, создаются 940 Часть IV. Объекты языка JavaScript
копии этих данных в виде массивов объектов JavaScript (см. главу 57). Преобразование XML- данных в массивы JavaScript позволяет выполнить сортировку данных с помощью более простых и быстрых методов, чем собственные процедуры сортировки элементов XML. Пример В листинге 30.8 приведены примеры сортировки массива строковых значений (рис. 30.2). Четыре кнопки на этой странице выполняют разные процедуры сортировки. В трех из них применяются функции сравнения. Каждая из упомянутых функции использует собственный алгоритм сравнения данных. ЕЁ £Ш Fit* Edit Vtow Fmrita» T««to H#t» / ' • ' • ©*** о«a а вир*»*<jfr"p--•#■•* 4&\&*& в *d ятя'*** " Sorting array elements Tins document contains an array of planets in our solar system. Click on a button to sort the array: jNep^ne;Ee^;Selum;Pluto;JuprterVenue;Uranu8;Mar8;Mercury ^ ^A6fea»i^«»T» ■t^iiir&tii^.^j&^&'r*^ Рис. 30.2. Сортировка массива названий планет по последней букве <html> <head> <title>Array.sort()</title> <script type="text/j avascript"> solarSys = new Array(9); solarSys[0] solarSys[1] solarSys[2] solarSys[3] solarSys[4] solarSys[5] solarSys[6] solarSys[7] solarSys[8] "Mercury" "Venus"; "Earth"; "Mars"; "Jupiter"; "Saturn"; "Uranus"; "Neptune"; "Pluto"; // функции сравнения Глава 30. Объект Array 941
function comparel(a,b) { // обращение алфавитного порядка if (a > b) return -1; if (b > a) return 1; return 0; function compare2(a,b) { // последний символ в именах планет var aComp = a.charAt(a.length - 1); var bComp = b.charAt(b.length - 1) ; if (aComp < bComp) return -1; if (aComp > bComp) return 1; return 0; function сотрагеЗ(a,b) { // длина имен планет return a.length - b.length; } // сортировка и отображение массивов function sortIt(form, compFunc) { var delimiter = ";"; if (compFunc == null) { solarSys.sort(); } else { solarSys.sort(compFunc); } // вывод результата в поле form.output.value = unescape(solarSys.join(delimiter)); } </script> </head> <body onload="document.forms[0].output.value = unescape (solarSys. j oin (';'))"> <h2>Sorting array elements</h2> This document contains an array of planets in our solar system. <hr /> <form> Click on a button to sort the array: <pxinput type= "button" value="Alphabetical A-Z" onclick="sortIt(this.form)" /> <input type="button" value="Alphabetical Z-A" onclick= "sortlt(this.form,comparel)" /> <input types"button" value="Last Character" onclick="sortIt(this.form,compare2)" /> <input type="button" value="Name Length" onclicks"sortlt(this.form,сотрагеЗ)" /> <input type="button" value="Reload Original" onclicks"self.location.reloadO" /> <input types»text" name*"output" size="62" /></p> </form> </body> * </html> См, также: метод array. reverse (). 942 Часть IV. Объекты языка JavaScript
Как отмечается в главе 42, массивы часто являются результатом выполнения методов объектов регулярных выражений (например, массив строковых фрагментов, совпадающих с указанным значением). Эти специальные массивы обладают набором собственных свойств, позволяющих сценарию анализировать найденную информацию. В остальном массивы, полученные в результате обработки регулярных выражений, ведут себя привычным образом. массив.splice(начИядекс , количество[, элем! [, злем2 [, ... элемМ] ] ]) Возвращаемое значение: массив. Совместимость: WinIE5.5+, MacIE-, NN4+, Mozl+, Safaril+ Если требуется удалить несколько элементов из середины массива, решение этой задачи облегчает метод массив, splice О . В ином случае потребовалось бы создать новый массив из определенных частей исходного. Первым из двух обязательных параметров является индекс первого удаляемого элемента, вторым— общее число таких элементов. Удаление элементов влияет на длину всего массива. Метод splice () возвращает массив, содержащий все удаленные элементы. Метод splice () можно применять и для замены элементов массива. Дополнительные аргументы (начиная с третьего) позволяют указать данные, которые будут вставлены в массив вместо удаленных элементов. Каждый добавляемый элемент может принадлежать к любому типу данных JavaScript, а их количество не обязательно должно быть равным числу удаленных элементов. Укажите второй параметр равным нулю и вы сможете воспользоваться методом splice () для вставки одного или нескольких значений в любом месте массива. Пример Приложение The Evaluator позволяет изучить метод массив. splice (). Для начала создайте массив, содержащий последовательность чисел. а = new Array(1,2,3,4/5) Далее удалите из него средние три элемента и замените их одной строкой. a.spliced, 3, "two/three/four") В области результатов отображается строковая версия массива из трех элементов, возвращаемая1 этим методом. Чтобы ознакомиться с текущим содержимым массива, введите в верхнем текстовом поле приложения значение а. Чтобы вернуть в массив исходные числовые значения, воспользуйтесь следующим оператором. a.spliced, 1, 2, 3, 4) Теперь массив а вновь обретает пять числовых значений. См. также: метод массив. slice (). массив.toLocaleString() Возвращаемое значение: строка. Совместимость: WinIE5.5+, MacIE-, NN6+, Mozl+, Safari 1+ / Haatwntv Глава 30. Объект Array 943
массив.toString() Возвращаемое значение: строка. Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ Метод массив.toLocaleString() и более ранний, поддерживаемый большим числом браузеров — массив. toString (), позволяют вывести содержимое массива в строковой форме. Браузеры используют метод toString () по-своему при отображении массива в текстовом окнелВ этом случае элементы массива разделены запятой. Точный алгоритм преобразования, используемый методом toLocaleString (), зависит от версии браузера. Поэтому неудивительно, что Ш и NN несколько отличаются в определенных деталях (это происходит даже для версии U.S. English браузеров и операционной системы). Например, если массив содержит целые числа, метод toLocaleString () в Ш5.5+ возвращает список значений, разделенных запятой и пробелом и отформатированных с двумя знаками после запятой (как цены в долларах и центах). В NN6+ этот же метод возвращает обычные целые числа, также разделенные запятой и пробелом. Если массив необходимо преобразовать в строку для других целей (например, данные в скрытом текстовом поле для передачи серверу или строка поиска, пересылаемая другой страницы), лучше воспользоваться методом массив .join (). Он предоставляет более надежный и гибкий способ управления символами-разделителями. Кроме того, результат будет одинаковым независимо от локализации. См. также: метод массив. j oin (). 944 Часть IV. Объекты языка JavaScript
Управляющие структуры и обработка исключительных ситуаций ак правило, утром человек встает, собирается, идет на работу, вечером возвращается, а когда темнеет, включает свет. Аналогичная закономерность прослеживается и при работе программы с момента ее запуска до завершения. Но в промежутке между утром и вечером — запуском и завершением, выполняется огромное количество крошечных шагов, однако не все действительно нужны. Время от времени, необходимо управлять происходящим, принимая решения или повторяя задачи до тех пор, пока работа не будет завершена. Управляющие структуры являются мощным средством осуществления подобных возможностей в JavaScript. Код управляющих структур подобен тому, что используется во многих языках программирования, особенно после его расширения в NN4 и Ш4. Принципы принятия решений и организации циклов практически одинаковы во всех задачах программирования. Существует и другой механизм программного управления — это обработка ошибок (или исключительных ситуаций), формально данный механизм описывается в 3-м издании стандарта ЕСМА-262. Для версии JavaScript, используемой в Ш5.5 и NN6, концепция обработки исключительных ситуаций является новой, но во многих других средах данная методика стала довольно популярной. Применение такой технологии в сценарии может значительно улучшить процесс исправления ошибок, вызванных неверно введенными пользователем данными либо сбоями в сети. к
Конструкции if и if...else Совместимость: Winffi3+, МасГЕЗ+, NN2+, Mozl+, Safaril+ В программах JavaScript часто возникают ситуации, в которых должно быть принято решение, основанное на текущих значениях переменных или свойств объекта.1 Одновременно можно получить только два результата в процессе принятия решения. Фактором, которым определяются дальнейшие операции программы, является некоторое выражение. Например, если человек входит ночью в дом, это выражение будет иметь следующий вид: "Слишком темно, без света ничего не видно". Если данное выражение истинно, вошедщий в комнату включает свет; если ложно, возвращается к исходной задаче. Простые решения Фрагмент программы JavaScript для данного вида простого решения всегда начинается с оператора if, после которого следует проверяемое условие и выражения, выполняемые, если указанное условие соблюдается. В JavaScript не используется оператор then (как в некоторых других языках); ключевое слово помещают в круглые скобки, а различные составляющие этой конструкции — в фигурные. Формальный синтаксис данной конструкции имеет такой вид. if (условие) { выражение, выполняемое при истинности условия ) Это означает, что если условие истинно, далее в программе выполняются операторы, указанные в фигурных скобках. Если ложно, программа продолжает выполнять операторы, следующие после закрывающей фигурной скобки (}). Если передвижение по дому описать с помощью языка сценариев, код программы будет выглядеть следующим образом. if (tooDark. == true){ найти выключатель включить свет } Если пользователь ранее не сталкивался с языками С или C++, использование двойного знака равенства может показаться странным. В следующей главе об этом операторе будет рассказываться более подробно, а пока необходимо знать, что он применяется для определения равенства элементов, указанных по обе его стороны. Другими словами, выражению условие конструкции if всегда должно соответствовать булево значение (true или false). Так как некоторые свойства объекта имеют булево значение, ссылки на них можно указывать в выражении условие. Иначе выражение условие будет состоять из двух значений, разделенных оператором сравнения: == (равно) или ! = (не равно). Рассмотрим реальный пример — фрагмент программы на JavaScript. В данную функцию подставляется объект формы, в котором содержится текстовый объект entry. function notTooHigh(form) { if (parselnt(form.entry.value) > 100) { alert("Sorry, the value you entered is too high. Try again."); return false; return true; } С помощью условия (в круглых скобках) содержимое поля проверяется на равенство строго определенному значению 100. Если введенное значение больше заданного, на экран выводится предупреждение, и в том месте сценария, где была вызвана данная функция, выражению возвращается значение false. Но если это значение меньше 100, все указанные операторы пропускаются, и функция возвращает значение true. 946 Часть IV. Объекты языка JavaScript
Условные выражения Во многих условных управляющих выражениях числовые значения сравниваются со специальными величинами — пустой строкой или null. При различных обстоятельствах используются разные сокращенные именования. В табл. 31.1 приведено подробное описание значений, которые можно указывать в выражении условия управляющей структуры в качестве истины или лжи (или равенства). Истина Ложь Непустая строка Пустая строка Ненулевое число О Непустое значение null Объект существует Объект не существует Свойство определено Неопределенное свойство Вместо расшифровывания эквивалентного выражения в условии с помощью значений, приведенных в таблице, можно просто указать проверяемое значение. Например, если переменная с именем myVal в конструкции if может принять значение null пустой строки или строкового значения для дальнейшей обработки, код программы можно записать в следующей форме. if (myVal){ // Обработка myVal } Все нулевые или пустые строки условия расцениваются как false, поэтому операторы, указанные внутри конструкции if, в данном примере выполняются только в том случае, когда значение myVal пригодно для обработки (т.е. существует). В этой книге данный механизм используется во всех ситуациях, когда необходимо определить поддержку объекта в иерархической структуре браузера. Например, следующий фрагмент программы выполняется только в том случае, если объект document имеет свойство массива images. i f (document.images) { // Обработка объектов изображения ) Составные решения Простую конструкцию if, описанную ранее, удобно использовать в случае, когда решение состоит в том, чтобы совершить небольшое отклонение в процедуре перед возвращением к главной задаче. Но не все решения, в программировании или в жизни, соответствуют данной ситуации. Для того чтобы задать два возможных варианта решений, в JavaScript в конструкцию if нужно добавить еще один компонент. Соответствующий синтаксис выглядит следующим образом. if {условие) { операторы, выполняемые при справедливости утверждения } else { операторы, выполняемые при ложности утверждения } Глава 31. Управляющие структуры и обработка исключительных ситуаций 947
Добавляя в конструкцию if оператор else, пользователь определяет действия сценария в том случае, когда условие имеет ложное значение. Операторы, выполняемые при справедливости и ложности утверждения, не обязательно должны быть сбалансированы: один оператор может состоять из одной строки программы, другой — из сотни. Но когда завершается цикл любой из этих ветвей, выполнение программы продолжается с последней закрывающей фигурной скобки. Для того чтобы продемонстрировать, насколько удобна данная конструкция, приведем пример. В этом фрагменте сценария вычисляется количество дней в феврале. Решение основывается на том, является ли этот год високосным (для этого он должен быть кратным четырем, т.е. его арифметический модуль должен быть равен нулю — см. главу 32). var howMany = 0; var theYear - 2002; if (theYear % 4 == 0) { howMany = 29; } else { howMany = 2 8; } В данном случае для задания количества дней переменной howMany выполняется только одна из двух возможных частей сценария, если не использовать оператор else, как в следующем примере. var howMany = 0; var theYear = 2002; if (theYear % 4 == 0) { howMany = 29; } howMany = 28; Значение переменной всегда будет равным 28, иногда после кратковременного приравнивания 29. Дня того чтобы избежать подобной ситуации, используют конструкцию else. Вложенные выражения if... else Разработка составного решения требует особого внимания к логической схеме решений. В сценарии необходимо предусмотреть любые возможные виды условий и соответствующие им ситуации развития действий. Потребность в сложных конструкциях исчезает с появлением оператора switch в NN4+ и NN4+ (этот оператор описывается далее в этой главе). Однако все еще могут возникать ситуации, когда необходимо будет использовать составное решение, состоящее из серии вложенных конструкций if. . .else. Если программист не пользуется текстовыми редакторами кода, где удобно форматировать код приложения и проверять его синтаксис (например, закрытие фигурных скобок), ему придется контролировать весь синтаксис самому. Кроме того, в сообщениях об ошибках, выводимых средствами JavaScript, при возникновении таковых (см. главу 45) не указывается номер строки с ошибкой, а только определенная область сценария, вызвавшая неполадки. Не забывайте еще одну важную особенность вложенных выражение if.. .else, хотя это касается только ранних версий JavaScript, предшествующих 1.2. В этих версиях не существует возможности выхода из вложенной части конструкции. Поэтому при создании сложной структуры необходимо предусмотреть все возможные варианты. Только тогда вы будете уверенны, что для каждого набора условий выполняется соответствующий оператор. Конечно, после этого желательно протестировать программу (см. главу 45). В листинге 31.1 демонстрируются многократно вложенные конструкции if... else; при выполнении программы на экране отображается простой интерфейс для решения сложной /» Назам*й$ 948 Часть IV. Объекты языка JavaScript
проблемы. Пользователя просят ввести один из трех символов: А, В или С. Для каждого из следующих условий в сценарии обрабатывается соответствующее сообщение. Пользователь не вводит значение. Пользователь вводит А. Пользователь вводит В. Пользователь вводит С. Пользователь вводит собственное значение. <html> <head> <titlex/title> <script type="text/javascript"> function testLetter(form){ inpVal = form.entry.value; // назначение сокращенного // имени переменной if (inpVal 1= "") { // продолжение, если запись не пустая... if (inpVal == "A") { // Это "А"? alert("Thanks for the A."); } else if (inpVal == "B") { // Нет. Это "В"? alert("Thanks for the B."); } else if (inpVal == "C") { // Нет. Это "С"? alert("Thanks for the C."); } else { // Нет. Ни одно из них alert("Sorry, wrong letter or case."); } } else { // значение пустое; пропуск всего выше alert("You did not enter anything."); } } </script> </head> <body> <form onsubmit="return false"> Please enter A, B, or C: <input type="text" name="entry" onchange="testLetter(this.form)" /> </form> </body> </html> В каждом случае выполняются только те операторы, которые соответствуют определенному условию, даже если для определения соответствия требуется обработать несколько отдельных запросов. Совсем не обязательно выходить из вложенной конструкции, так как, при нахождении соблюдаемого условия соответствующий оператор выполняется, а остальные просто игнорируются. Даже если создание вложенной конструкции, например, подобной приведенной в листинге 31.1, не вызывает трудностей, необходимо следить за тем, чтобы каждой открывающей скобке соответствовала закрывающая. Рекомендуется использовать следующий прием: после введения открывающей скобки сразу же введите и закрывающую. Обычно после ввода открывающей скобки,* дважды нажимают <Enter> (первый раз — для создания строки, в которую в дальнейшем будет вводиться следующий оператор, а второй — для ввода закрывающей скобки). Используйте Глава 31. Управляющие структуры и обработка исключительных ситуаций- 949
<Tab>, если необходимо в одной строке задать и открывающую, и закрывающую скобки. Чтобы вставить еще несколько строк, переместите вниз введенные ранее закрывающие скобки. Если придерживаться данной методики оформления кода программы, то после завершения процесса программирования все закрывающие скобки будут расположены с определенными отступам, даже если их пришлось передвинуть с начального места на несколько строк вниз. Для чего используется форматирование? Форматирование кода совершенно не сказывается на правильности работы сценария в JavaScript. Отступы в конструкциях if и дальнейшие отступы ее операторов выполняются для наглядности и удобного восприятия кода. Подобное форматирование является, своего рода договоренностью между большинством программистов. Поскольку код вводится в текстовом редакторе, используйте клавишу <ТаЬ> для визуального распределения строк по разным уровням. При загрузке документов HTML со сценариями символы табуляции браузером не воспринимаются, а следовательно, не отображаются на странице. Условные выражения Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safaril+ Так как конструкции принятия решений в JavaScript уже были описаны в данной главе, теперь самое время рассказать об особенном выражении, которое можно использовать вместо управляющей структуры if. . .else для задания обычного типа решения. В этой конструкции переменной можно назначить одно из двух значений, в зависимости от поставленного условия. Структура данного условного выражения имеет следующий вид. переменная = (условие) ? значение! : значение2; Это выражение означает следующее: если булев результат оператора условие является истинным, переменной назначается значение!; в противном случае этой переменной назначается значение2. Подобно другим конструкциям, условное выражение также необходимо помещать в круглые скобки. Вопросительный знак является ключевым, как и двоеточие, которым разделены два возможных значения. Данное условное выражение, хоть и не особо понятно, является очень компактным. Сравните следующий вариант конструкции if. . .else var collectorStatus; if (CDCount > 500) { collectorStatus = "fanatic"; } else { collectorStatus = "normal"; с условным выражением, используемым для решения той же самой задачи var collectorStatus = (CDCount > 500) ? "fanatic" : "normal"; В последнем варианте для выполнения тех же операций используется гораздо меньше строк (хотя внутренняя обработка полностью идентична обработке конструкции if. . . else). Конечно, если в решении содержится более одного оператора задания значения переменной, предпочтительнее использовать конструкцию if. . .else или switch. Однако помните: если необходимо выполнить бинарное действие, например, установить в сценарии флажок истинности или ложности, в этой ситуации рекомендуется использовать именно условное выражение. 950 Часть IV. Объекты языка JavaScript
Циклы повторения операций (for) Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Как можно было убедиться, просмотрев примеры предыдущих глав, возможность циклического просмотра каждого элемента массива или опции элемента формы довольно часто используются во многих сценариях JavaScript. Наверное, наиболее типичная операция для данной конструкции — это поиск в свойствах нескольких элементов определенных значений, например, определение выбранного переключателя. Для повторения выполнения одних и тех же действий в JavaScript используется специальный цикл for, названный так от ключевого слова, с которого и начинается данная структура. Два других цикла, while и do-while, описываются ниже. Как уже отмечалось, с помощью цикла for в JavaScript можно повторять набор операций любое количество раз, используя при этом счетчик цикла (хотя это и необязательно). Синтаксис данной конструкции имеет следующей вид. for ( [начальное выражение] ; [условие] ; [выражение обновления] ) { операторы } Три выражения в круглых скобках (параметры оператора for) являются ключевыми при выполнении данного цикла. Начальное выражение выполняется только один раз при запуске цикла. Наиболее часто в начальном выражении указывают имя и начальное значение переменной, используемой в цикле. Подобным образом, при указании в операторе var, объявляется и имя переменной, и ее начальное значение (как правило, 0 или 1). var i = 0; Имя переменной может быть любым, но наиболее часто используют символ i, сокращенно от index. Конечно, если пользователь предпочитает слово counter (счетчик) или другое, напоминающее ему о значении этой переменной, можно использовать любые другие имена. Помните, что это выражение в цикле for выполняется только один раз. Второе выражение представляет собой условие, подобно соответствующему оператору в конструкции if (см. ранее в этой главе). Если переменная цикла уже установлена в начальном выражении, в операторе условие указывают конечное значение счетчика цикла. Поэтому наиболее часто в этом выражении выполняется сравнение переменной-счетчика и некоторого установленного значения (т.е. осуществляется проверка, является ли значение счетчика цикла меньше максимального разрешенного значения). Если это условие не соблюдается в самом начале, указанные в теле цикла операции не выполняются. Если же условие соблюдается, то выполнение каждый раз начинается с "вершины" цикла, и каждый раз проверяется условие для определения текущего результата выражения. Если значение счетчика увеличивается с каждой новой итерацией цикла, в конечном счете оно превысит значение, указанное в операторе условие, и данный оператор перестанет соответствовать условию. Когда это произойдет, выполнение цикла for полностью прекратится. Заключительный оператор— выражение обновления, выполняется в конце каждой итерации цикла, после запуска всех операторов, определенных в конструкции for. Причем в этом выражении можно снова использовать ту же переменную-счетчик. Если необходимо увеличить ее значение на единицу при каждой итерации цикла (это называется приращением значения), используйте специальный оператор JavaScript ++, который добавляется к имени переменной. Именно так объясняются загадочные символы i++, используемые во всех циклах for. Но не думайте, что можно увеличить значение переменной только на единицу. Его можно увеличивать на любое число (и даже уменьшать с помощью соответствующего оператора). Глава 31. Управляющие структуры и обработка исключительных ситуаций 951
Используя всю изложенную выше информацию, рассмотрим синтаксис данного фрагмента программы, в котором показан обычный способ применения счетчика цикла i. // Приращение переменной цикла for (var i = минЗначение; i < = максЗначение; i++) { операторы ) II Уменьшение переменной цикла for (var i = максЗначение; i > = минЗначение; i--) { операторы } Вначале переменная i инициализируется со значением, заданным в переменной minValue. Затем i сравнивается с MaxValue. Если значение i меньше или равно maxValue, обработка продолжается в теле цикла. В конце цикла выполняется выражение обновления. В предыдущем примере значение i увеличивалось на 1. Если i инициализируется как 0, то при первом прохождении цикла для выполнения операторов используется переменная со значением 0. В следующий раз переменная уже имеет значение 1. Как, наверное, можно было заметить из приведенного синтаксиса, все параметры оператора for необязательны. Например, значением счетчика цикла, основанном на данных, которые используются в обработке, можно управлять в выражениях, выполняемых внутри этого цикла. Поэтому выражение обновления может дублироваться с операцией, определенной в самом цикле. Однако рекомендуется использовать все три параметра (хотя бы до тех пор, пока у вас не появится абсолютная уверенность в своих силах и принципах работы этого типа цикла). Если, например, пропустить выражение условия и не указать в программе оператор выхода из цикла, этот цикл может стать бесконечным, что отрицательно скажется на применении данного приложения. Использование счетчика цикла Счетчик i (имя может быть любое) является довольно мощным инструментом управления данными внутри повторяющегося цикла. Ниже приведен пример классической функции JavaScript, в которой создается массив, совместимый с NN2; при его инициализации каждому элементу присваивается значение 0. // Инициализация массива п элементов function MakeArray(n) { this.length = n; for (var i = 1; i <= n; i++) { this[i] = 0; } return this; } В данной функции счетчик цикла i инициализирован со значением 1. Так как необходимо создать массив пустых элементов (со значением 0), начинайте с элемента, индекс которого равен 1 (нулевой используется в свойстве length) в предыдущей строке. В условном выражении цикл продолжает выполняться до тех пор, пока значение счетчика меньше либо равно числу создаваемых элементов (п). После каждой итерации цикла значение счетчика увеличивается на 1. Во вложенном операторе, который выполняется в самом цикле, переменная i используется для установки значения индекса в выражении присвоения. this[i] = 0; В первой итерации цикла выражение имеет такой вид. this[l] = 0; 952 Часть IV. Объекты языка JavaScript
В следующей итерации оно несколько изменяется. this[2] = 0; И так далее, пока все элементы не будут созданы и им не будет присвоено значение 0. Теперь просмотрите листинг 30.2 HTML-страницы, на которой пользователь выбирает региональный офис из списка select (с его помощью запускается сценарий поиска имени менеджера и нормы продаж, установленные в этом регионе.) Так как названия региональных офисов хранятся в массиве, можно изменить сценарий так, чтобы опции элемента select считывались из массива. В случае, когда изменится структура региональных офисов, вам потребуется выполнить только одно исправление в массиве, а не переписывать всю страницу. Еще раз приведем этот массив, который создается во время загрузки страницы. var regionalOffices = new Array ("New-York", "Chicago", "Houston", "Portland"); Сценарий формы HTML может использоваться для динамического генерирования списка select следующим образом. <script type="text/javaScript"> var elem = ""; // начало назначения следующей части страницы и формы elem += "<p>Select a regional office: "; elem += "<select name='offices' onchange='getData(this.form)•>"; // создание списка опций из массива названий офисов for (var i = 0; i < regionalOffices.length; i++) { elem += "<option"; // дескрипторы для опций if (i == 0) { // предварительный выбор первого элемента списка elem += " selected=»selected'"; } elem += ">" + regionalOffices[i]; } elem += "</selectx/p>"; // закрытие дескриптора выбранного элемента document.write(elem); // вывод элемента на страницу </script> Обратите внимание на один важный момент, касающийся условного оператора цикла for: в JavaScript свойство length извлекается из массива и используется как конечное значение счетчика цикла. С точки зрения кода программы, а также стилистической структуры, этот метод очень удобен для программного определения значений. Если компания добавляет новый региональный офис, то при внесении нового элемента в "базу данных" массива во всем коде программы автоматически выполняются соответствующие изменения, включая появление более длинного всплывающего меню. Также обратите внимание на то, что в условном выражении используется оператор "меньше" (<) — это означает, что при изменении индексов массива, начинающихся с нуля, максимальное значение, которое можно использовать в данном цикле, на единицу больше индекса последнего элемента в массиве. Это нужно учитывать, так как переменная счетчика (i) используется как индекс элементов массива regionalOffices, и при каждой итерации цикла считывается строка, содержащаяся в каждом из этих элементов. Счетчик также используется для определения первой опции, после чего выполняется небольшое отклонение от основной программы (с помощью конструкции if), в результате которого в определение первой опции вставляется атрибут selected. Счетчик в цикле for часто влияет на проектируемую структуру данных, например двухмерные массивы (см. главу 30), которые используются как базы данных. Всегда помните о механизме изменения счетчика в цикле при написании сценариев JavaScript, благодаря которым совокупность данных, внедряемых в документы, объединяется в строго упорядоченные структуры. Глава 31. Управляющие структуры и обработка исключительных ситуаций 953
Выход из цикла Некоторые операторы цикла продолжают свою работу до тех пор, пока не будет выполнено некоторое условие. В этом условии указано значение счетчика, при достижении которого работа цикла прекращается. Общая картина действий такова: в цикле обрабатывается массив данных и при этом осуществляется поиск некоторого элемента, соответствующего установленному критерию. Проверка критерия проводится с помощью расположенной внутри цикла конструкции if. Если этот критерий выполняется, происходит выход из цикла; работа сценария будет продолжена с выполнения следующих операторов в основном блоке кода. Для выхода из цикла используйте оператор break. Ниже показан способ применения оператора break в цикле for. for (var i = 0; i < array.length; i++) { if (array[i].property == magicValue) { * операции над элементом array[i] break >J Команда break для компилятора JavaScript означает выход из последнего обрабатываемого цикла for (в случае, если несколько циклов вложены друг в друга). Выполнение сценария продолжается с оператора, следующего за закрывающей фигурной скобкой этого цикла. Переменное значение i остается тем же, что и в момент завершения цикла, т.е. в дальнейшем его можно использовать в сценарии для обращения, например, к тому же элементу массива. В главе 22 используется подобная конструкция. В листинге 22.8 представлен набор переключателей, в атрибутах value которых содержатся четыре полных имени. В данной функции с помощью цикла for определяется выбранная пользователем опция, а значение индекса соответствующего элемента после выхода из цикла используется для вывода на экран необходимого сообщения. Описанная функция приведена в листинге 31.2. function fullName(form) { for (var i = 0; i < form.stooges.length; i++) { if (form.stooges[1].checked) { break; alert("You chose " + form.stooges[i] .value + "."); } В этой ситуации выход из цикла for применялся не только для того, чтобы прервать работу цикла, так как значение счетчика (оставшееся таким, каким оно было в момент остановки) затем используется при вызове различных свойств вне данного цикла. Оператор break имеет дополнительные преимущества при совместном использовании с новым свойством label элементов управления (См. далее в этой главе) Управление циклом с помощью оператора continue Еще одна возможность цикла for состоит возможности пропускать выполнение вложенных операторов для выполняемого условия. Другими словами, поскольку в цикле происходит постоянное повторение операторов и выполнение выражений с учетом текущего значения 954 Часть IV. Объекты языка JavaScript
счетчика, можно установить определенное значение счетчика, для которого операторы выполняться не будут. Для этого необходимо использовать вложенную конструкцию if, с помощью которой и будет осуществляться проверка этого значения. Если условие выполняется, в компилятор JavaScript передается указание немедленно пропустить остальную часть цикла, выполнить оператор обновления, а затем продолжать работу цикла сначала (пропуская условное выражение в параметрах цикла for). Для того чтобы разобраться в работе данной сложной конструкции, создайте специальный пример, в котором выполнение операций цикла будет пропускаться при достижении переменной "несчастливого" значения 13. for (var i = 0; i <= 20; i++) { if (i == 13) { continue; } опера торы В этом примере часть цикла операторы выполняется для всех значений, кроме 13. С помощью оператора continue выполнение цикла "переносится" в область оператора i++, но при этом значение i увеличивается только при следующей итерации цикла. Если используется несколько вложенных циклов for, оператор continue применяется к тому циклу for, в котором "сработала" конструкция if. Оператор continue усовершенствован в NN4+ и Ш4+; в него добавлены новые возможности по взаимодействию со свойством 1аЫе элементов управления. (См. далее в данной главе). Цикл while Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Цикл for — не единственный вид циклов в JavaScript. Кроме него, существует оператор while; он работает несколько иначе. В данном случае не проводится изменение значения счетчика, выполнение тела цикла while зависит от заданного в нем условия. Если это условие изначально не выполняется, цикл не используется вообще. Базовый синтаксис цикла while приведен ниже. while {условие) { операторы } Выражение условие подобно тому, которое уже встречалось в конструкции if и в среднем параметре цикла for. При использовании цикла while вначале следует убедиться в том, что в программе выполняется некоторое условие (установленное в true). Тогда в цикле будут выполняться соответствующие операции, воздействующие на это условие, до тех пор, пока его значение не станет false. В этом случае произойдет выход из цикла; работа сценария продолжится с операторов, следующих за закрывающей фигурной скобкой цикла. Если значения, проверяемые в операторе условие, в цикле whi 1е никак не изменяются, то этот цикл становится бесконечным. В одном сценарии можно использовать циклы как for, так и while. Например, в листинге 31.3 (на компакт-диске) цикл for листинга 31.2 преобразован в цикл while. function full Name(form) { var i = 0; while (!form.stooges[i].checked) { Глава 31. Управляющие структуры и обработка исключительных ситуаций 955
i++; } alert("You chose " + form.stooges[i].value + "."); } Всегда помните о следующем: если условие цикла while зависит от значения счетчика этого цикла, то необходимо инициализировать счетчик заранее и управлять его значением в пределах цикла. При необходимости можно использовать управляющие операторы break и continue, которые работают так же, как и в цикле for. По причине того, что в for и while счетчики и условия обрабатываются по-разному, будьте предельно осторожны (выполните неоднократное тестирование), применяя в этих циклах операторы break и continue. Не существует определенных правил для определения того, когда и какую конструкцию цикла следует использовать. Обычно циклы while применяют тогда, когда данные или объект, предназначенный для обработки, уже является частью сценария. Другими словами, значения, рассматриваемые в условии, или счетчики циклов (если они необходимы) в этом сценарии уже инициализированы. Если требуется несколько раз подряд вызвать свойства объекта или элементы массива для получения определенных данных и использования их позже в сценарии, выберите цикл for. Существует еще одна особенность использования цикла for, в котором программист должен вначале объявить переменную 1. Некоторые программисты объявляют (или инициализируют, если начальные значения известны) все переменные в начальных операторах сценария или функций. Именно поэтому в сценариях встречается много операторов var. Например, если в функции используется только один цикл for, не произойдет ничего страшного, если счетчик i будет объявлен или инициализирован в начальной части выражения этого цикла (см. предыдущие разделы). Но если в функции используется несколько циклов for, в которых переменная i применяется многократно (т.е. циклы выполняются независимо друг от друга), то ее можно объявить один раз в начале функции и просто назначать новое начальное значение в каждой конструкции. Цикл do-while Совместимость: WinIE4+, МасГ£4+, NN2+, Mozl+, Safari 1+ В JavaScript существует еще одна конструкция цикла, так называемого do-while. Синтаксис цикла этой конструкции имеет следующий вид. do { операторы } while {условие) Циклы while и do-while существенно отличаются. В конструкции do-while операторы выполняются минимум один раз перед тем, как условие будет проверено; а в цикле while, если условие проверено и не соблюдается (false), операторы не выполняются никогда. Используйте цикл do-while, если вы полностью уверены в том, что операторы будут выполнены хотя бы один раз. Если при первом же прохождении цикла условие может не соблюдаться, используйте цикл while. Во многих случаях обе конструкции взаимозаменяемы, правда do-while совместима не со всеми браузерами, поддерживающими сценарии. ОСА 900 Часть IV. Объекты языка JavaScript
Просмотр свойств (цикл for-in) Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safaril+ В JavaScript существует некоторая разновидность цикла for — так называемый цикл for- in, с помощью которого можно получить имя и значение любого свойства объекта, расположенного в данный момент в памяти браузера. Синтаксис выглядит следующим образом. for {переменная in объект) { операторы } В параметре объект указывают ссылку на объект, а не его строковое имя. Компилятор JavaScript сам генерирует ссылку на объект, если имя объекта не заключено в кавычки, например window или document. Используя переменную переменная, можно создать специальный сценарий и с его помощью вывести на экран любые свойства любого объекта. В листинге 31.4 приведен пример страницы, в сценарии которой содержится вспомогательная функция. Данную функцию можно применять в своих документах HTML на стадии разработки и отладки документов в сценариях JavaScript. В этом примере исследуется текущий объект window, его свойства выводятся на страницу. <html> <head> <titlex/title> <script type="text/javascript"> function showProps(obj,objName) { var result = ""; for (var i in obj) { result += objName + "." + i + " =" + obj[i] + "<br />"; } return result; } </script> </head> <body> <b>Here are the properties of the current window:</b> <P> <script type="text/javascript"> document.write(showProps(window, "window")); </script> ч </p> </body> </html> При отладке можно указать, чтобы результаты отображались в диалоговом окне предупреждения. Для этого замените дескриптор HTML <br> символом возврата каретки \п, отобразив в диалоговом окне предупреждения правильно отформатированный текст. Данную функцию можно вызвать из любого места сценария, опустив и ссылку на объект, и строку для нее. Таким образом, можно идентифицировать объект после выведения результатов в диалоговом окне предупреждения. Функция showProps () может показаться знакомой, так как она очень похожа на приложение The Evaluator (см. главу 13). В главе 45 рассказано о том, как внедрить функциональные возможности The Evaluator в конструкцию страницы, чтобы можно было просмотреть значения свойств при отладке сценариев. Глава 31. Управляющие структуры и обработка исключительных ситуаций 957
Оператор with Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ C помощью оператора with можно объявить любое количество объектов, которые будут использоваться в сценарии. Таким образом, не стоит указывать полные формальные адреса, чтобы обратиться к свойствам или вызвать методы одного и того же объекта. Синтаксис выглядит следующим образом. with (объект) { опера торы } Ссылка на объект представляет собой ссылку на любой допустимый объект, в настоящее время содержащийся в памяти браузера. В главе 28 описываются объекты Math и приводится соответствующий пример. Используя некоторые операторы Math в конструкции with, можно вызвать свойства и методы без указания объектной части ссылки на каждое свойство и метод. Преимущество структуры with состоит в том, что при ее использовании операторы управления объектами становятся более доступными для чтения и понимания. Обратите внимание на приведенную ниже функцию, в которой многократно вызывается один и тот же объект (различные его свойства). function seeColor(form) { newColor = (form.colorsList.options[form.colorsList. selectedlndex].text); return newColor; } Используя структуру with, можно значительно сократить это длинное выражение. function seeColor(form) { with (form.colorsList) { newColor = (options[selectedlndex].text) } return newColor; } Когда компилятор JavaScript сталкивается с неизвестным идентификатором внутри оператора with, то осуществляется попытка формирования ссылки вне объекта, а параметрами ссылки являются текущий объект и этот неизвестный идентификатор. Однако нельзя вкладывать оператор with в другой оператор with (для другого объекта). Например, в предыдущем примере нельзя поместить оператор with (colorsList) внутри with (form) и при этом рассчитывать на то, что будет создана ссылка на основе этих двух имен объектов. Помните, что при использовании данного оператора могут возникать ошибки в формировании самих операторов сценария (так как ссылки в JavaScript генерируются искусственно). Единичное использование данной конструкции существенно не отобразится на работе программы, но если она используется в цикле и выполняется несколько раз, в большинстве случаев скорость обработки данных снизится. Маркированные операторы Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safaril+ Использование многократно вложенных циклов может затруднять поиск конечного условия, если оно выполняется глубоко внутри вложенных блоков. Проблема состоит в том, что с помощью операторов break или continue можно обратиться только к наиболее "близкому" уровню циклов. Поэтому даже при выходе из внутреннего цикла, внешний(е) 958 Часть IV. Объекты языка JavaScript
цикл(ы) продолжает(ют) выполняться. Если необходимо выйти из цикла после выполнения указанного условия, используйте оператор return, действие которого аналогично командам выхода в других языках. Если же после выполнения условия необходимо провести некоторую дальнейшую обработку данных в этой функции, в NN4+ и Ш4+ предусмотрено средство, с помощью которого в JavaScript блокам операторов можно назначать соответствующие маркеры. В этом случае операторы break и continue можно применять для маркированных блоков, а не для блоков, в которых содержится данный оператор. Маркер может быть любым идентификатором (именем, которое начинается с символа буквы; в нем не должно содержаться никаких пробелов или знаков препинания, кроме символа подчеркивания), сопровождаемым двоеточием. Также маркер должен предшествовать блоку логически выполняющихся операторов — if., .else или конструкции цикла. Соответствующий синтаксис выглядит следующим образом. Маркер: операторы Для того чтобы применить операторы break или continue к определенной группе операций, к каждому оператору добавьте маркер (как некоторый параметр). break Маркер continue Маркер В листинге 31.5 описаны две версии одной и той же вложенной конструкции цикла, демонстрирующие, насколько удобен данный метод при правильном использовании. В каждой версии в цикле используются различные переменные индекса, изменяемые до тех пор, пока их значения не будут соответствовать переменным, установленным вне цикла. Когда подобное условие соблюдается (совпадение найдено), работа вложенной конструкции цикла прерывается, и обработка продолжается позже. Чтобы помочь вам разобраться в обработке данных, которая происходит в цикле, на экране в текстовой области будут выведены ее промежуточные и конечные результаты. Если совпадение найдено, в варианте без маркеров, выполняется обычный оператор break. Следовательно происходит выход из вложенного цикла, но внешний цикл продолжает работать со следующей итерации. К тому времени, когда будет выполнена вся циклическая конструкция (просмотрены все значения), произойдет немало лишних операций. Кроме того, значения переменных счетчика будут увеличены, так как циклы продолжают выполняться еще несколько раз после нахождения совпадения. В варианте с использованием маркеров выход из вложенного цикла осуществляется из маркированного внешнего цикла, если совпадение найдено. Таким образом обрабатывается гораздо меньшее количество строк программы, а переменные счетчика цикла соответствуют необходимым значениям. В листинге 31.5 проводится эксперимент — оператор break заменяется оператором continue. Теперь проанализируйте два результата, отображенных в текстовой области, и найдите отличия этих двух версий программы. <html> <head> <title>Breaking Out of Nested Labeled Loops</title> <script type="text/javascript"> var targetA = 2; var targetB = 2; var range = 5; function runl() { var out = document.forms[0].output; Глава 31. Управляющие структуры и обработка исключительных ситуаций 959
out.value = "Running WITHOUT labeled break\n"; for (var i = 0; i <= range; i++) { out.value += "Outer loop #" + i + "\n"; for (var j =0; j <= range; j++) { out.value += " Inner loop #" + j + "\n"; if (i == targetA && j == targetB) { out.value += "**BREAKING OUT OF INNER LOOP**\n"; break; } } } out.value += "After looping, i="+i + ", j = " + j + "\n"; } function run2() { var out = document.forms[0].output; out.value = "Running WITH labeled break\n"; outerLoop: for (var i = 0; i <= range; i++) { out. value += "Outer loop #" + i + "\n"; innerLoop: for (var j =0; j <= range; j++) { out.value += " Inner loop #" + j + "\n"; if (i == targetA && j == targetB) { out.value += "**BREAKING OUT OF OUTER LOOP**\n"; break outerLoop; } } } out.value += "After looping, i = " + i + ", j=" +j+ "\n"; } </script> </head> <body> <hl>Breaking Out of Nested Labeled Loops</hl> <hr /> <p>Look in the Results field for traces of these button scripts:</p> <form> <p><input type="button" value="Execute WITHOUT Label" onclick="runl()" /></p> <pxinput type = "button" value="Execute WITH Label" onclick="run2()" /></p> <p>Results:</p> <textarea name="output" rows="43" cols="60"></textarea> </form> </body> :/html> Оператор switch Совместимость: WinIE4+, МасШ4+, NN4+, Mozl+, Safari 1+ В некоторых случаях двоичных значений (истина или ложь) не достаточно для обработки всех операций в сценарии. Свойству object или значению variable может соответствовать любое из нескольких значений, причем для выполнения каждого из них требуется 960 Часть IV. Объекты языка JavaScript
отдельный способ. Раньше для осуществления данной задачи необходимо было использовать несколько конструкций if. . . else. Но чем больше условий необходимо проверить, тем менее эффективной будет программа, так как каждое условие проверяется обязательно. Кроме того, блочная структура операторов и скобок может быть очень громоздкой и запутанной. Во многих языках программирования для решения этой задачи используется специальная управляющая структура, которую разработчики JavaScript добавили в NN4+ и ГЕ4+. Работает этот оператор аналогично подобному оператору в Java и С, в нем используются ключевые слова вариантов выбора и переключателя. Основное преимущество данного оператора — это возможность создания любого количество вариантов ветвления, основанных на значении некоторого выражения. В начале структуры это выражение идентифицируют, а затем для каждого варианта выполнения задают маркер, соответствующий получаемому значению. Синтаксис оператора switch выглядит следующим образом. switch {выражение) { case вариант!: операторы [break] case вариант2: опера торы [break] [default: операторы] } Параметр выражение оператора switch может принимать любое строковое или числовое значение. Варианты значений не заключаются в кавычки, даже если они содержат строковые выражения. Обратите внимание на то, что оператор break в данном случае использовать необязательно. При указании этого оператора проверка остальных вариантов не осуществляется. Еще одна опция — оператор default, который срабатывает в том случае, когда значение выражения не соответствует ни одному из вариантов case. Если в конструкции всегда справедлив хотя бы один вариант, то последнюю часть конструкции не используют. В листинге 31.6 приведен пример программы, в которой используется оператор switch. На странице представлено два отдельных массива различных категорий изделия. Каждое изделие имеет название и цену, значения которых сохранены в соответствующем массиве. Названия изделий выводятся на экран с помощью списка select. Когда пользователь выбирает изделие, в соответствующем массиве сценария выполняется поиск этого изделия, и его цена выводится на экран. Ценность данного приложения состоит в том, что для каждого изделия в списке заданы определенные значения. На экране пользователь видит название изделия, а в атрибуте value каждого дескриптора <option> определяется соответствующий этому изделию элемент массива. Также значение представляет собой выражение, которое используется для определения нужного варианта. Обратите внимание, что маркер назначается для всей конструкции switch. Таким образом, многократно вложенные циклы каждого варианта будут полностью выходить из конструкции switch (с помощью маркированного оператора break) каждый раз, когда будет найдено выражение, соответствующее заданному в условии. Эту программу можно дополнить любыми элементами массивов изделий, указав дополнительные операторы case для расширения структуры. <html> <head> <title>Switch Statement and Labeled Break</title> <script type="text/javascript"> Глава 31. Управляющие структуры и обработка исключительных ситуаций 961
// создание двух массивов товаров, // эмулирующих таблицы базы данных function product(name, price) { this.name = name; this.price = price; } var ICs = new Array(); ICs[0] = new product("Septium 900MHz","$149"); ICs[l] = new product("Septium Pro 1.0GHz","$249"); ICs[2] = new product("Octium BFD 750MHz","$329"); var snacks = new Array(); snacks[0] = new product("Rays Potato Chips","$1.79"); snacks[l] = new product("Cheezey-ettes","$1.59"); snacks [2] = new product("Tortilla Flats","$2.29"); // просмотр 'таблицы', связанной с товаром function getPrice(selector) { var chipName = selector.options[selector.selectedlndex].text; var outField = document.forms[0].cost; master: switch(selector.options[selector.selectedlndex].value) { case "ICs": for (var i = 0; i < ICs.length; i++) { if (ICs[i].name == chipName) { outField.value = ICs [i] .price; break master,- } } break; case "snacks": ' for (var i = 0; i < snacks.length; i++) { if (snacks[i].name == chipName) { outField.value = snacks[i].price; break master; } } break; default: outField.value = "Not Found"; } } </script> </head> <body> <b>Branching with the switch Statement</b> <hr /> Select a chip for lookup in the chip price tables: <form> Chip:<select name="chips" onchange="getPrice(this)"> <optionx/option> <option value="ICs">Septium 900MHz</option> <option value="ICs">Septium Pro 1.0GHz</option> <option value="ICs">Octium BFD 750MHz</option> <option value="snacks">Rays Potato Chips</option> <option value="snacks">Cheezey-ettes</option> <option value="snacks">Tortilla Flats</option> <option>Poker Chipset</option> </select>&nbsp; Price:<input type="text" 962 Часть IV. Объекты языка JavaScript
name="cost" size="10" /> </form> </body> </html> Обработка исключительных ситуаций Тема обработки исключительных ситуаций является относительно новой в JavaScript, хотя она и описана в 3-м издании стандарта ЕСМА-262. Частично данный механизм осуществлен в Ш5, а его более полная версия — в Ш6 и NN6, а также Mozilla и Safari. Исключительные ситуации и ошибки Любой программист, создавая сценарии, помнит об ошибках в JavaScript — это могут быть как синтаксические ошибки в коде программы, так и ошибки при выполнении программы, которые происходят во время обработки информации компилятором. Идеально, когда в программе определяется факт происхождения ошибки, и она обрабатывается настолько "аккуратно", насколько это возможно. При таком "самоизлечении" можно предотвратить потерю данных (это не так уж сложно в Web-приложениях), и уберечь пользователей от появления на экране сообщений об ошибках. В главе 16 уже упоминалось об обработчике событий onerror (и свойстве window, onerror), с помощью которых в сценариях задается определенный уровень контроля над ошибками во время выполнения программы. Этот механизм управления событиями используется на глобальном уровне (т.е. в объекте window); в нем обрабатывается каждая ошибка, которая происходит на странице. Этот обработчик событий применялся прежде всего, как последняя защита от вывода пользователю любого сообщения об ошибках, и представлял действенный способ обработки исключительных ситуаций. Термин исключение, как правило, означает что-то необычное или аварийно происходящее. Это определение, казалось бы, имеет мало общего со словом "ошибка". Но в языках программирования эти два слова обладают близкими значениями. Разница между ними зависит прежде всего от принимаемой точки зрения. Рассмотрите простой сценарий, в котором вычисляется произведение чисел, вводимых пользователем в два текстовых поля на странице. Как и предполагается, результаты выводятся в третьем текстовом поле. Если в сценарии не предусматривается никакой проверки на правильность введенных данных, то будет проводиться попытка умножения любых значений, введенных в текстовые поля. Если пользователь вводит два числа, сценарий выполняется нормально, даже при том, что значения свойств value двух текстовых полей являются строковыми; в строковых значениях содержатся числа', которые могут быть преобразованы в числовой тип данных, пригодный для умножения. В данной ситуации результат умножения двух чисел вычисляется и выводится на экран. Что же произойдет, если пользователь введет в одно из текстовых полей символ? Если в сценарии не осуществляется никакой проверки правильности введенных данных, на этот вопрос в JavaScript будет дан такой ответ: результат умножения — постоянная NaN (не является числом). Это загадочное NaN указывает на то, что произошла некоторая ошибка. Тут можно обвинять компьютер, а можно и самого себя. Сценарий был разработан в расчете на тех пользователей, которые никогда не делают ошибок при вводе (намеренно или нет). Однако пользователи допускают ошибки, поэтому предусмотреть вводимые пользователем данные, которые не подходят для выполнения операций над ними (также исключения из правил, с которыми пытается работать написанная программа) — прямая обязанность программиста. Необходимо разработать дополнительный Глава 31. Управляющие структуры и обработка исключительных ситуаций 963
фрагмент программы, в котором будут обрабатываться исключительные ситуации, что предоставит пользователю возможность исправить введенные данные. В этом дополнительном фрагменте программы обрабатываются нежелательные и ошибочные данные, введенные пользователем. Итак, в словарях JavaScript и объектной модели документа W3C термины исключения и ошибки взаимосвязаны; они используются при обработке исключительных ситуаций. Как вы вскоре убедитесь, в исключительной ситуации создается объект ошибки, в котором содержится информация об этой ситуации. Поэтому можете смело говорить об исключениях и ошибках как об одном и том же. Механизм обработки исключительных ситуаций Начинающим разработчикам JavaScript (или любой другой среды программирования) зачастую трудно сразу понять, как все описанное выше применяется в браузерах. Механизм загрузки страницы, создания объектных моделей и вызов функций в сценарии с помощью обработчиков событий (или получателей событий в терминологии W3C DOM) довольно прост. Но большинство действий происходит на втором плане. Например, объект события, который автоматически генерируется при каждом действии события (см. главу 25), кажется, находится "непонятно где", в то время как функции обработчика вызываются со всеми данными, описывающими это событие. После завершения обработки, объект события исчезает, от него не остается ничего, даже воспоминаний. В браузерах, предназначенных для обработки исключительных ситуаций, имеется большее количество необходимого для этого "материала", который задействуется в сценарии при возникновении ошибки. Так как каждый программист наверняка хотя бы один раз сталкивался с ошибкой сценария, то механизм обработки исключительных ситуаций, встроенный в браузеры, ему в определенной степени знаком. При возникновении подобной ошибки браузер создает в выделенной ему памяти объект ошибки, в свойствах которого и содержится информация об этой ошибке. Конкретные данные (которые описываются ниже в этой главе) изменяются в зависимости от версии браузера, но та информация, которая выводится в специальном окне, является результатом стандартной обработки браузером исключительных ситуаций или ошибок. Поскольку браузеры устаревают, их разработчики делают все возможное для предупреждения и исправления ошибок в сценариях. Например, в NN4+ ошибки выводятся на отдельной консоли JavaScript (которую можно вызвать, если ввести в поле адреса javascript: или щелкнуть на значке ошибки в строке состояния, а также выбрав соответствующую команду в меню Tools (Сервис) NN6 или Mozilla). Пользователи в последнем случае увидят сообщение о возникновении ошибки только в строке состояния. В Ш4+ для Windows строка состояния используется снова, поскольку в ее левом нижнем углу появляется соответствующий значок ошибки: при двойном щелчке на нем на экран выводится подробная информация об этой ошибке. В МасШ можно совсем отключить отображение сообщений об ошибках выполнения сценария. Safari же вообще не выводит сообщения об ошибках выполнения сценариев (см. главу 45). Истинная же обработка исключительных ситуаций — это нечто большее, чем просто вывод сообщения об ошибке. В результате обеспечивается единственный для сценариев способ принятия мер против получения неверных результатов. В идеале все ошибки выполнения программы должны пройти через этот механизм, что упрощает управление в нем исключительными ситуациями. Данный механизм также разработан для использования его в сценариях пользователя таким образом, что генерируемые ошибки прекрасно могут обрабатываться и в других частях программы. Другими словами, можно представить механизм обработки исключительных ситуаций как своего рода "обратный канал" взаимодействия одной части сценария с другой. Этот механизм построен на основе двух групп операторов приложений. Первая группа состоит из тройки try-catch-finally; вторая — из единственного оператора throw. 964 Часть IV. Объекты языка JavaScript
Использование конструкций try-catch-finally Назначение группы связанных между собой операторов try-catch-finally— это обеспечение управляющей среды, в которой могут запускаться операторы сценария, содержащие ошибки выполнения. Подобная задача осуществляется так^ чтобы при возникновении исключительной ситуации, ее обработка проводилась в сценарии, а остальные механизмы управления ошибками, характерные для браузера, не задействовались. Для каждого из трех операторов указывается блок кода, соответствующий следующему синтаксису. try { выполняемые операторы } catch (сведенияОбОшибке) { операторы, выполняемые при справедливости ситуации в блоке try } finally { операторы, выполняемые в любом случае [необязательно] } Каждый блок try должен располагаться на том же уровне вложенности, что и блоки catch и-или finally, т.е. на этом уровне не должно быть никаких других операторов. Например, в функции может использоваться одноуровневая конструкция try-catch, как показано в следующем примере. function myFunc\) { try { опера торы } catch (e) { операторы } } Но если имеется еще один блок try, расположенный на один уровень ниже, соответст-^ вующие ему блоки catch и finally также следует располагать на этом более низком уровне. function myFunc() { try { операторы try { операторы ) catch (e) { опера торы } } catch (e) { опера торы } } Операторы, содержащиеся внутри блока try, включают инструкции, которые, на взгляд пользователя, могут послужить причиной возникновения ошибки вьшолнения программы из-за неверно введенных пользователем данных, неудачной загрузки какого-либо компонента страницы или подобных ошибок. Блок catch предназначен для предотвращения появления сообщения об ошибке в браузере (например, в NN6 и Mozilla это может быть консоль JavaScript). Глава 31. Управляющие структуры и обработка исключительных ситуаций 965
Для получения информации об обработке исключительных ситуаций этого типа сущест- . вует специальный термин переход. Когда с помощью какой-либо операции или метода проводится запуск исключительной ситуации, говорят о "переходе к исключительной ситуации". Например, если в операторе сценария вызывается метод строкового объекта, а этого метода для данного объекта не существует (возможно, его имя указано с ошибкой), то компилятор JavaScript "переходит к исключительной ситуации". Некоторые исключительные ситуации имеют имена, в этих именах иногда (но не всегда) содержится важная информация об ошибке. Имя описанной выше ситуации — TypeError (еще больше доказывает то, что "исключительные ситуации" и "ошибки" невероятно похожи). Но не только в языке JavaScript (ГЕ5+, NN6+ и W3C) существует переход к исключительным ситуациям. В W3C DOM также определяются категории исключительных ситуаций для объектов DOM. Например, согласно W3C DOM 2, метод appendChild() (см. главу 15) может приводить к (или вызывать в терминологии W3C) одной из трех ситуаций. Имя исключительной ситуации Вызывается в случае hierarchy_request_err Если типу текущего узла запрещается иметь дочерние узлы типа newchild, или если добавляемый узел является одним из родительских данного узла wrong_document_err ' Если newChil d и текущий узел были созданы из разных документов no_mod I f i cat I on_allowed_err Если текущий узел предназначен только для чтения Так как исключительные ситуации можно вызвать с помощью метода appendChild (), в идеале оператор JavaScript, который используется для этого, должен располагаться внутри блока try. Работа блока немного необычна. Его формат внешне подобен функции, так как ключевое слово catch сопровождается парой круглых скобок и произвольной переменной, в которой задается ссылка на объект ошибки, а свойства этого объекта заполняются браузером при возникновении исключительной ситуации. В одном из таких свойств хранится имя ошибки. Поэтому в блоке catch можно исследовать это имя и вызвать некоторую часть программы для обработки различных зарегистрированных ошибок. Для того чтобы понять, как использовать данную конструкцию в своей программе, приведем пример гипотетической универсальной функции, с помощью которой можно создать новый элемент и добавить его к некоторому узлу. Тип создаваемого элемента и ссылка на родительский узел указываются как параметры. Чтобы предупредить потенциально неправильное использование значений параметра в этой функции, в ней проводится дополнительная обработка ошибок. Таким образом обрабатываются все возможные исключительные ситуации для двух методов DOM: createElement () и appendChild (). Листинг для данной функции выглядит следующим образом. // Общий вариант function attachToEnd(theNode, newTag) { try { var newElem = document.createElement(newTag); theNode.appendChild(newElem); catch (e) { switch (e.name) { case "INVALID CHARACTER ERR" : 966 Часть IV. Объекты языка JavaScript
операторы для обработки ошибки в методе createElement () break; case "tfIERARCHY_REQUEST_ERR" : операторы для обработки ошибки в методе appendChild () break; case "WRONG_DOCUMENT_ERR" : операторы для обработки ошибки в методе appendChild () break; case "NO_MODIFICATION_ALLOWED_ERR" : операторы для обработки ошибки в методе appendChild () break; default: операторы для обработки любой другой ошибки return false; return true; } Отдельный блок catch листинга 31.7 выполняется только тогда, когда исключительная ситуация возникает в одном из операторов в блоке try. Но исключение не обязательно должно быть одним из четырех указанных в блоке catch, это могут быть и ошибки синтаксиса, и любые другие ошибки, которые присутствуют в блоке try. Именно поэтому пользователю предоставляется последняя возможность, чтобы обработать совершенно неожиданные ошибки. Работа программиста заключается не только в предупреждении ошибок, но также и в обеспечении правильных способов обработки исключительных ситуаций (независимо от того, будет все это проводиться в диалоговых окнах предупреждения или внутренними средствами). Например, в случае использования неверного символа в createElement () можно попробовать спасти данные, передаваемые функции attachToEnd (), и повторно вызвать метод, обрабатывающий полученное значение theNode Восстановленное значение записывается в newTag. Если все эти операции были проведены успешно, блок try будет выполнен без ошибки, причем пользователь даже не узнает о том, что в сценарии есть проблема. В блоке finally содержится код, который всегда выполняется после блока try, независимо от того, происходит ли в этом блоке переход к ошибке. В отличие от блока catch, в блок finally объект ошибки не передается как параметр, поэтому то, что определяется в блоке try, остается неизвестным. Если блоки catch и finally следуют после блока try, их выполнение зависит от того, будет ли сгенерирована исключительная ситуация. Если ни одна исключительная ситуация не возникла, блок finally выполняется после запуска последнего оператора блока try. Но если в блоке try исключение возникло, выполнение программы начинается с блока catch. После завершения обработки блока catch выполняется блок finally. В среде разработки, в которой программисты получают полный контроль над такими ресурсами, как память, блок finally может использоваться для удаления некоторых временных элементов, сгенерированных в блоке try (независимо от того, возникает исключительная ситуация в этом блоке или нет). В настоящее время в JavaScript редко используют данный вид технического обслуживания, но вам следует знать о программных возможностях блока finally в контексте конструкции try-catch-finally. Исключительные ситуации на примерах Случай, рассмотренный в листинге 31.7, немного идеализирован. Получается, что браузер сообщает о каждой исключительной ситуации так, как это определено в формальной спецификации W3C DOM. К сожалению, браузеры вплоть до версий ГЕ6 и NN7, так не делают Глава 31. Управляющие структуры и обработка исключительных ситуаций 967
(пока). В этих браузерах существуют дополнительные соглашения об именовании ошибок и синтаксисе, отличном от используемого в DOM, с помощью которых сообщение 66 ошибке отображается на экране во время возникновения исключительной ситуации. Совершенно прав тот, кто считает, что все эти несоответствия усложняют обработку исключений, поддерживаемую несколькими браузерами. Даже сообщения о простых ошибках в этих двух версиях браузеров и спецификации W3C DOM могут быть разными. Пока в браузерах не наблюдается особого единодушия в отслеживании исключительных ситуаций, рекомендуется создавать сценарии только для одной из сред браузеров, таких как Ш6 для Windows или NN7. Однако один аспект обработки исключительных ситуаций может все-таки применяться в IE5+, NN6 и W3C. Можно воспользоваться преимуществом конструкции try-catch для перехода к собственным исключительным ситуациям; на практике эту методику чаще всего используют в расширенных средах программирования. Переход к исключительным ситуациям Последнее, еще не рассмотренное ключевое слово обработки исключительных ситуаций throw, позволяет использовать специальные средства для управления таким процессом, как проверка правильности введенных данных. В любом месте блока try можно вручную предусмотреть исключительные ситуации, которые тут же будут обрабатываться в соответствующем блоке catch. Более подробно исключительные ситуации описаны выше. Синтаксис для оператора throw имеет следующий вид. throw значение; Указанное значение может быть любого типа, но рекомендуется применять значение объекта ошибки (более подробно он описывается далее в этой главе). Любое указанное пользователем значение будет назначено параметру блока catch. Просмотрите следующие два примера. В первом случае это значение является строковым сообщением; во втором — объектом ошибки. В листинге 31.8 рассматривается одно входное текстовое поле для чисел от 1 до 5. После щелчка на кнопке проводится поиск соответствующего символа в массиве, и этот символ выводится во втором текстовом поле. Сценарий поиска состоит из двух простых подпрограмм проверки правильности данных, в которых проверяется, является ли введенный символ числом и принадлежит ли это число нужному диапазону. Отслеживание ошибок осуществляется с помощью сценария. Если любое условие ошибки соблюдается, в операторе throw выполняется переход к блоку catch. В блоке catch переменной е назначается входной параметр string. Это означает, что указанное в операторе сообщение следует вывести в диалоговом окне предупреждения. Но одиночный блок catch используется не только для проверки двух условий возникновения ошибок (и, очевидно, любых других, добавленных программистом), он также выполняется подобно функциям (т.е. можно использовать ссылку на текстовое поле ввода данных, чтобы получить и выбрать введенный текст, в котором содержится ошибка). Листинг 31.8. Вызов строковых исключительных ситуаций ::^\<^i£0§ <html> <head> <title>Throwing a String Exception</title> <script type="text/javascript"> var letters = new Array("A","B","C","D","E"); function getLetter(fId) { try { var inp = parselnt(fid.value, 10); 968 Часть IV. Объекты языка JavaScript
if (isNaN(inp)) { throw "Entry was not a number."; } if (inp < 1 || inp > 5) { throw "Enter only 1 through 5."; } fid.form.output.value = letters[inp - 1]; } catch (e) { alert(e); fid.form.output.value = ""; fid.focus(); fld.selectO ; </script> </head> <body> <hi>Throwing a String Exception</hi> <hr /> <form> Enter a number from 1 to 5: <input type="text" name=" inputJ' size="5" /> <input type="button" value="Get Letter" onclick="getLetter(this.form.input)" /> Matching Letter is: <input type="text" name="output" size="5" /> </form> </body> </html> Упущение данной программы состоит в следующем: если бы внутри блока try возникла другая исключительная ситуация, значение, переданное блоку catch, было бы объектом ошибки, а не строкой. В таком случае, результат, выведенный в диалоговом окне предупреждения, совершенно бессмысленный. Поэтому в конструкциях throw-catch рекомендуется задать объект ошибки. Листинг 31.9 является усовершенствованной версией листинга 31.8, в которой демонстрируется возможность создания объекта ошибки, передаваемого в блок catch в операторе throw. <html> <head> <title>Throwing an Error Object Exception</title> ocript type="text/javascript"> var letters = /new Array("A","B","C","D","E"); function getErrorObj(msg) { var err = new Error(msg); return err; } function getLetter(fid) { try { var inp = parselnt(fid.value, 10); if (isNaN(inp)) { throw getErrorObj("Entry was not a number."); } if (inp < 1 || inp > 5) { throw getErrorObj("Enter only 1 through 5."); Глава 31. Управляющие структуры и обработка исключительных ситуаций 969
} fid.form.output.value = letters[inp - 1]; } catch (e) { alert(e.message); fid.form.output.value = ""; fid.focus(); fid.select(); </script> </head> <body> * <hl>Throwing an Error Object Exception</hi> <hr /> <form> Enter a number from 1 to 5: <input type="text" ,name="input" size="5" /> <input type="button" value="Get Letter" onclicks"getLetter(this.form.input)" /> Matching Letter is: <input type*"text" name="output" size="5" /> </form> </body> </html> Единственное отличие блока catch в этой программе состоит в том, что в нем теперь воспринимается свойство message генерируемого объекта ошибки. Таким образом, если внутри блока try возникнет другая исключительная ситуация, сгенерированное браузером сообщение будет выводиться в диалоговом окне предупреждения. По правде говоря, на этом работа не заканчивается. Если сгенерированная браузером исключительная ситуация и возникает, не всегда сообщение в диалоговом окне предупреждения будет понятно пользователю. В сообщении об ошибках будет, вероятно, указана ошибка синтаксиса либо ошибка введенных данных— наиболее бессмысленное сообщение, которое пользователь часто получает от своей любимой операционной системы. Рекомендуется выполнить переход из блока catch так, чтобы исключительные ситуации, "намеренно" создаваемые в сценарии, обрабатывались в диалоговых окнах предупреждения, которые определены в этом блоке, но другие типы ситуаций будут обрабатываться иначе. Для этого можно "позаимствовать" одно из свойств объекта ошибки, например, name, чтобы пользовательские сообщения обрабатывались отдельно в блоке catch. В листинге 31.10 с помощью функции getErrorObj О свойству name назначается определенное пользователем значение последнего созданного объекта ошибки. Имя может быть любым, но лучше не использовать имена исключительных ситуаций, зарезервированных JavaScript или DOM. Но можно же не знать всех этих имен? Да, поэтому старайтесь дать уникальное имя своей ошибке. Ниже, в блоке, с помощью конструкции switch выполняется переход для распознавания двух классов ошибок. По причине того, что в Ш5 у объекта ошибки отсутствует свойство name, выражение (е.name), указанное в switch, принимает значение undefined, что влечет за собой выполнение случая default всякий раз, когда возникает "родная" исключительная ситуация (необходимо быть внимательным с тем, свойство какого объекта ошибки используется в операторах default). В этом упрощенном примере описывается единственная возможная проблема, отличная от тех, которые отслеживаются в блоке try (из-за нее могут возникнуть сложности при загрузке страницы). В данном примере в случае возникновения других ошибок пользователю просто предлагается перезагрузить страницу и повторить свои действия. Суть состоит в том, что в одном блоке catch можно обрабатывать неограниченное количество классов пользовательских и системных ошибок. 970 Часть IV. Объекты языка JavaScript
<html> <head> <title>Throwing a Custom Error Object Exception</title> <script type="text/javascript"> var letters = new Array("A","B","C","D","E"); function getErrorObj(msg) { var err = new Error(msg); err.name = "MY_ERROR"; return err; function getLetter(fId) { try { var inp = parselnt(fid.value, 10); if (isNaN(inp)) { throw getErrorObj("Entry was not a number."); if (inp < 1 || inp > 5) { throw getErrorObj("Enter only 1 through 5."); } fid.form.output.value = letters[inp - 1]; catch (e) { switch (e.name) { case "MY_ERR0R" : alert(e.message); fid.form.output.value = ""; fid.focus(); fid.select(); break; default : alert("Reload the page and try again."); ,>' </script> </head> <body> <hl>Throwing a Custom Error Object Exception</hi> <hr /> <form> Enter a number from 1 to 5: <input type="text" name="input" size="5" /> <input type="button" value="Get Letter" onclick="getLetter(this.form.input)" /> Matching Letter is: <input type="text" name="output" size="5" /> </form> </body> </html> Если вам интересно посмотреть, как работает программа, альтернативная коду листинга 31.10, скопируйте файл листинга с компакт-диска себе на жесткий диск и измените последнюю строку блока try так, чтобы в имени массива отсутствовал один из символов. fid.form.output.value = letter[inp]; Это обеспечит неправильную загрузку страницы. Если вводится одно из допустимых значений, скорее всего, на экране появится предупреждение о перезагрузке, а не фактическое сообщение объекта ошибки: символ не определен. Пользователи будут благодарны такому подходу. Ниже приведено подробное описание объекта ошибки. Глава 31. Управляющие структуры и обработка исключительных ситуаций 971
Объект ошибки Свойства Методы Error.prototype объектОшибки. toString() объектОшибки. constructor объектОшибки. description объектОшибки.filename объектОшибки. lineNumber объектОшибки. message объектОшибки. name объектОшибки. number Синтаксис Создание объекта ошибки. var myError = new Error ("сообщение'1) var myError = Error {"сообщение") Доступ к статическому свойству объекта Error. Error.свойство Доступ к методам и свойствам объекта ошибки. ErrorObject.свойство \ метод {[свойство)] Совместимость: Winffi5+, MacIE-, NN6+, Mozl+, Safari 1+ Описание объекта Образец объекта ошибки создается всякий раз, когда возникает исключительная ситуация или программист вызывает любой из типов конструкторов для создания этого объекга. В свойствах экземпляра объекта ошибки содержится информация о природе ошибки в таком виде, чтобы ее можно было просмотреть и соответственно обработать в блоке catch. В ГЕ5 объект ошибки представлен в соответствии с формальным объектом ошибки ЕСМА-262, поэтому в версии Ш5 не существует собственного набора свойств, которые не являются частью стандарта ЕСМА. Эти свойства все еще существуют в ГЕ5.5+, разработка которого также основывалась на указанном стандарте. С другой стороны, в NN6 используются как свойства ЕСМА, так и два собственных свойства. Эти дополнительные свойства нужны для вывода собственного сообщения об ошибке сценария в данном браузере. К сожалению, для разработчиков приложений во всех версиях браузеров не предусмотрено унифицированного способа управления ошибками, поскольку ни одно свойство браузеров не поддерживает объект ошибки. Однако в ГЕ5.5+ и NN6+ есть свойства name и message. Как отмечалось ранее в этой главе, программист может создать объект в любое время при использовании оператора throw, чтобы обеспечить собственную защиту от сбоев (см. описание листинга 31.9 обработки несуществующих в Internet Explorer свойств). 972 Часть IV. Объекты языка JavaScript
Свойства constructor См. строка. constructor (глава 27) description Возвращаемое значение: строка Чтение/Запись Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- B свойстве description содержится строка описания, с помощью которой обеспечивается определенный уровень детализации ошибки. Для ошибок, заданных браузером, описание представляет собой тот же текст, который выводится в диалоговом окне ошибки сценария в Internet Explorer. Несмотря на то, что это свойство и продолжает поддерживаться, все же предпочтительнее использовать свойство message. См. также: свойство message. filename lineNumber Возвращаемое значение! строка Чтение/Запись Совместимость: WinIE5+, MacIE-, NN6+, Moz-, Safari- B NN6 свойства filename и lineNumber объекта ошибки используются для обработки собственной внутренней ошибки сценария; эти значения являются частью сообщений об ошибках, которые выводятся на консоли JavaScript, filename представляет собой URL документа, в котором содержится ошибка; lineNumber— номер строки исходного кода оператора, с помощью которой генерируется исключительная ситуация. Эти свойства в JavaScript разработаны так, что при возникновении такой необходимости содержащуюся в них информацию можно будет использовать для собственной обработки ошибок. О том, как применять эту информацию для вывода сообщений об ошибках, определенных пользователем, речь шла при описании свойства window. error (глава 16). См. также: свойство window. error. message Возвращаемое значение: строка Чтение/Запись Совместимость: Winffi5.5+, MacIE-, NN6+, Mozl+, Safari 1+ В свойстве message содержится строка описания, которая обеспечивает необходимый уровень детализации ошибки. Для ошибок, заданных браузером, описание представляет собой тот же текст, который выводится в диалоговом окне ошибки сценария в Internet Explorer и на консоли NN6+. Эти сообщения более полезны для программистов, чем для пользователей. К сожалению, не существует никаких стандартов для формулировки сообщения для данной ошибки. Поэтому опасно использовать содержимое сообщения в блоке catch как средство обработки определенных видов ошибок. Можно воспользоваться этой возможностью, если разрабатываемый сценарий предназначен для одной платформы браузера, но нет никаких гарантий, что текст сообщения для определенной исключительной ситуации не будет изменяться в следующих версиях браузера. Пользовательские сообщения об ошибках, применяемые в приложении, могут быть написаны на доступном пользователю языке, если программист намеревается вывести сообщения на экран (см. листинги 31.8-31.10). См. также: свойство description. Глава 31. Управляющие структуры и обработка исключительных ситуаций 973
name Возвращаемое значение: строка Чтение/Запись Совместимость: WinIE5.5+, MacIE-, NN6+, Mozl+, Safari 1+ B свойстве name содержится слово, которым определяется тип произошедшей ошибки. Наиболее общий вид ошибки, определяемой в конструкторе new Error (), — Error. В JavaScript ошибки могут быть представлены другими именами: EvalError, RangeError, ReferenceError, SyntaxError, TypeError и URLError. Некоторые из этих типов ошибок не обязательно должны использоваться программистами (они применяются прежде всего при выполнении компилятором JavaScript возложенных на него задач), но некоторые браузеры также используют их в повседневной работе. К сожалению, имеются некоторые несоответствия в имени, назначенном этому свойству для ошибок сценария. Если JavaScript используется в среде браузера, который поддерживает W3C DOM, некоторые виды исключительных ситуаций DOM возвращаются с помощью свойства name. Часто браузеры назначают этому свойству собственные типы ошибок, но обычно в этом плане практически все версии браузеров поступают одинаково. Для пользовательских исключительных ситуаций, которые инициируются в сценарии, можно назначить любые имена. Как показано в листингах 31.9 и 31.10, эта информация может использоваться в блоке catch при обработке разных категорий ошибок. См. также: свойство message. number Возвращаемое значение: число Чтение/Запись Совместимость: WinIE5+, MacIE-, NN-, Moz-, Safari- B Ш5+ каждому описанию ошибки или сообщению назначается уникальный номер. Однако использование свойства number влечет за собой некоторые проблемы. Несмотря на то, что разработчики Microsoft задокументировали средства синтаксиса, соответствующие ошибкам выполнения сценариев и их номеров, на практике браузеры Internet Explorer не выводят номера, описанные в документации Microsoft. Это неудобно, поскольку такой номер чаще всего не зависит от языка программирования (хотя в блоке catch легче указать номер ошибки, чем описание или сообщение). Свойство number появилось одновременно со свойством description (теперь замененное свойством message), поэтому пока неизвестно, насколько безопасно использовать значения номеров ошибок в сценариях. См, также: свойство description. Методы toStringO Возвращаемое значение: строка (см. текст) Совместимость: Winffi5+, MacIE-, NN6+, Mozl+, Safaril+ С помощью метода toString для объекта ошибки возвращается строковое описание ошибки. В ГЕ5 и Ш5.5 посредством этого метода возвращается ссылка на этот же объект. В NN6 возвращается строка свойства message, которой предшествует строка Error: (с пробелом после двоеточия). Если необходимо получить удобочитаемое выражение объекта ошибки, используют свойство message (а в Ш5 — description). См. также: свойство сообщения. 974 Часть IV. Объекты языка JavaScript
Операторы JavaScript 1рЧ}\ JavaScript существует огромное количество операто- ы^' ров. Это могут быть слова и символы, используемые в выражениях, с помощью которых выполняются операции над одним или двумя значениями для получения определенного результата. Любое значение, над которым оператор выполняет некоторое действие, называется операндом. В выражении может содержаться один операнд и один оператор (так называемый унарный оператор) или два операнда, разделенные одним оператором (бинарный оператор). Во многих операторах используются одни и те же символы. Различие операторов заключается в их комбинировании и порядке расположения. # Большинство операторов JavaScript появилось /назаметет еще при разработке первой версии этого языка. I ^* Но, как и следовало ожидать, со временем в словарь добавилось несколько новых операторов. В этой главе обратите внимание на категории операторов, которые указаны в таблицах совместимости. Если для оператора в его категории существуют определенные ограничения, связанные с используемой версией, то они описываются полностью. Категории операторов Для того чтобы упростить восприятие большого количества операторов JavaScript, они были поделены на семь категорий. (Автор дает неточное название второй категории, но, по его мнению, это название гораздо лучше передает назначение этой группы в данном языке программирования. — Примеч. ред.) В табл. 32.1 приведены все существующие типы операторов. Любое выражение, в котором содержится оператор, в конечном счете принимает некоторое значение. В одних случаях с помощью оператора изменяется значение одного из операндов; в других— результатом является новое значение. Даже в простом выражении 5 + 5 используется два целочисленных операнда, объединенных оператором сложения. Данное выражение возвращает зна-
чение 10. Оператор применяется для указания компилятору JavaScript команды, которая должна быть выполнена для определения значения каждого выражения в сценарии. 1. Категории операторов JavaScript Назначение Сравнения Используются для сравнения значений двух операндов, результатом является либо истина, либо ложь (наиболее часто используется в условных инструкциях if. . . else и конструкциях цикла for) Арифметические Объединяются два операнда для получения одного значения, которое является результатом арифметической или другой операции над ними Присвоения Значение выражения правого операнда присваивается переменной, указанной с левой стороны оператора, иногда с некоторым его изменением (в зависимости от символа, применяемого совместно с этим оператором) Булевы Используются для выполнения булевых операций над одним или двумя булевыми операндами Битовые Применяются для выполнения арифметических действий либо смещения двух операндов в двоичном представлении (основание = 2) Объектные Для определения средств наследования и возможностей определенного объекта перед вызовом его свойств или методов Комбинированные Группа операторов, используемых в особых ситуациях Сравнение двух операндов, которые на первый взгляд выглядят совершенно разными, не является чем-то необычным. В JavaScript важно не то, как выглядят эти операнды, важно их значение. Два совершенно непохожих операнда при сравнении могут оказаться идентичными. Таким образом, выражение, в котором сравниваются два значения fred == 25 возвращает true, если значение, хранящееся в переменной fred после выполнения более ранней инструкции, равно 25. Операторы сравнения Совместимость: WinIE3+, MacIE3+, NN2+, Mozl+, Safari 1+ При любом сравнении двух значений в JavaScript результат принимает булево значение true или false. Существует целый ряд операторов сравнения, которые можно выбрать в зависимости от действия, необходимого для выполнения над двумя операндами. В табл. 32.2 приведены все операторы сравнения. Синтаксис Название Типы операндов Результаты i = Равенство Все Неравенство Все Строгое равенство Все Булев Булев Булев (IE4+, NN4+, W3C) 976 Часть IV. Объекты языка JavaScript
Окончание табл. 32.2 Синтаксис !== > > = < < = Название Строгое неравенство Больше чем Больше .или равно Меньше чем Меньше или равно Типы операндов Все Все Все Все Все Результаты Булев (IE4+, NN4+, W3C) Булев Булев Булев Булев При использовании числовых значений результат операции будет аналогичен результатам, получаемым с помощью обычных алгебраических преобразований. Ниже приведены некоторые примеры, результат которых может быть не достаточно очевидным. 10 == 10 // true 10 == 10.0 // true 9! = 10 // true 9 > 10 // false 9.99 < = 9.98 // false Любым из этих способов можно сравнивать даже строковые значения. "Fred" == "Fred" // true "Fred" == "Fred" // false "Fred" > "Fred" // false "Fred" < "Fred" // true Для того чтобы сравнить два строковых значения, в JavaScript проводится преобразование каждого строкового символа в код ASCII. Каждый символ левого операнда сравнивается с соответствующим символом правого операнда. Для прописных букв код ASCII имеет меньшее значение, чем для строчных, поэтому прописной букве присваивается меньшее значение, чем строчной. С полной уверенностью можно сказать, что операторы сравнения в JavaScript "чувствительны" к регистру. Для сравнения можно также использовать значения свойств объекта, возвращаемые функциями обработчиков событий или любыми другими функциями. Обычное сравнение строки, используемое при проверке правильности введенных данных, сводится к проверке наличия в этой строке определенных символов. form.entry.value != " " // true, если в поле задано значение Равенство несоизмеримых типов данных Во всех версиях JavaScript, предшествующих 1.2, при сравнении строкового значения, состоящего из цифр и строковых чисел (например, "123" == 123 или "123" != 123), предполагается, что сравниваться будут соизмеримые значения. В исключительных случаях проводится дополнительное преобразование данных, при этом тип данных оригинала не изменяется (например, если значения содержатся в переменных). Но обычно ситуация гораздо сложнее, так как другие типы данных, например объекты, необходимо сравнивать в первоначальном виде. Поэтому для всех версий JavaScript, предшествующих 1.2, используют правила сравнения, приведенные в табл. 32.3. Применение логической схемы, по которой выполняется сравнение (табл. 32.3), требует от программиста предусмотрительности, так как он должен описать все возможные и невозможные варианты преобразования типов данных для достижения равенства (даже при том, что исходные значения непосредственно не преобразуются). В этой ситуации рекомендуется Глава 32. Операторы JavaScript 977
провести требуемое преобразование непосредственно в операторе сравнения. Таким образом, лучше четко определить тип сравниваемых значений, например, строковые экземпляры двух значений или их числовые варианты, а не оставлять это компилятору JavaScript. Операнд А Операнд В Внутреннее осуществление сравнения Ссылка на объект Любой тип данных Ссылка на объект Пустое значение Ссылка на объект Строковое значение Строковое значение Числовое значение Сравнение значений ссылок на объект Проводится преобразование непустого значения в тип объекта и сравнивание с пустым значением Проводится преобразование объекта в строку и сравниваются строковые значения Проводится преобразование строкового значения в численное и сравниваются числовые значения Обратное преобразование числа в строку влечет за собой связывание пустой строки с этим числом. var a = "09"; var b = 9; а == " " + b; // результат false, так как "09" не равняется "9" Для преобразования строковых значений в числовые существует ряд способов. Наиболее простой из них — это вычесть нуль из строки чисел. var a = "09"; var b = 9; а — 0 == Ь; // результат true, так как 9 равняется числу 9 Для преобразования строковых значений в числовые можно также использовать функции parselnt() и parseFloat(). var a = "09"; var b = 9; Parselnt(a, 10) == b; // результат true, так как 9 равняется числу 9 Чтобы избежать двусмысленности внутренних преобразований в JavaScript 1.2, разработчики добавили еще два оператора равенства, конкретизирующих ситуацию при сравнении. С помощью операторов строгого равенства (===) и строгого неравенства (I ==) сравниваются и типы данных, и их значения. Единственный случай, при котором оператор === возвращает истинное значение, — это когда два операнда имеют один и тот же тип данных (например оба являются числами) и одно и то же значение. Поэтому автоматически число никогда не будет приравниваться к строковому варианту этого же числа. Перед сравнением значений типов данных'и объектов сначала проверяется их соответствие. Также в JavaScript 1.2 предусмотрены некоторые глобальные функции для преобразования строковых переменных в числовые и наоборот: String () и Number (). Для того чтобы продемонстрировать принцип работы данных методов, в следующих примерах используется оператор typeof для определения типа данных выражений, в которых применены эти функции. typeof 9; // результат: числовое значение typeof String (9); // результат: строковое значение typeof "9"; // результат: строковое значение typeof Number ("9м); // результат: числовое значение Ни в одной из этих функций исходный тип данных преобразуемого значения не изменяется. При сравнении используется значение функции. 978 Часть IV. Объекты языка JavaScript
var a = "09"; var b = 9; a = = String (b); // результат: false, так как "09" не равно "9" typeof b; // результат: все еще число Number (а) == Ь; // результат: true, так как 9 равно 9 typeof a; // результат: все еще строковое значение Этот пример является подтверждением того, насколько важно учитывать соответствие типов данных при проверке равенства двух значений. Арифметические операторы Совместимость: WinIE3+, МасГЕЗ+, NN2+, Mozl+, Safari 1+ Арифметические операторы — это те операторы, с помощью которых в результате преобразования двух операндов получается результирующее значение. В табл. 32.4 приведены все виды арифметических операторов в JavaScript. Таблица 32.4.J Синтаксис Название Типы операндов ;•/ у^у 'Ф. У>;;&-5$#£;);'..'. .-; Результаты + - * / % ++ -. +val -val Плюс Минус Умножение Деление Взятие по модулю Приращение Уменьшение Положительность Отрицательность Целочисленный, с плавающей запятой, строковый Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой, строковый Целочисленный, с плавающей запятой, строковый Целочисленный, с плавающей запятой, строковый Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Целочисленный, с плавающей запятой Четыре основных арифметических оператора для чисел известны всем. Оператор "плюс" используется для сложения числовых и строковых значений. "Howdy" + "Doody" // результат "Howdy Doody" В объектно-ориентированном программировании оператор "+" является перегруженным. Это означает, что его действие зависит от контекста. Следует помнить, что при объединении строк никакие дополнительные операции, такие как, например, удаление пробелов между словами или их вставка, не выполняются. В предыдущем примере пробел между названиями является частью первой строки. Глава 32. Операторы JavaScript 979
Определение модуля проводится в случаях, когда необходимо узнать, делится ли одно число на другое без остатка. Этот оператор использовался в предыдущей главе при определении високосности года. Существуют и другие способы определения високосного года, однако в примере просто проверяется, делится ли этот год на четыре нацело. Результатом данной операции является остаток от деления двух значений: если остаток — 0, год делится нацело. Отметим несколько лет, значения которых делят на четыре. 2002 % 4 // результат 2 2003 % 4 // результат 3 2 004 % 4 // результат 0 (Ура! Високосный год!) Таким образом, этот оператор использовался в операторе условия if. . .else следующей структуры. var howMany = 0; today = new Date(); var theYear = today.getYear{); if (theYear % 4 == 0) { howMany = 29; } else { howMany = 28; } В некоторых других языках предлагается использовать операторы, при применении которых результат представляет собой целую часть от деления: интегральное деление или div. В JavaScript не существует подобных операторов, однако можно осуществить выполняемые ими операции самим (при условии, что используемые операнды— положительные числа). Используйте методы Math. floor () или Math. ceil () и оператор деления. Math.floor (4/3); // результат 1 В этом примере можно указать только числа со значениями большими либо равными 0; в Math. ceil () же .используются только отрицательные значения. Оператор приращения (++) является унарным оператором (только один операнд). Его можно использовать в двух различных случаях, в зависимости от того, с какой стороны расположены символы операнда. Операторы приращения и уменьшения (--) могут использоваться вместе с операторами присвоения, которые будут описаны позже. Как следует из названия, с помощью оператора приращения проводится увеличение значения операнда на единицу. Но в инструкции присвоения необходимо внимательно следить за тем, когда это увеличение будет осуществляться. При использовании одного знака = значение правого операнда записывается в переменную, указанную слева. Если оператор ++ расположен перед правым операндом (префикс), правый операнд увеличивается перед записью его значения в переменную; если оператор ++ расположен после правого операнда (постфикс), предыдущее значение операнда передается в переменную прежде, чем значение будет увеличено. Рассмотрим следующий пример, чтобы лучше понять разницу между этими двумя ситуациями. var a = 10; //а инициализируется равным 10 var z = 0; // z инициализируется равным 0 z = а; // а = 10, следовательно и z = 10 z = ++а; // а = 11 перед присвоением, // а = 11 и z становится равным 11 z = а++; // а = 11 перед присвоением, // таким образом z = 11; а = 12 z = а++; // а = 12 перед присвоением, // таким образом z = 12; а = 13 Оператор уменьшения работает аналогично, за исключением того, что значение операнда уменьшается на единицу. Операторы приращения и уменьшения наиболее часто используются 980 Часть IV. Объекты языка JavaScript
в счетчиках циклов for и while. Простая конструкция ++ или - - более компактна, чем переназначение переменной с прибавлением к ней 1 (z = z + 1 или z ±= 1). Так как эти операторы унарные, их можно использовать без инструкции присвоения при изменении значения переменной счетчика цикла. function doNothingO { var i = 1; while (i < 20) { ++i; } alert(i); // отображение при i = 20 } Последние два арифметических оператора также являются унарными (работающими с одним операндом). И положительный, и отрицательный операторы могут использоваться в глобальной функции Number () для преобразования строкового операнда, состоящего из символов чисел, в числовой тип данных. Строковый операнд не изменяется, но после выполнения последней операции возвращается значение числового типа, как показано в следующем фрагменте. var a = "123"; var b = +a; // b теперь = 123 typeof a; // результат: строковое значение typeof b; // результат: числовое значение У оператора отрицания (-val) существует дополнительная возможность. При помещении знака "-" перед любым числом (без пробела между символом и значением) компилятор JavaScript преобразует указываемое положительное значение в отрицательное и наоборот. При этом значение операнда не изменяется, но выражение возвращает измененное значение (см. следующий пример). var х = 2; var у = 8; var z = -х; // z равно -2, ax все еще 2 z = — (х + у); // z равно -10, ах-2иу-8 z = -х + у; // z равно 6, ах все еще 2 и у — 8 Для того чтобы сделать отрицательным булево значение, следуйте описанию булевых операторов, в частности, оператора Not (!). Операторы присвоения Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safari 1+ Операторы присвоения — наиболее часто встречающиеся инструкции в сценариях JavaScript. Они применяются во всех случаях, когда проводится копирование значений или результатов выражения в переменную для использования этого значения в дальнейшем. Значения присваиваются переменным по многим причинам, даже тогда, когда можно использовать оригинальные значения или выражения в одном сценарии несколько раз. Далее приводится ряд причин, по которым переменным присваиваются различные значения. ■ Имена переменных обычно короче. ■ Имена переменных более наглядны. ■ Может возникнуть необходимость сохранения оригинального значения для дальнейшего его использования в сценарии. ■ Оригинальное значение является свойством, которое нельзя изменить. ■ Многократный вызов в сценарии одного и того же метода неэффективен. Глава 32. Операторы JavaScript 981
Начинающие программисты часто игнорируют последнюю причину. Например, если с помощью сценария создается HTML-код нового документа, то более эффективно поместить строку, состоящую из больших фрагментов страницы, в одну переменную перед вызовом метода document. write () для отображения на экране этого текста. Это гораздо удобнее, чем выводить HTML-документ по одной строке, при этом многократно вызывая операторы document . writeln (). В табл. 32.5 приведены операторы присвоения, используемые в JavaScript. Синтаксис = += - = * = /= %= <<= >= >>= >>>= &= | = А Название Равенство Добавление значения Вычитание значения Умножение на значение Деление на значение Взятие значения по модулю Сдвиг влево на значение Сдвиг вправо на значение Заполнение значения нулями Сдвиг вправо на значение Побитовое И Побитовое ИЛИ Побитовое исключающее ИЛИ Пример X X X X X X X X X X X X X = У += у — У *= У /- У %= у «= у >= У »= у >>>= у &= у 1= У = У Операция X X X X X X X X X X X X X - = = = 55 = = = = = = = = У X X X X X X X X X X X X + У - у * У / У % у « У > У >> у >>> у и у 1 У А у Как можно заметить в группе операторов, рассмотренных ранее (и в группе, которая описывается далее в этой главе в разделе "Побитовые операторы"), используя операторы присвоения и простой знак "=", в коде можно эффективно представить сложные операции, особенно, если обрабатывается несколько значений, которые необходимо объединить в последующих инструкциях. В предыдущих главах вам уже встречались примеры, в которых оператор приращения (+=) использовался при преобразовании строки в длинную строковую переменную, которая в конечном счете передавалась в метод document .write (). Ниже приведен фрагмент листинга 37.3 с некоторыми изменениями. В данной программе можно использовать сценарии JavaScript для создания содержимого элемента select. var elem = " "; // вызов следующей части страницы и формы elem + = " <p>Select a regional office: "; elem + = " <select name = 'offices' onchange = 'getData(this.form)' >"; // формируется список опций из массива названий офисов for (var i = 0; i < regionalOffices.length; i ++) { elem + = " <option"; // дескрипторы OPTION if (i «a o) { // первый элемент в списке elem + = " selected"; } elem + = ">" + regionalOffices [i]; } elem + = "</selectx/p>"; // закрытие дескриптора элементов select document.write (elem); // отображение элементов на странице 982 Часть IV. Объекты языка JavaScript
Фрагмент сценария начинается с использования оператора присвоения, с помощью которого переменная el em инициализируется как пустая строка. Во многих строках используется оператор приращения для прибавления строкового значения к тому, которое содержится в переменной el em в данный момент. Без оператора приращения пользователь вынужден применять простой оператор присвоения в каждой строке программы, (чтобы связать новые строковые данные с уже существующими). В этом случае начало программы будет выглядеть следующим образом. var elem = ""; // вызов следующей части страницы и формы elem = elem + " <p>Select a regional office: "; elem = elem + " <select name = 'offices' onchange = 'getData (this.form)'; В цикле for из-за многократного повторения elem+ код становится тяжелым для понимания, отладки и обновления. Такие усовершенствованные операторы присвоения являются более краткими, поэтому их спокойно можно использовать в циклах. Булевы операторы Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safari 1+ В программировании логическая арифметика играет довольно важную роль. Мы приводили примеры, в которых программы принимают решения, основываясь на том, возвращает ли оператор или выражение булево значение true либо false. Зато нечасто встречались примеры объединения нескольких булевых значений и выражений, так как подобные сценарии относятся к сценариям высокого уровня сложности. В различных условных выражениях, повсеместно используемых в JavaScript (подобных тем, которые применяются в конструкциях if), условие, которое должно проверяется в программе, может быть более сложным чем, скажем, сравнение значения переменной с некоторым установленным значением или проверка на существование в поле пустого значения. Например, часто проверяют, содержит ли выражение, введенное в текстовое поле, все числа, необходимые для обработки в сценарии. Если бы в JavaScript не было специальной функции для вывода сообщения о содержимом введенной строки, программисту пришлось бы рассматривать каждый введенный символ по отдельности и исследовать, принадлежит ли он к диапазону 0-9. Данную операцию можно вьшолнить двумя способами: проверить все символы, значение ASCII которых меньше 0 или больше 9. Также можно проверить, является ли символ большим или равным 0 и меньшим или равным 9. В результате необходимо сравнить результаты обоих тестов. Булева математика Перейдем к особенностям булевой математики. Имея в наличии всего два значения true и false, можно обработать строку выражений, результаты которых являются булевыми, а затем с помощью булевой арифметики выяснить, является результат истиной или ложью. Однако булевы значения не прибавляют и не отнимают, как прибавляют и отнимают обычные числа. Вместо этого используют один из трех булевых операторов JavaScript. В табл. 32.6 приведен синтаксис булевых операторов. Если пользователю не знакомы некоторые символы в таблице, отметим, что символы для оператора ИЛИ получены комбинацией <Shift+/>. Использование булевых операторов с булевыми операндами представляет некоторую сложность для тех, кто не сталкивался с ними ранее, поэтому начнем с наиболее простого оператора: Not (НЕТ). Для него необходим только один операнд. Оператор НЕТ располагается перед любым булевым значением, таким образом "переключая его" в значение, противоположное по знаку (true в false или false в true). Глава 32. Операторы JavaScript 983
Таблица 32.6. Булевы операторы Синтаксис Название Операнды Результаты II И ИЛИ НЕТ Булевы Булевы Один булев Булевы Булевы Булевы 'true !(10 > 5) !(10 < 5) !(document.title // результат: false // результат: false // результат: true "Flintstones") // результат: true Как видно из примера, заключение операнда выражения Not в круглые скобки никогда не бывает лишним, так как при наличии скобок компилятор JavaScript оценивает взятое в них выражение перед тем, как изменить его согласно оператору Not. С помощью оператора И (&&) два булевых значения складываются; результатом этого сложения может быть true или false, что зависит от значений обоих операндов. Существует так называемая таблица истинность, в которой расписаны результаты всех возможных комбинаций значений операндов. Далее приведена таблица истинности для оператора И (табл. 32.7). Таб/шца 327 Лаблица истинное дпяо^ Левый операнд Оператор И Правый операнд Истина Истина Ложь Ложь Истина Ложь Истина Ложь Результат Истина Ложь Ложь Ложь Результат true можно получить только в одном случае — когда оба операнда имеют значение true. Сторона, с которой расположен оператор true или false, не имеет никакого значения. Далее приведены примеры для каждого из рассмотренных случаев. 5 > 1 && 50 > 10 // результат: true 5 > 1 SlSl 50 < 10 // результат: false 5 < 1 && 50 > 10 // результат: false 5 < 1 && 50 < 10 // результат: false . Совершенно обратное происходит с оператором ИЛИ (| |): результат true получить гораздо легче, чем false, true возвращается в любом случае, когда хотя бы один из операндов (или оба) имеют истинное значение. Таблица истинности для оператора ИЛИ приведена далее (табл. 32.8). им h&?b ^'^^^Щ Оператор ИЛИ Правый операнд Результат Истина Истина Ложь Ложь Истина Ложь Истина Ложь Истина Истина Истина Ложь 984 Часть IV. Объекты языка JavaScript
Если с обеих сторон оператора указано выражение, значение которого true, результатом также будет истинное значение. Попробуйте изменить в предыдущих примерах операторы И на ИЛИ и посмотрите, как это скажется на результатах. 5 > 1 || 50 > 10 // результат: true 5 > 1 || 50 < 10 // результат: true 5 < 1 || 50 > 10 // результат: true 5 < 1 || 50 < 10 //результат: false Оператор ИЛИ возвращает false только тогда, когда оба операнда имеют ложное значение. Применение булевых операторов Применение булевых операторов в JavaScript первый раз занимает некоторое время, тем более что приходится предварительно провести вычисления на бумаге (чтобы разобраться в логической схеме выражений). Ранее уже говорилось об использовании булевых операторов, когда необходимо выяснить, попадает ли символ в диапазон значений ASCII для проверки правильности ввода даннцх. В листинге 32.1 представлена функция, используемая далее в главе 43. С помощью этой функции проверяется значение ASCII каждого символа указанной строки. Если оно меньше 0 или больше 9, то во введенной строке не содержатся цифры. Листинг 32.1 .Является ли ваеденное значение цифрой? ' function isNumber (inputStr) { for (var i - 0; i < inputStr.length; i++) { var oneChar = inputStr.substring (i, i + 1); if (oneChar < "0" || oneChar > "9") { alert ("Please make sure entries are numerals only."); return false; »' return true; ) Для того чтобы считать по одному символу (подстроке) из объекта string, используемого в цикле for, необходимо указать нужное условие в конструкции if. (oneChar < "0" || oneChar > "9") В этом выражении используется оператор ИЛИ для проверки обоих условий. Если применить к данному выражению таблицу истинности ИЛИ (табл. 32.8), получим, что результат true будет возвращен (хотя бы одно условие должно быть истинным). После этого пользователь получит сообщение о возникшей проблеме; вызывающий проверку оператор получит значение false. Функция возвратит значение true только в том случае, если оба условия, указанные в выражении, примут значение false для всех символов строки. От простого оператора ИЛИ перейдем к более сложным операциям. В функции (а точнее, в одном условии) проверяется отношение числа к нескольким числовым диапазонам. Сценарий, описанный в листинге 32.2, является фрагментом приложения поиска массивов (см. главу 50), в котором пользователь вводит первые три символа номера социального страхования. Листинг 32.2. П номера одному из диапазонов // функция проверки принадлежности значения диапазону function inRange (inputStr) { num = parselnt (inputStr) if (num < 1 || (num > 586 && num < 596) || (num > 599 && num < Глава 32. Операторы JavaScript 985
700) || num > 728) { alert ("Sorry, the number you entered is not part of our database. "); return false; . } return true; } Во время вызова данной функции введенные пользователем данные одновременно проверяются в JavaScript на принадлежность к числовому типу данных. Теперь в функции необходимо проверить, относится это число к одному или нескольким диапазонам, которые отдельно представлены в приложении. Далее описаны условия, проверяемые в функции. Число не должно быть: ■ меньше 1; ■ больше 586 и меньше 596 (использование оператора И); ■ больше 599 и меньше 700 (использование оператора И); ■ больше 728. Каждое из этих условий объединено в одно с помощью оператора ИЛИ. Если какое-либо из этих условий принимает значение true, вся конструкция if принимает истинное значение, и пользователь получает соответствующее сообщение. Вместо объединения такого количества булевых выражений в одном условии можно создать несколько вложенных конструкций if. Но недостатком подобной конструкции будет не только ее громоздкость, в случае "провала" одного из условий, для каждого из них в диалоговом окне будет выводиться собственное предупреждение. Объединенное булево условие намного эффективнее. Побитовые (или поразрядные) операторы Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safari 1+ Для программистов побитовые операции представляют собой довольно обширную тему. Если программист не работает с внешними процессами на CGI-сервере или подключенными аплетами Java, маловероятно, что он когда-либо будет использовать побитовые операторы. Опытные программисты, которые интересуются специфическими типами данных (например long integer), детально разбираются в этой области, поэтому остается только предоставить описание возможностей JavaScript. В табл. 32.9 приведены побитовые операторы JavaScript. Твб*1Ю4а32^ Оператор & 1 А. ~ << >> >>> Название Побитовое И Побитовое ИЛИ Побитовое исключающее ИЛИ Побитовое НЕТ Смещение влево Смещение вправо Заполнение нулями при смещении вправо Левый операнд Целочисленное значение Целочисленное значение Целочисленное значение (Нет) Целочисленное значение Целочисленное значение Целочисленное значение Правый операнд Целочисленное значение Целочисленное значение Целочисленное значение Целочисленное значение Количество разрядов, на которое проводится смещение Количество разрядов, на которое проводится смещение Количество разрядов, на которое проводится смещение 986 Часть IV. Объекты языка JavaScript
Числовые значения операндов могут располагать любым из трех числовых литеральных базисов в JavaScript (десятичные числа, восьмеричные или шестнадцатеричные). Как только оператору указывается операнд, значение преобразуется в двоичное представление (длиной 32 бита). Для первых трех побитовых операций биты одного операнда сравниваются с соответствующими битами другого операнда. Конечное значение каждого бита зависит от оператора. ■ Побитовое И. 1, если оба символа — 1. ■ Побитовое ИЛИ. 1, если хотя бы один из символов — 1. ■ Побитовое исключающее ИЛИ. 1, если только один символ — 1. Побитовое НЕТ является унарным оператором, с помощью которого инвертируют значение каждого бита в одиночном операнде. Побитовые операторы смещения управляют только одним операндом. Вторым операндом определяется число позиций, на которое смещаются двоичные значения разрядов в направлении стрелок оператора. Пример Применение оператора смещения влево (<<) влечет за собой следующий результат. 4 << 2 // результат 16 Это объясняется тем, что двоичное представление десятичного числа 4 имеет вид 00000100 (в любом случае, восемь разрядов). Использование оператора смещения влево для компилятора JavaScript означает, что необходимо сдвинуть все символы на два разряда влево. Результат данной операции будет 00010000 (в десятичном формате ему соответствует число 16). Если кого-нибудь заинтересовали эксперименты с этими операторами, используйте приложение The Evaluator (глава 13) для вычисления типовых выражений. Также вам будут интересны книги по программированию на С и C++. Объектные операторы Для работы со следующей группой операторов используются объекты (включая пользовательские объекты, объекты JavaScript или DOM) и типы данных. Большинство из них осуществлено уже после выхода первого браузера, поддерживающего JavaScript, таким образом, для каждого из них представлена собственная оценка совместимости. delete Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ Для объектов массивов не существует метода, с помощью которого можно было бы удалить отдельный элемент, также для пользовательских объектов не представлено 'метода удаления свойств. Можно удалить данные в элементе массива или свойстве, указав пустую строку или пустую ссылку, но после этого элемент массива или свойство все равно останутся в объекте. С помощью оператора delete можно полностью удалить элементы и свойства. Помните о важном моменте, который имеет место при удалении элемента массива. Если в массиве используются числовые индексы, при удалении элемента массива удаляется и его индекс из полного массива, однако массив не "нарушается" (т.е. индексы элементов, расположенных выше удаленного элемента, не изменяются). Пример Рассмотрим следующий простой массив. var oceans = new Array ("Atlantic", "Pacific", "Indian","Arctic"); В этом массиве числовые индексы автоматически назначаются указанным элементам для дальнейшего обращения к ним в различных конструкциях (например, в цикле for). Глава 32. Операторы JavaScript 987
for (var i s 0; i < oceans.length; i++){ if (oceans[i] == form.destination.value){ операторы } } Если использовать выражение delete oceans[2]; в массиве произойдут существенные изменения. Сначала третий элемент массива будет удален. Заметьте, что длина массива не изменится. После индекса (2) удаления из массива этот массив будет выглядеть следующим образом. oceans[0] = "Atlantic"; oceans[1] = "Pacific"; oceans[3] = "Arctic"; Если попробовать обратиться по ссылке oceans [2 ], результат будет undefined. Рекомендуется применять оператор delete в массивах с именными индексами. Таким образом будет легче контролировать остающиеся элементы и их значения, поскольку в данном случае не имеет значения, отсутствует определенный числовой индекс или нет. Еще один аспект подобного удаления элементов — в JavaScript не обеспечивается абсолютный контроль за использованием памяти. Вся очистка ненужных данных из памяти проводится с помощью ядра JavaScript, в результате чего принимается автоматическое решение, когда можно очистить память от расположенных в ней элементов, и когда неиспользованная прикладная память браузера должна восстанавливаться. Однако вы не сможете заставить браузер выполнить задачу очистки памяти вручную. in Совместимость: Winffi5.5+, МасГЕ-, NN6+, Mozl+, Safaril+ С помощью оператора in можно проверить, имеет ли объект именованные свойства или методы. Операнд, указываемый слева от оператора, представляет собой строковую ссылку на свойство или метод (только имя метода без скобок); правый операнд — исследуемый объект. Если указанное свойство или метод присутствует в объекте, выражению возвращается значение true. Таким образом можно применить оператор in в условных выражениях. Пример Поэкспериментируйте с этим оператором в приложении The Evaluator. Например, чтобы доказать, что метод write () доступен для объекта document, введите в верхнее текстовое поле следующее выражение. "write" in document Сравните работу метода document. createAttribute () в W3C DOM для Ш5.5 и NN6. "createAttribute" in document В NN6 результатом будет true, а в Ш5.5 — false. Используя этот оператор в условных выражениях, можно определить поддержку объекта в коде программы. Например, если программист намеревается использовать в своем сценарии метод document. createAttribute (), он предварительно должен удостовериться в том, что данный метод поддерживается (предполагается, что в браузерах всех пользователей оператор in поддерживается). 988 Часть IV. Объекты языка JavaScript
instanceof Совместимость: Winffi5+, MacIE-, NN6+, Mozl+, Safari 1+ С помощью оператора instanceof можно проверить, относится ли объект к модели JavaScript или DOM (NN6). Операнд, указываемый слева от оператора, представляет собой проверяемое значение; операнд, указываемый справа от оператора, — ссылку на корневой класс, в котором, возможно, содержится созданное значение. Для родных классов JavaScript в ссылках, указываемых справа от оператора, могут указываться такие статические объекты, как Date, String, Number, Boolean, Object, Array и RegExp. Иногда необходимо помнить, что родные классы JavaScript могут быть дочерними для других родных классов, а это означает, что значение может быть экземпляром двух различных статических объектов. Пример Рассмотрим следующий фрагмент программы (который можно исследовать в приложении The E valuator). а = new Array(1,2,3); a instanceof Array; Второе выражение выдает результат true, так как конструктор Array использовался для генерирования объекта. Но Array в JavaScript сам является образцом корневого объекта Ob j ect. Поэтому оба следующих выражения принимают значения true. instanceof Object; Array instanceof Object; new Совместимость: WinIE3+, Macffi3+, NN2+, Mozl+, Safari 1+ Многие объекты среды JavaScript имеют функции-конструкторы, встроенные в язык. Для обращения к этим функциям используют оператор new вместе с именем конструктора. В функции возвращается ссылка на экземпляр объекта, который может быть использован в сценарии для получения, и установки свойств или вызова методов объекта. Например, при создании объекта даты today необходимо вызвать конструктор объекта Date следующим образом. var today = new Date(); В некоторых конструкторах создания объектов запрашиваются определенные параметры. В других, как в случае с объектом Date, можно использовать различные форматы параметров, в зависимости от той информации, с помощью которой необходимо организовать исходный объект. Оператор new может использоваться со следующими объектами базового языка. JavaScript 1.0 JavaScript 1.1 JavaScript 1.2 JavaScript 1.5 Date Array RegExp Error Object Boolean (Пользовательский объект) Func t ion Number String Глава 32. Операторы JavaScript 989
this Совместимость: WinIE3+, МасШЗ+, NN2+, Mozl+, Safari 1+ B JavaScript существует ключевое слово; с его помощью в операторе сценария можно обращаться к объекту, в котором эти инструкции расположены. Этот оператор, "обращающийся сам к себе", — this. Наиболее часто он используется в обработчиках событий, в которых ссылки на себя передаются в функции для дальнейшей их обработки. <input type="text" name="entry" onchange="process(this)"> В функции переданное значение назначается переменной, которая может использоваться для обращения к отправителю, свойству или методу. Пример Поскольку с помощью оператора this проводится обращение к объекту, к свойствам этого объекта также можно обращаться, используя его. Например, для того чтобы передать свойство value текстового объекта в функцию, оператор this задается в текущей ссылке на объект, и в ней же осуществляется обращение к свойству value. <input type="text" name="entry" onchange="process(this.value)"> Оператор this можно также использовать внутри других объектов, например, пользовательских. Данная возможность часто практикуется при определении функции-конструктора пользовательского объекта, оператор this применяют для определения свойств этого объекта и указания их значений. Рассмотрим следующий пример создания объекта. function bottledWater(brand, ozSize, flavor) { this.brand = brand; this.ozSize = ozSize; this.flavor = flavor; } var myWater = new bottledWater("Crystal Springs", 16, "original"); При создании нового объекта с помощью функции-конструктора операторы this определяют каждое свойство объекта, после чего им назначаются соответствующие начальные значения. Довольно удобно использовать одинаковые имена для свойств и переменных параметров, это заметно облегчает работу с конструктором. Кроме того, если функция назначается как свойство объекта (и работает подобно методу объекта), с помощью оператора this внутри этой функции выполняется обращение к объекту, вызывающему функцию (таким образом открывается возможность доступа к свойствам объекта). Например, если добавить следующее определение функции и выражение к только что созданному объекту myWater, функция может обратиться к свойству этого объекта brand. function adSloganO { return "Drink " + this.brand + ", it's wet and wild!"; } myWater.getSlogan = adSlogan; При вызове метода myWater. getSlogan () в объекте вызывается функция adSlogan (), но в контексте объекта myWater. Таким образом, оператор this применяется в указанном объекте для обращения к свойству brand в форме (this. brand). Комплексные операторы Последняя группа операторов не вписывается ни в одну из предыдущих категорий, однако она является не менее важной. 990 Часть IV. Объекты языка JavaScript
# Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Оператор "запятая" используется при определении нескольких выражений, которые необходимо оценить, начиная с крайнего левого. Наиболее часто этот оператор используется при перечислении инициализируемых переменных. Например, объявление нескольких переменных можно объединить в одном операторе следующим образом. var name, address, serialNumber,- Еще один случай, в котором применяют данный оператор, — выражение конструкции цикла for. В следующем примере две различные числовые переменные инициализируются, а затем увеличиваются на различные числа. В начале работы цикла обе переменные были инициализированы как нулевые (это совсем не обязательно, на данный пример так написан). При каждом последующем прохождении цикла одна переменная увеличивается на единицу, а вторая — на 10. for (var i=0, j=0; i < someLength; i++, j+10) { } Только не путайте оператор "запятая" с оператором "точка с запятой", которую используют для разделения выражений. ?: Совместимость: Winffi3+, MacIE3+, NN2+, Mozl+, Safaril+ Оператор условия является сокращенной формой условного выражения конструкции if. . .else, которая уже описывалась в главе31. Этот оператор обычно используется вместе с оператором присвоения для указания одного из двух значений переменной (в зависимости от результата условного выражения). Формальный синтаксис для условного оператора выглядит следующим образом. условие ? выражениеЕслиПравда : выражениеЕслиЛожь Если используется оператор присвоения, обратитесь к такому синтаксису. var = условие ? выражениеЕслиПравда : выражениеЕслиЛожь; Не столь важно, в какой из двух форм будет использоваться этот оператор, лишь запомните, что выражение, в котором содержится этот оператор, принимает значение одного из двух выражений, указанных после вопросительного знака. В этом выражении можно выполнить любую операцию JavaScript, включая вызов других функций, а также вложение других условных операторов одного из выражений для создания конструкции, эквивалентной вложенным структурам if. . .else. Чтобы полученное выражение соответствовало вложенным условным выражениям, заключите внутренние выражения в круглые скобки (таким образом можно проверить, принимают ли они значения перед тем, как примет значение внешнее выражение). В следующем примере переменной назначается одно из трех строковых значений (в зависимости от значения переменной даты). var monthPart = (dateNum <= 10) ? "early" : ((dateNum <= 20) ? "middle" : "late"); Вначале внутреннему условному выражению, расположенному справа от первого двоеточия, будет присвоено значение либо middle, либо late; после чего внешнему условному выражению передается либо значение early, либо результат внутреннего условного выражения. typeof Совместимость: WinIE3+, МасШЗ+, NN3+, Mozl+, Safari 1+ В отличие от большинства других операторов, преимущественно связанных с арифметикой и логикой, с помощью унарного оператора typeof определяется вид значения, которое Глава 32. Операторы JavaScript 991
получает переменная или выражение. Обычно этот оператор используется для определения того, относится ли переменное значение к одному из следующих типов: number, string, boolean, object, function или undefined. Пример Данная возможность в JavaScript очень полезна, так как в переменных данные не просто содержатся — они, как правило, изменяются в процессе выполнения программы, и, соответственно, изменяются их типы. Может возникнуть ситуация, когда потребуется обработать значение другого типа. Наиболее часто свойство typeof используют как часть условия. if (typeof myVal == "number") { myVal = parseInt(myVal); } Значение операции typeof является строковым. void Совместимость: Winffi3+, МасШЗ+, NN3+, Mozl+, Safari 1+ Bo всех браузерах, поддерживающих сценарии, можно использовать запись j avascript: псевдо-URL для определения параметра атрибутов href и src в дескрипторах HTML (например, ссылок). При работе с данным выражением необходимо быть внимательным, так как функция и операторы, вызываемые в URL, не возвращают и не принимают любое значение. Если значение такого выражения возвращено, то этим значением (а иногда каталогом папок жесткого диска клиента) часто заменяется содержимое страницы. Чтобы такого не происходило, перед функцией или выражением используют оператор void, вызываемый j avascript: URL. Пример Наиболее оптимальный способ использования данной конструкции состоит в размещении оператора перед выражением или функцией и разделение их пробелом, как показано ниже. javascript: void doSomething(); Иногда вы будете брать выражение, следующее за оператором void, в круглые скобки. Использование скобок необходимо только в том случае, когда в выражении содержатся операторы с более низким приоритетом, чем оператор void (см. следующий раздел, "Приоритеты операторов"). Но не стоит автоматически брать в скобки все выражения, так как в некоторых браузерах это может вызвать проблемы. Атрибуту href ссылки а чаще всего назначают текущий URL для дальнейшего вызова ее обработчика событий onclick. href = "javascript: void (0)"; С помощью оператора void можно убедиться в том, что функция или выражение не возвратит значение, которое может быть использовано атрибутом HTML. Даже обработчик событий onclick ссылки не может работать так, как он бы работал при вызове этой ссылки (например, принимая значение return false). Приоритеты операторов При работе с выражениями, в которых используется несколько операторов (например листинг 32.10), важно помнить порядок, в котором компилятор JavaScript обрабатывает эти выражения. В JavaScript всем типам операторов назначены свои приоритеты (чтобы все выражения обрабатывались в единственно возможной последовательности). В следующем выражении 10 + 4 * 5 // результат 30 992 Часть IV. Объекты языка JavaScript
компилятором JavaScript используется схема'приоритетности для выполнения умножения перед сложением несмотря на порядок, в котором расположены операторы. Другими словами, сначала перемножаются 4 и 5, а затем полученный результат добавляется к 10, таким образом получается 30. Нельзя сделать так, чтобы результат этого выражения был другим. Если необходимо сначала прибавить 10 к 4, а затем умножить эту сумму на 5, то отмените естественную приоритетность операторов в JavaScript. Чтобы сделать это, следует взять оператор с более низким приоритетом в круглые скобки. Далее приведен пример с соответствующей коррекцией. {10 +4) * 5 // результат 70 Благодаря скобкам результат существенно изменился. Скобки в JavaScript имеют самый высокий приоритет; заключенное в них выражение будет обработано первым. С помощью табл. 32.10, в которой приведены приоритеты операторов JavaScript, изучите правило построения выражений с несколькими действиями. Совет: когда возникает сомнение относительно приоритетности операторов, используйте больше скобок, так как это более надежный способ указать правильную последовательность действий. ta&wua 32.10. Приоритеты операторов JavaScript Уровень приоритета Оператор Замечания О [] function О i ~ - ++ new typeof void delete • / % + - << > >> < От внутренних к внешним Значение индекса массива Вызов любой удаленной функции Булево НЕТ Побитовое НЕТ Отрицание Приращение Декремент - Удаление массива или объектного элемента Умножение Деление Деление по модулю Сложение Вычитание Поразрядные сдвиги Ппрпятппы гпясшрыма Глава 32. Операторы JavaScript 993
Окончание табл. 32.10 Уровень приоритета Оператор Замечания <= > >= 7 == Равенство I : 8 & Побитовое И 9 А Побитовое исключающее ИЛИ 10 I ' Побитовое ИЛИ 11 && Булево И 12 II Булево ИЛИ 13 ? Условное выражение 14 = Операторы присвоения /= %= <<= >= >>= 1 = 15 ' Запятая (разделитель параметров) Приведенная схема полезна в том случае, когда в одном выражении используются два оператора с одним уровнем приоритета. Если такое случается (например, со сложением и вычитанием), обработка выражения проводится слева направо. Иногда в условном операторе указывается несколько булевых выражений (листинг 32.2). Компилятор JavaScript работает по принципу так называемой короткой обработки. Поскольку вложенные выражения рассматриваются слева направо, результат всего условия иногда может определяться раньше, чем все выражения будут обработаны. Если встречается оператор И, а левый операнд принимает значение false, результатом всего выражения будет false. В таком случае обработка правого операнда даже не проводится. Для оператора ИЛИ: если левый операнд — true, выражению автоматически присваивается истинный результат. Следующая особенность может немного запутать программиста, у которого не дос- 994 Часть IV. Объекты языка JavaScript
таточно опыта написания подобных сценариев: если в правом операнде существует синтаксическая или какая-либо другая ошибка (и она не была обнаружена при обработке правого операнда выражения), о ее существовании узнать будет невозможно. Ее обнаружат уже пользователи страницы. Советуем проверять свои страницы на наличие подобных ошибок. Обратите внимание, что все математические операции и операции объединения строк выполняются раньше операторов сравнения. Это означает, что все выражения, которые выступают в роли операндов, полностью обрабатываются перед их сравнением. Ключ к управлению выражениями, в которых выполняется несколько действий, — в изоляции отдельных выражений и анализе их работы (см. дополнительные советы по отладке главу 45). /" На замелет Глава 32. Операторы JavaScript 995
Функции и пользовательские объекты сценариях, описанных в предыдущих главах этой книги, уже использовались функции JavaScript, следовательно, даже у начинающего программиста должно сформироваться некоторое представление об их работе. В данной главе описывается объект function и возможность создания программистом собственных объектов. (Для которых, как и для остальных объектов, будут существовать собственные свойства и методы.). Объект функции Свойства Методы Обработчики событий arguments apply() arity call() caller toStringO constructor valueOf() length prototype Синтаксис Создание объекта функции. function имяФункции([aprl,. . . [,aprN] ]) { операторы (ы) ) var имяФуякции=new Function([■•aprl",...[,"aprN»] , " оператор!; . . . [; операторе " ] ) object.eventHandlerName=function([aprl,. . . [, aprtf] ]) {оператор(ы)}
Доступ к свойствам и методам объекта функции. объектФункции.свойство]метод([параметры]) Совместимость: Winffi3+, МасШЗгК NN2+, Mozl+, Safari 1+ Описание объекта Такие общепринятые понятия, как процедуры, подпрограммы и функции, существующие в других языках, в JavaScript объединены в один тип: пользовательские функции, функция может возвращать значение (если в ней используется ключевое слово return), хотя это и не обязательно. Функции приспособлены для любой обработки данных, в них обрабатывается не только код JavaScript, который выполняется при загрузке документа. Существует возможность создать огромные функции, состоящие из сотни строк, но целесообразнее разбить такую функцию на отдельные процессы и поместить их в отдельные небольшие функции. Достоинства подобного метода состоят в следующем: меньшие фрагменты проще для написания и отладки; весь сценарий визуально выглядит проще, если он состоит из отдельных блоков; одни и те же функции можно сделать общими для нескольких сценариев и при этом использовать их многократно; функции также можно вызывать из различных частей сценария и открытых фреймов. Правда, для того чтобы научиться создавать функции, используемые многократно, потребуется некоторое время и опыт. Поэтому советуем изучить как можно больше возможностей, а также ознакомиться с примерами других Web-программистов. Создание функций Стандартный способ определения функции заключается в использовании стандартного шаблона для дальнейшего заполнения его всем необходимым. Формальный синтаксис функции имеет такой вид. function имяФункции {[aprl] ... [, aprN] ) { оператор (ы) ) Для имени функции, как правило, выбирают такое название, с помощью которого можно будет точно определить ее назначение и возможности. Если запланированную для функции задачу нельзя выразить именем из одного или максимум трех слов (которые сжаты в один непрерывный набор символов имяФункции), то возможно, для одной функции предназначена слишком большая нагрузка. Скорее всего, лучше будет разделить поставленную задачу на две или более функций. Начинающему программисту рекомендуется использовать уже существующие функции, которые можно вызвать из функции, им написанной. Если складывается ситуация, когда необходимо скопировать строки программы из одной части функции и вставить их в другую (так как в них выполняются одни и те же операции), то лучше создать отдельную функцию для этого фрагмента. Всегда можно создать так называемые анонимные функции, используя конструктор new Function (). Имя этой "анонимной" функции присваивается следующим образом. var имяФункции = new Function (["aprl", ... [,"aprN"] , "оператор1; ... [; опера торы] "]) Такой способ создания функций особенно удобен в случае, когда такая функция в сценарии используется после загрузки документа. В этой структуре присутствуют все составляющие функции. Имя каждого параметра функции является строковым значением, все параметры отделены друг от друга запятыми. Заключительная строка параметра состоит из операторов, Глава 33. Функции и пользовательские объекты 997
которые выполняются при вызове функции. Отделите каждый оператор JavaScript точкой с запятой и заключите всю последовательность в кавычки, как показано ниже. var willltFit = new Function("width","height","var sx = screen.availWidth; var sy = screen.availHeight; return (sx >= width && sy >= height)") В функции willltFit () — два параметра; в теле функции определяются две локальные переменные (sx и sy). Если значения входных параметров окажутся меньше, чем значения локальных переменных, возвращается булево значение true. Традиционно эта функция выглядит следующим образом. function willltFit(width, height) { var sx « screen.availWidth; var sy « screen.availHeight; return (sx >= width && sy >= height); } Если функция уже существует в памяти браузера, вызвать ее можно подобно любой другой функции. if (willltFit(400,500)) { операторы ) В NN4+, ГЕ4+ и W3C DOM для создания функций используется еще один формат. С помощью этой распространенной методики, получившей название выражение лямбда, создается ссылка на анонимную функцию (причем действительно анонимную, так как у данной функции нет никакого имени, по которому можно было бы обратиться к ней позже). Данный метод часто применяют для присвоения ссылок на функции в обработчиках событий, когда необходимо также передать объект события, используемый в Netscape Navigator. Далее приведен пример присвоения анонимной функции обработчику событий onchange для управления формой. document.forms[0].age.onchange = function(event) {isNumber(document.forms[0].age)} Вложенные функции В NN4+, NN4+ и W3C также предусмотрено вложение функций друг в друга. Раньше при написании сценария функции определялись на глобальном уровне, в результате чего каждая функция была доступна и во всех других сценариях. В данной ситуации можно формировать функции внутри друг друга, таким образом, вложенная функция не будет доступна из других частей сценария. Конечно, не рекомендуется многократно использовать одни и те же названия, но можно создать функции с одинаковыми именами, вложенные в другие функции глобального уровня. Ниже приведен пример подобной структуры. function outerA(){ опера торы function innerA(){ операторы } операторы function outerB(){ операторы function innerA(){ операторы } function innerB(){ операторы 998 Часть IV. Объекты языка JavaScript
} операторы } Вложенные функции удобно применять, когда один набор операторов необходимо вызвать в нескольких местах большой функции, и такие операторы имеют значение только в контексте этой большой функции. Другими словами, можно было бы выделить повторяющуюся последовательность в отдельную глобальную функцию, но целесообразнее оставить данные в пределах области, в которой они используются. К вложенной функции можно обращаться только из операторов функции, в которой она содержится (в любом порядке). Кроме того, все переменные, определенные во внешней функции (включая переменные параметров) доступны и во внутренней функции; хотя переменные, определенные во внутренней функции, не доступны для внешней функции. В разделе "Переменные: глобальные и локальные" речь пойдет об использовании переменных в различных фрагментах сценария. Параметры функции В определении функции после имяФункции обязательно указывается набор круглых скобок. Если функции не передается определенная информация, поступающая при ее вызове, скобки могут быть пусты. Но если с вызовом функции поступают некоторые данные, каждому из параметров необходимо дать имя. Параметром может быть любое значение: строковое, числовое, булево, это могут быть даже ссылки на объекты — формы или элементы форм. Выберите такие имена для переменных, по которым можно будет легко вспомнить их содержимое; избегайте многократного использования уже существующих названий объектов в качестве имен переменных, поскольку объекты и переменные с одинаковыми именами в одном выражении легко перепутать. Не рекомендуется использовать ключевые слова JavaScript (в том числе зарезервированные слова, перечисленные в приложении Б) и имена глобальных переменных, определенных в другом месте сценария. (О глобальных переменных будет рассказано в следующих разделах.) В JavaScript можно не поддерживать соответствие между числом параметров в определении функции и числом параметров, используемых в вызывающих их операторах. Если в функции определяется три параметра, а в вызывающем его операторе только два, третьему параметру присваивается значение null. function oneFunction(a, b, с) { опера торы } oneFunction("George","Gracie") В этом примере параметрам а и b в функции соответствуют значения George и Gracie; параметру с — пустое значение (null). В JavaScript допускается передавать большее количество параметров из вызывающих операторов, чем число переменных параметров, указанных при определении этой функции. В данном языке существует специальный механизм — свойство arguments, с помощью которого к функции можно "подключать" любые посторонние параметры. Свойства arguments Возвращаемое значение: массив аргументов Только чтение Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Глава 33. Функции и пользовательские объекты 999
Когда значения параметров передаются в функцию с помощью операторов, которые и вызывают эту функцию, такие значения параметров присваиваются свойству объекта функции arguments. Это свойство представляет собой массив значений, в котором содержатся значения параметров, хранящихся в элементах этого массива. Индексация элементов начинается с нуля, независимо от того, определены параметры для этих элементов или нет. Используя оператор имяФункции.arguments, length, можно выяснить-количество параметров, переданных в данную функцию. Например, если в функцию передается четыре параметра, то имяФункции. arguments, length возвращает 4. Из этого следует, что можно использовать систему индексации массива {имяФункции. arguments [i]) для получения значения любого параметра (или параметров). Теоретически, программист не должен определять переменные параметров для функций и вызывать для этого соответствующий элемент массива. Но если используется свойство arguments, то рекомендуется обращаться к переменным параметров по именам, которые являются намного более удобными для восприятия, если они правильно подобраны. Однако могут возникнуть ситуации, в которых для одной определенной функции должно обрабатываться несколько вызовов, при этом в каждом вызове задано различное количество параметров. В функции могут обрабатываться любые параметры, даже те, которым не присвоены имена переменных. Пример См. листинги 33.1 и 33.2, в которых демонстрируется работа свойств arguments и caller. arity Возвращаемое значение: целочисленное Только чтение Совместимость: WinlE-, МасШ-, NN4+, Moz-, Safari- См. свойство lenght далее в этой главе. caller Возвращаемое значение! ссылка на объект функции Только чтение Совместимость: WinIE4+, MacIE4+, NN3+, Mozl+, Safaril+ При вызове одной функции из другой между ними устанавливается специальная связь для правильного обмена значениями. Поэтому в вызванной функции организуется ссылка на функцию, вызывающую ее. Подобная информация автоматически сохраняется в объекте функции как свойство caller. Эта зависимость подобна свойству opener, в котором указывается окно или фрейм, используемый для создания подокна. Свойству присваивается значение только в том случае, когда функция вызывается из другой функции; если это не так, свойству caller присваивается пустое значение null. Значение свойства caller представляет собой ссылку на объект функции; таким образом можно просматривать его свойства arguments и caller (в случае, когда он вызван из другой функции). Следовательно, из функции можно обращаться к вызывающей ее функции для получения передаваемых ею значений. В свойстве имяФункции. caller хранится определение всей функции (включая обработчик событий). Если вызов функции осуществляется из операторов JavaScript, не включенных ни в одну из функций, свойство имяФункции. caller имеет значение null. 1000 Часть IV. Объекты языка JavaScript
Пример Рассмотрите листинг 33.1, в котором используются оба свойства. Лис™иг33.1.СвойСТвафункц1ШагдгшвпЬв и caller <html> <head> <titlex/title> <script type="text/javascript"> function hansel(x,y) { var args = hansel.arguments; document.write("<p>hansel.caller is " + hansel.caller + "<br />"); document.write("hansel.arguments.length is " + hansel.arguments.length + "<br />"); for (var i = 0; i < args.length; i++) { document.write("argument " + i + " is " + args[i] + "<br />'»); } document.write("<\/p>") ; } function gretel(x,y,z) { today = new DateO; thisYear = today.getFullYear(); hansel(x,y,z,thisYear); } </script> </head> <body> <script type="text/javascript"> hansel(1, "two", 3); gretelU/ "five", 6, "seven"); </script> </body> </html> После загрузки этой страницы в окне браузера будут отображены следующие результаты (в Safari в данном случае свойство caller примет значение undefined). hansel.caller is null hansel.arguments.length - 3 argument 0 is 1 argument 1 is two argument 2 is 3 hansel .caller is function gretel(x, y, z) { today = new DateO; thisYear = today.getFullYear(); hansel(x, y, z, thisYear); } hansel.arguments.length is 4 argument 0 is 4 argument 1 is five argument 2 is 6 argument 3 is 2 001 (или другой текущий год) При загрузке документа функция hansel () вызывается непосредственно из тела сценария. Ей передаются три параметра, при том, что определяется только два. Несмотря на это, все три параметра записываются в свойство hansel .arguments. Далее из основной части сценария вызывается функция gretel (), в которой, в свою очередь, снова вызывается hansel (). Глава 33. Функции и пользовательские объекты 1001
Но теперь при вызове передается уже четыре параметра. В функции gretel () обрабатываются только три из них, а при вызове hansel () добавляется еще один параметр, который является результатом выполненных в gretel () вычислений. В свойстве hansel .caller хранится полное содержимое функции gretel (). Примите во внимание то, что в hansel. arguments теперь содержатся все четыре параметра, включая значение года, полученное в функции gretel (). constructor См. string. constructor (глава 30). lenght Возвращаемое значение: целочисленное Только для чтения Совместимость: WinIE4+, МасГЕ4+, NN4+, Mozl+, Safari 1+ На примере свойства arguments можно убедиться в том, что в JavaScript не очень строго контролируется соответствие количества параметров, передаваемых в функцию, и количества переменных параметров, определенных для этой функции. Но из сценария можно обратиться к свойству length для точного определения количества переменных параметров, определенных для конкретной функции. Ссылка на это свойство начинается с имени функции, содержащейся в данном объекте. Например, рассмотрим следующее определение. function identify(name, rank, serialNum) { } Количество параметров можно определить в операторе сценария, расположенном за пределами функции, для чего используется ссылка следующего вида. identify.length Значение свойства в предыдущем примере— 3. Однако чаще всего вместо свойства length используется свойство arity, реализованное только в Netscape Navigator. prototype См. array.prototype (глава30). Методы apply ( [ текОбъехт [, массивАргументов] ] ) call([текОбъект[, aprl[, арг2[, . . .aprtf] ]]]) Методы apply () и call О используются для вызова функции. На первый взгляд иногда кажется странным, зачем пользоваться такой сложной конструкцией, если можно просто указать сначала имя функции, а затем ее параметры и т.п. Отличие данных методов состоит в том, что с их помощью можно вызвать функцию, имея только ссылку на нее. Например, если функция определяется в конструкторе new Function () (или с помощью другого анонимного способа, поддерживаемого в браузере), полученная ссылка на функцию является результатом выполнения конструктора. Для вызова этой функции в дальнейшем с помощью только этой ссылки (возможно, сохраняемой в глобальной переменной) подходят и apply О, и call О . Результат, полученный в обоих методах, одинаков, но определение используемого метода зависит от формы, в которой передаются параметры функции (подробнее об этом вы узнаете далее). Первый параметр, демонстрирующий работу обоих методов, — это ссылка на объект, который для данной функции является текущим. Для многоуровневых функций, определенных в сценарии, используйте ключевое слово this, которое означает, что контекстом функции 1002 Часть IV. Объекты языка JavaScript
становится текущий объект (как для обычной функции). Если нет таких параметров, которые необходимо передать в функцию, в обоих методах их можно опустить. Ссылка на объект используется, когда вызываемая функция принадлежит к функциям, которые обычно определяются как методы пользовательского объекта. (Некоторые из показанных концепций рассматриваются позже в этой главе, поэтому после знакомства с пользовательскими объектами, возможно, придется возвратиться к этому разделу.) Пример В следующем примере генерируется пользовательский объект, после чего ему назначается метод для вывода сообщений о свойствах этого объекта. // Функции, вызываемые как метод объекта 'саг' function showCar() { alert(this.make + " : " + this.color); } // Функция-конструктор объекта 'car' function car(make, color) { this.make = make; this.color = color; this.show = showCar; } // Создание экземпляра объекта '.car' var myCar = new carC'Ford", "blue"); Стандартный способ вывода сообщения из объекта my Car. myCar.show(); В этом случае при вызове функции showCar () текущий объект саг используется как контекст для ссылок this, указанных в функции. Другими словами, если функция showCar () вызывается как метод объекта, объект обрабатывается как "текущий". Однако, используя методы apply О и call О, не обязательно связывать функцию showCar () с объектом myCar. В конструкторе саг () можно не указывать выражение определения функции showCar в качестве метода объекта. Вместо этого вызовите метод showCar () и с его помощью обработайте myCar как текущий объект. showCar.call(myCar); В этом случае функция showCar () работает так же, как и прежде, и ссылка на объект в первом параметре метода call () обрабатывается как текущий объект функции showCar (). Что касается второго параметра метода apply (), то он представляет собой массив значений, которые необходимо передать как параметры текущей функции. Порядок указания значений должен соответствовать порядку задания параметров, определенных для функции. С другой стороны, с помощью метода call () можно передать список индивидуальных параметров, отделенных друг от друга запятой. Все зависит от того, каким способом в данном сценарии передаются параметры. Если они уже представлены в форме массива, то используют метод apply (); в остальных же случаях используют метод call (). ЕСМА рекомендует применять метод call (), когда при вызове функции параметры не передаются. toStringO valueOf () Возвращаемое значение! строковое Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Программисты довольно редко используют методы объекта функции toString () и valueOf (), которые необходимы для отладки сценария и вывода определения функции в строковом Глава 33. Функции и пользовательские объекты 1003
виде. Например, при вводе имени функции, определенной в приложении The Evaluator, в верхнем текстовое поле компилятор JavaScript автоматически преобразует функцию в строку так, чтобы "значение'* можно было вывести в области результатов. Использование этих методов и синтаксический анализ возвращаемого ими текста, имеет, хотя и редко, некоторое практическое применение. Замечания по применению функций Понимание особенностей ввода и вывода функций JavaScript является основой успешного программирования, особенно в случае с несколькими приложениями. В данной главе описываются все способы вызова функций, области рассмотрения переменных функции, рекурсия и разработка функций для многократного использования. Вызов функции В функции действия не выполняются до тех пор, пока она не вызвана с помощью имени иди ссылки. В сценарии функцию можно вызвать (т.е. "заставить ее выполнять определенные действия") четырьмя способами: в обработчике событий объекта документа; в операторе JavaScript; в атрибуте HREF, в результате выполнения конструкции javascript :URL; и более современным способом — с помощью методов call () и apply (). Способ j avascript :URL (называемый также псевдо-URL) в этой книге подробно не описывается. Некоторые дескрипторы HTML имеют свои атрибуты HREF, предназначенные для хранения URL-адресов страниц, используемых при навигации в Internet или загрузки MIME-файлов, для воспроизведения которых требуются вспомогательные приложения или надстройки. Подобные HTML-элементы, как правило, задаются для дескрипторов объектов, выделяемых с помощью мыши (например, ссылок или областей карт изображений, обрабатываемых на стороне клиента). В браузерах, поддерживающих JavaScript, разработан специальный встроенный псевдопротокол — j avascript :URL, с помощью которого к функциям или методам JavaScript можно обращаться в атрибуте HREF так же, как и к документу с помощью URL, определенному в сети. Например, довольно часто javascript :URL используют для того, чтобы изменить содержимое двух фреймов с помощью одной ссылки. Так как атрибут HREF разработан для обращения только к одному URL, тб без этого метода осуществить одновременную загрузку разных документов в нескольких фреймах было бы невозможно. В противном случае вам необходимо создать функцию и задать в ней свойство location.href для двух фреймов, после чего эту функцию можно вызвать с помощью атрибута href. Ниже приведен соответствующий пример. function loadPagesO { parent.frames[1].location.href = "page2.html"; parent.frames[2].location.href = "instrux2.html"; } <a href="javascript:loadPages()">Next</a> При вызове функций вышеописанными способами, могут использоваться параметры, с помощью которых в функциях можно выполнять любые поставленные задачи. Но существует ситуация, когда необходимо предотвратить потенциальный побочный эффект: при возвращении функцией значения (возможно, функция вызывается из других фрагментов сценария, в которых возвращаемые значения должны использоваться в дальнейшем). С помощью атрибута href в окне target устанавливается любое значение, которое примет атрибут, поэтому возвращенное значение присваивается окну target, хотя это и не всегда оправдано. / На заметку 1004 Часть IV. Объекты языка JavaScript
Чтобы предотвратить присвоение возвращенного значения атрибуту href при вызове функции используйте оператор void. <href = "javascript:void loadPages () "> Чтобы в атрибуте href не выполнялись никакие операции (т.е. чтобы сработал обработчик событий onclick), после оператора следует указать пустую функцию. <href = " javascript:void(0)"> Для опытных программистов, владеющих несколькими языками, этот оператор знаком как способ объявления того, что функции или процедуры не возвращают значения. В JavaScript этот оператор имеет такие же функциональные возможности, как и в других языках; отличие заключается в его нетрадиционном применении. Переменные: глобальные и локальные В языке JavaScript переменная может быть двух типов. Как и следовало ожидать, любая переменная, инициализированная в пределах основного потока сценария (не внутри функции), является глобальной переменной; в любом операторе сценария этого же документа к ней можно обращаться, используя имя. Также иногда инициализируют переменные внутри функции (в инструкции var); таким образом, имя переменной можно будет использовать только в операторах этой функции. Ограничивая доступ к переменным одной функции, можно многократно использовать одни и те же имена переменных в нескольких функциях, а эти переменные могут иметь различное применение в каждой функции. В листинге 33.2 демонстрируется данная возможность. Листинг 33.2/Страмица с многократным использованием одних / и тех же переменных <html> <head> <title>Variable Scope Trials</title> <script type="text/javascript"> var headGlobal = "Gumby"; function doNothingO { var headLocal = "Pokey"; return headLocal; } </script> </head> <body> <script type="text/javascript"> // две глобальные переменные var aBoy = "Charlie Brown"; var hisDog = "Snoopy"; function testValuesO { var hisDog = "Gromit"; // инициализация локальной // версии "hisDog" var page = ""; page += "headGlobal is: " + headGlobal + "<br />"; // page += "headLocal is: " + headLocal + "<br />" // не выполняется: не определена headLocal page += "headLocal value returned from head function is: " + doNothing() + "<br />"; page += " aBoy is: " + aBoy + "<br />"; page += "local version of hisDog is: " + hisDog + "<br />"; document.write(page); } Глава 33. Функции и пользовательские объекты 1005
testvalues(); document.write("global version of hisDog is intact: " + hisDog); </script> </body> </html> На этой странице определяется несколько переменных, некоторые из них глобальные, некоторые локальные (они встречаются в таких разделах документа, как head и body). При загрузке этой страницы вызывается функция test Values (), в которой определяются текущие значения всех переменных. После этого извлекается еще одно значение переменной, которая использовалась в функции, но не была объявлена ранее. Таким образом, текст, выведенный на страницу, будет выглядеть следующим образом. headGlobal : Gumby headLocal value, returned from head function is: Pokey aBoy is: Charlie Brown local version hisDog is: Gromit global version of hisDog is intact: Snoopy Исследуйте переменные, инициализированные в этом сценарии. Первая переменная объявляется в разделе Head (headGlobal) и является глобальной, так как она не задается ни в одном определении функции. Для глобальных переменных необязательно указьгоать ключевое слово, но подобная практика весьма полезна— программисту гораздо легче отыскать переменные, инициализированные им специальным образом. Затем создается небольшая функция; в ней определяется переменная (headLocal), которая используется только в операторах этой функции. В разделе Body определяются еще две глобальные переменные: аВоу и hisDog. В функции, расположенной в разделе Body (в качестве примера), снова используется переменная hisDog. Инициализация hisDog с ключевым словом var внугри функции для компилятора JavaScript означает, что необходимо создать отдельную переменную, которая будет использоваться только в этой функции. Подобная инициализация никак не соотносится с глобальной переменной с таким же именем. Это может запутать любого разработчика, даже автора сценария, В операторах описываемого сценария определяются значения объявленных в нем переменных. В JavaScript не возникает никаких проблем при непосредственном обращении к глобальным переменным, включая переменные, определенные в разделе Head. Но компилятор JavaScript не может получить локальную переменную, определенную в другой функции. Например, headLocal является локальной переменной своей функции. Попытка обратиться к этой переменной приведет к сообщению об ошибке, в котором будет сказано, что имя переменной не определено. И это действительно так — для всех функций, кроме doNothing (■), данная переменная не существует. Но если это значение необходимо использовать где-нибудь еще, можно создать функцию, которая будет возвращать его в нужный оператор (как в функции test Values ()). Считывание глобального значения аВоу производится без возникновения проблем. Но поскольку в этой функции инициализирована собственная версия hisDog, то в ней можно обращаться только к данной версии переменной. Если внутри функции назначается переменная, имя которой совпадает с именем уже существующей глобальной переменной, то в этой функции к последней обратиться будет невозможно. В доказательство того, что значение глобальной переменной, имя которой использовалось в функции testValues (), не изменилось, это значение выводится в конце страницы. В результате выполнения программы Чарли Браун (Charlie Brown) и его собака опять будут вместе. Основная идея подобной схемы заключается в возможности многократного использования одного имени переменной во всех функциях, в которых это необходимо. Например, можно использовать переменную счетчика цикла i в каждой функции, в которой присутствуют циклы. (В принципе, один счетчик можно многократно использовать и в нескольких циклах for одной функции, 1006 Часть IV. Объекты языка JavaScript
поскольку в конструкции for значение заново инициализируется в начале цикла.) При передаче параметров в функцию их имена можно использовать для переменных этих параметров в качестве наглядности. Например, обычно полную форму ссылки на объект передают как параметр функции (используя параметр this. form в обработчиках событий). В каждой функции, в которой используется один из этих объектов, можно применить form в переменной параметра. function doSomething(form) { операторы ) <input type="button" yalue="Do Something" onclick="doSomething(this.form)"> Если при щелчке на кнопках, расположенных на странице, объекты форм этих кнопок передаются как параметры различных функций, то в каждой из этих функций в качестве имени параметра можно использовать form (или любое другое имя). Использовать одни и те же имена рекомендуется только для "временных" переменных. В таком случае все переменные являются локальными для своих функций, а потому вы не перепутаете их с глобальными переменными. Многократное использование имени глобальной переменной в любой функции является рискованным. Часто методика глобализации и локализации влечет за собой путаницу и ошибки. Некоторые программисты договариваются о тактике выбора имен (чтобы избежать использования глобальных переменных в качестве локальных). Иногда перед всеми именами глобальной переменной помещают строчную букву д. В примере, приведенном в листинге 33.2, глобальные переменные можно было бы назвать следующим образом. gHeadGlobal gABoy gHisDog Из этого следует, что при определении локальных переменных символ g лучше не использовать. В принципе, хороша любая схема, с помощью которой можно избежать многократного использования одной переменной (если, конечно, она эффективна в остальных отношениях). В случае с несколькими фреймами или несколькими окнами можно обращаться к глобальным переменным из любого другого документа, загруженного в браузер в данный момент (см. главу 16). Правила "видимости" переменных остаются действительными и для вложенных функций в NN4+, ГЕ4+ и W3C. Любые переменные, определенные во внешней функции (включая переменные параметров), могут использоваться во всех функциях, вложенных в нее. Но если новая локальная переменная определяется внутри вложенной функции, эта переменная не будет доступна для внешней функции. Вы можете возвратить значение из вложенной функции в оператор внешней функции, в котором она вызывается. Переменные параметров Когда в функцию поступают данные в виде параметров, помните, что их значения могут быть копиями данных (в случае с обычными значениями данных) или ссылками на реальные объекты (например, объекты форм). В последнем случае в функции можно изменить соответствующие свойства объекта при передаче в эту функцию данного объекта как параметра (см. следующий пример). function validateCountry (form) { if (form.country.value == "") { form.country,value = "USA";. Глава 33. Функции и пользовательские объекты 1007
Поэтому всякий раз, передавая ссылку на объект как параметр функции, помните, что изменения, проведенные в "переданной" функции версии этого объекта, будут отражены и на исходном объекте. Если в функции необходимо обратиться к свойствам или результатам выполнения методов переданных данных (свойства объектов или строк), рекомендуется сделать это в начале функции. Как правило, программисты вначале инициализируют столько переменных, сколько необходимо для обработки всех групп данных, используемых далее в этой функции. Таким образом, можно дать логические (или смысловые) названия группам данных, а не полагаться на длинные ссылки для обращения к соответствующей области функции (например, лучше воспользоваться переменной inputstr вместо form, entry .value). Рекурсия в функциях Функцию можно вызвать саму в себе — эта операция известна под названием рекурсии. Классический пример запрограммированной рекурсии — вычисление факториала (факториал для значения 4 вычисляется как 4*3*2*1); также вычисления проведены в листинге 33.3 (листинг отсутствует на прилагаемом к книге компакт-диске). В третьей строке функции в выражении повторно вызывается текущая функция, параметром которой является значение п-1. Поскольку эта функция вызывается сама в себе, во второй строке производится проверка передаваемого в нее значения переменной — таким образом определяется конечное значение вложенного выражения. Однако обратите внимание, что проверять рекурсивные функции нужно очень осторожно. В частности, удостоверьтесь в том, что рекурсия конечна, т.е. существует предел количества повторных вызовов этой функции. В листинге 33.3 этот предел соответствует начальному значению п. Если предел не указан, может произойти самопроизвольная очистка памяти браузера, а это приведет к сбоям в системе. Листинг 33.3. Использование рекурсии в JavaScript function factorial(n) { if (n > 0) { return n * (factorial(n-1)); } else { return 1; Преобразование функций в библиотеки Создавая функции для сценариев, следует также помнить о возможности создания универсальных функций (написанных так, чтобы их можно было многократно использовать в других приложениях, независимо от объектной структуры страницы). Наиболее подходящими для такого вида обработки являются функции, в которых осуществляется определенная проверка (см. примеры в главе 43), преобразование данных или математическая итерация. Чтобы функция стала универсальной (или общей), в ней не должно быть никаких ссылок на конкретные объекты, заданные с помощью их имен. Имена объектов всегда разные для каждого конкретного документа. Поэтому в подобную функцию определенный объект передают как параметр. Например, если создается функция, в которую в качестве параметра передается объект text, в этой функции можно использовать данные объекта или вызывать его методы, при этом ничего не зная о его структуре или имени. Рассмотрим данную возможность на примере функции (листинг 33.4), которая теперь является частью целого документа. 1008 Часть IV. Объекты языка JavaScript
;/ftw^wfr ЗЭ;4. Вызов уйиверсалкной фугащ»т <html> <head> <title>Variable Scope Trials</title> <script type="text/javascript"> function factorial(n) { if (n > 0) { return n * (factorial(n - 1)); } else { return 1; </script> </head> <body> <form> Enter an input value: <input type="text" name="input" value»"0" /> <pxinput type= "button" value="Calc Factorial" onclick="this.form.output.value = factorial(this.form.input.value)" /></p> <p>Results: <input type="text" name="output" /></p> </form> </body> </html> Данная функция является универсальной только благодаря возможности введения в нее значения (п) в качестве параметра. На форме с помощью обработчика событий onclick кнопки введенное только в одном поле значение передается в функцию factorialO.B возвращаемое значение присваивается полю вывода данных формы. Функция factorial () ничего "не Знает" о том, будут ли в текущем документе использоваться формы, поля или кнопки. Если указанная функция понадобится вам в другом сценарии, ее можно скопировать и вставить в этот сценарий, так как она уже предварительно протестирована. Любая универсальная функция является частью персональной библиотеки сценариев программиста, которой он может пользоваться от случая к случаю, что экономит его время. Однако не все функции можно сделать универсальными. Все равно в сценарии придется создавать ссылки на объекты JavaScript или на пользовательские объекты. Если вам часто приходится создавать функции, в которых вьшолняются одни и те же действия, то напишите одну универсальную функцию и поместить ее в библиотеку. Если посетители используют браузеры Netscape Navigator версии выше 3 (это же относится и к Internet Explorer), поместите эти функции во внешнем файле библиотеки с расширением . j s (см. главу 13, в которой подробно описывается способ совместного использования вспомогательных функций в нескольких документах). Пользовательские объекты На примере предьщущих глав можно было убедиться в том, насколько удобно организовывать информацию об окнах браузера и содержащихся в них документах с помощью объектов. Но в примерах сценариев, которые были рассмотрены ранее, ни разу не использовалась возможность создания собственных объектов со своими свойствами и методами. Подобные объекты не являются элементами интерфейса пользователя на странице, они, скорее, принадлежат к объектам, в которых могут храниться данные и функции сценариев (выполняемые как методы), а результаты этих функций могут выводиться для обозрения пользователями в окне браузера. Глава 33. Функции и пользовательские объекты у 1009
О данной технологии уже упоминалось в главе 30, когда речь шла о массивах. Массив представляет собой упорядоченный набор данных. Можно создать массив JavaScript, элементами которого будут свойства — для обращения к ним используйте уже знакомый точечный синтаксис (имяМассива [индекс] . имяСвойства). Обычно в объекте содержатся различные типы данных. Совсем не обязательно создавать упорядоченную совокупность данных, хотя в сценариях могут использоваться объекты с конструкций, похожих на массивы. Кроме того, к пользовательскому объекту можно прикрепить любое количество собственных функций в качестве методов. Это означает, что программист имеет возможность полного управления структурой объекта, его данными и поведением. Пример "объектов планет" Для формирования массива данных о планетах в этом разделе используется массив, созданный в главе 30. Однако в данной главе демонстрируется, насколько удобно использовать данные, когда они сохраняются в форме пользовательских объектов. В этом модифицированном примере создается всплывающий список, содержащий названия девяти планет Солнечной системы, и выводятся сведения о каждой выбранной планете. Согласно концепции пользовательского интерфейса (и многофреймовых структур), результат выводится в отдельном фрейме двухфреймового окна браузера. Это означает, что с помощью такого объекта создается HTML-документ, который отображается в отдельном фрейме. Если это приложение разрабатывается строго для Ш4+, NN6+ и W3C, можно использовать одни и те же данные для преобразования вида таблицы в соответствии с выбором пользователя. Приведенный пример является полностью совместимым со всеми браузерами, поддерживающими сценарии. В этой главе не будет создаваться массив для хранения данных, мы создадим пользовательские объекты: для каждой планеты — отдельный объект. Объекты обладают пятью свойствами и одним методом. Каждая планета имеет следующие свойства: название, диаметр, расстояние от Солнца, продолжительность года и продолжительность дня. Для того чтобы указать дополнительные сведения об этих объектах, необходимо каждому из них определить возможность вывода "личных** сведений в специальном фрейме окна. Для этого лучше определить одну функцию, в которой можно будет обрабатывать любой объект планеты, вместо того чтобы определять девять отдельных функций для каждого случая. В листинге 33.5 представлен исходный код документа, в котором создается набор фреймов для данных планетарных исследований; в листинге 33.6 приведена полная страница объектно-ориентированного 'документа планет, который расположен в верхнем фрейме. <html> <head> <title>Solar System Viewer</title> <script type="text/javascript"> function blank() { return "<html><body><\/body><\/html>"; } </script> </head> <frameset rows="50%,50%" onload="Frame1.doDisplay(Frame1.document.forms[0] .planetsList)"> <frame name="Framel" src=Mlst33-06.htm" /> <frame name="Frame2" src="javascript:parent.blank()" /> </frameset> </html> 1010 Часть /V. Объекты языка JavaScript
В данной программе обратите внимание на одну особенность: нижний фрейм не загружается до тех пор, пока не загрузится документ верхнего фрейма, поэтому в атрибуте src второго фрейма необходимо указать определенный URL-адрес. Вместо того чтобы выполнять дополнительные действия и загружать файл с пустым документом HTML, здесь для вызова функции используется конструкция javascript :URL. В данном примере возвращенное функцией значение (пустая страница HTML) должно передаваться в указанный фрейм (при этом оператор void не используется). Это наиболее эффективный способ создания пустого фрейма в наборе фреймов. <html> <head> <title>Our Solar System</title> <script type="text/javascript"> // определение метода function showPlanetO { var result = "<html><body><centerxtable border='2'>"; result += "<caption align='top'>Planetary data for: <b>" + this.name + "</bx/caption>"; result += "<trxtd align= ■ right* >Diameter :</tdxtd>" + this.diameter + "</tdx/tr>"; result += "<trxtd align='right' >Distance from Sun:</td> <td>" + this, distance + "</tdx/tr>"; result += "<trxtd align= 'right' >One Orbit Around Sun:</td> <td>" + this.year + "</tdx/tr>"; result += "<trxtd align='right • >One Revolution (Earth Time) :</tdxtd>" + this.day + "</tdx/tr>"; result + = "</tablex/centerx/bodyx/html>" ; // отображение результатов во втором фрейме окна parent.Frame2.document.write(result); parent.Frame2.document.close(); } // определение типа объектов планет;» // 'new' создает новый экземпляр и внедряет в объект данные function planet(name, diameter, distance, year, day) { this.name = name; this.diameter = diameter; this.distance = distance; this.year = year; this.day = day; this.showPlanet = showPlanet; // создание showPlanetO // как метода планеты } // создание объектов планет и сохранение их в переменных var Mercury = new planet("Mercury","3100 miles", "36 million miles", "88 days", "59 days"); var Venus = new planet("Venus", "7700 miles", "67 million miles", "225 days", "244 days"); var Earth = new planet("Earth", "7920 miles", "93 million miles", "365.25 days","24 hours"); var Mars = new planet("Mars", "4200 miles", "141 million miles", "687 days", "24 hours, 24 minutes"); var Jupiter = new planet("Jupiter","88,640 miles", "483 million miles", "11.9 years", "9 hours, 50 minutes"); var Saturn = new planet("Saturn", "74,500 miles", Глава 33. Функции и пользовательские объекты 1011
"886 million miles", "29.5 years", "10 hours, 39 minutes"); var Uranus = new planet("Uranus", "32,000 miles", "1.782 billion miles","84 years", "23 hours"); var Neptune = new planet("Neptune","31,000 miles", "2.793 billion miles","165 years", "15 hours, 48 minutes"); var Pluto = new planet("Pluto", "1500 miles", "3.67 billion miles", "248 years", "6 days, 7 hours"); // вызывается кнопкой и реализует метод объекта планеты function doDisplay(popup) { i = popup.selectedlndex; eval(popup.options[i].text + ".showPlanet()"); } </script> </head> <body> <hl>The Daily Planet</hl> <hr /> <form> <p>Select a planet to view its planetary data: <select name='planetsList' onchange='doDisplay(this)'> <option>Mercury</option> <option>Venus</option> <option selected="selected">Earth</option> <option>Mars</option> <option>Jupiter</option> <option>Saturn</option> <option>Uranus</option> <option>Neptune</option> <option>Pluto</option> </selectx/p> </form> </body> </html> В разделе head основная задача состоит в определении функции, которая будет представлять метод для каждого из объектов. Подобную операцию следует выполнять при создании каждого сценария, в котором функция выступает в роли метода. Если не определить функцию вначале, может возникнуть ошибка — имя функции не определено. Сравнивая этот метод извлечения данных с вариантом, в котором используется массив, обратите внимание, что в первом случае параметр для индекса не задается, а ссылка на каждое свойство начинается с ключевого слова this. Далее будет рассмотрен пользовательский метод; однако вначале мы разберемся с остальной частью кода раздела Head. Ниже описывается функция-конструктор объекта, в которой выполняется несколько важных задач. Во-первых, в этой функции полностью устанавливается структура пользовательского объекта: свойства, предназначенные для хранения данных и их поиска, и всевозможные методы, которые моячо вызвать из объекта. Имя функции— это название, которое позже используется для создания новых экземпляров объекта. Поэтому при выборе имени важно учитывать природу данного объекта. Вероятнее всего, вам понадобится занести некоторые данные в свойства. Чтобы иметь возможность обратиться к одному или нескольким экземплярам загруженного и готового к использованию объекта, в определении функции предусмотрены параметры для каждого свойства, определенного в объекте. Для присвоения определенному свойству значений, передаваемых в качестве параметров функции, применяется ключевое слово this. В этом примере для передаваемых переменных параметров и свойств используются одинаковые имена. Прежде всего это сделано в целях удобства (просто так принято). Вы можете назначать переменным и свойствам любые имена и обра- 1012 Часть IV. Объекты языка JavaScript
щаться к ним любыми известными способами. В функции-конструкторе planet () под экземпляры объекта зарезервировано пять разделов свойств, независимо от того, хранятся в свойствах какие-либо данные или нет (каждое неинициализированное свойство имеет значение null). Последний элемент в функции-конструкторе planet () — это ссылка на определенную ранее функцию showPlanet (). Обратите внимание, что в выражении присвоения при обращении к функции не используются круглые скобки — только имя функции. Когда в сценарии встречается подобное выражение, компилятор просматривает все существующие определения (эти функции определены выше в сценарии) и ищет соответствующее указанному имени. Если соответствующая функция находится (как это и происходит в данном примере), функция присваивается идентификатору, расположенному слева от выражения присвоения. При этом данный идентификатор автоматически служит именем метода указанного объекта. Как и для всех уже изученных методов JavaScript, при его вызове задается ссылка на объект, потом точка, а затем имя метода, сопровождаемое пустыми скобками. Ниже приводится соответствующий пример. В следующем блоке операторов, согласно определению, установленному в конструкторе planet (), создаются индивидуальные объекты. Как и в случае с массивами, новый объект создается с помощью оператора присвоения и ключевого слова new. В данном случае имена объектов удобны не только тем, что они представляют собой реальные названия планет (объект Mercury соответствует планете Меркурий), но и тем, что их можно использовать позже, когда с помощью функции doDisplay () из "всплывающего" меню будет извлечено название и потребуется найти соответствующие его объекту данные. При создании нового объекта в памяти для него и его свойств резервируется специальная область (связанная с текущим документом). В этом сценарии резервируется девять областей для объектов, в каждой из которых содержится собственный набор свойств. Обратите внимание, что в функцию метода showPlanet () не передается ни один параметр (в функции он не ожидается). Но в данном случае это очень удобно, так как при таком способе определения объектов метод автоматически присоединяется к каждой версии (экземпляру) созданного объекта планеты. Последнее определение функции doDi splay () вызывается всякий раз, когда пользователь выбирает элемент из списка планет в верхнем фрейме. Данная функция также вызывается с помощью обработчика событий onload набора фреймов, и начальная таблица отображается для выбранного по умолчанию элемента (см. рис. 33.1). Однако при вызове функции из обработчика событий onload верхнего фрейма могут возникнуть проблемы (сбой в другом фрейме), если документы фреймов полностью не загружены. В обработчике событий onchange для списка select в функцию doDi splay () передаются ссылки на элементы списка. В этой функции объект select присваивается переменной popup, позволяющей представить объект во всплывающем меню. В первом выражении определяется индекс выбранного элемента. С помощью этого индекса находится соответствующий ему текст. Однако возникает следующая трудность: эту текстовую строку нужно использовать как имя переменной — название планеты, а затем добавить ее в вызов метода showPlanet (). Для обработки несоизмеримых типов данных используют функцию eval (). Далее в круглых скобках указывается строка для названия планеты, которая объединяется со ссылкой на метод showPlanet (). В функции eval () обрабатывается та строка, которая преобразуется в правильный вызов метода. Таким образом, если пользователь выбирает из всплывающего меню Jupiter, метод вызывается с помощью ссылки Jupiter. showPlanet (). Далее мы рассмотрим определение функции/метода showPlanet (), заданное в начале сценария. При вызове этого метода в ответ на выбранную пользователем планету Jupiter единственной областью рассмотрения метода становится объект Jupiter. Таким образом, с помощью ссылок на this .propertyName в showPlanet () можно обратиться только к Jupiter. Существует один способ использовать this.name в этом объекте— присвойте свойству name значение Jupiter. Аналогично можно обратиться к остальным свойствам, определенным в данной функции/методе. Глава 33. Функции и пользовательские объекты 1013
щущтящтщтгшшшшшштшшшшш^штщтнштттттщтяттт Fife Edtt Vfew FwmIMi T*ol* H*ip . Ом • О - id III Ыр*~* i**» ♦■* #! 0'%-.»:> OB-"***: The Daily Planet Select a planet to view its planetary data: [ Mjm^ HI Planetary data for: Man Diameter i4200 miles Distance from Sua (141 million miles One Orbit Around Sun: J687 days One Revolution (Earth Time): j24 hours, 24 minutes Puc. 33. J. Вводимые и выводимые данные для описанного выше приложения Создание массива объектов В листинге 33.6 каждый объект планеты присваивается глобальной переменной, название которой соответствует "его" планете. При знакомстве с методиками пользовательских объектов этот принцип позволяет эффективно решить поставленные задачи, поскольку в данном случае представить переменную, соответствующую определенному объекту, предельно просто. Как можно убедиться на примере функции doDisplay (), при обращении к объекту по имени необходимо использовать функцию eval (), чтобы преобразовать строковое представление имени в допустимую ссылку на объект. Несмотря на то, что в данном простом примере это и не слишком важно, функция eval () не является сильной стороной JavaScript. Поэтому, вместо функции eval () рекомендуется найти способы обращения к объекту, в которых бы использовалось строковое значение. Одним из таких способов для данного приложения является помещение объектов в массив, индексы которого представляют названия планет. Для того чтобы присвоить пользовательские объекты массиву в листинге 33.6, сначала создают пустой массив, а затем каждому элементу массива присваивают результат вызова конструктора объекта. Измененный фрагмент программы выглядит следующим образом. // Создание массива var planets = new Array(); // "заполнение" массива новыми объектами планеты planets["Mercury"] = new planet("Mercury","3100 miles", "36 million miles", "88 days", "59 days"); planets["Venus"] = new planet("Venus", "7700 miles", "67 million miles", "225 days", "244 days"); planets["Earth"] = new planet("Earth", "7920 miles", "93 million miles", "365.25 days","24 hours"); planets["Mars"] = new planet("Mars", "4200 miles", 1014 Часть IV. Объекты языка JavaScript
"141 million miles", "687 days", "24 hours, 24 minutes"); planets["Jupiter"] = new planet("Jupiter ","88,640 miles", "483 million miles", "11.9 years", "9 hours, 50 minutes"); planets["Saturn"] = new planet("Saturn", "74,500 miles", "886 million miles", "29.5 years", "10 hours, 39 minutes"); planets["Uranus"] = new planet("Uranus ", "32,000 miles", "1.782 billion miles","84 years", "23 hours "); planets["Neptune"] = new planet("Neptune","31,000 miles", "2.793 billion miles"/"165 years", "15 hours, 48 minutes"); planets ["Pluto"] = new planet("Pluto", "1500 miles", "3.67 billion miles", "248 years", "6 days, 7 hours"); Наиболее существенное преимущество такого подхода демонстрируется в измененной функции doDisplay (), в которой строковое значение элемента select используется непосредственно, без преобразования в ссылку на объект. // Вызов метода объектов планет при щелчке на кнопке function doDisplay(popup) { i = popup.selectedlndex; planets[popup.options[i].text].showPlanet(); } Сам факт использования такого количества подобных объектов должен наводить на мысль о хранении их в виде массива. По причине того, что в данном приложении названия напрямую используются при выборе этих объектов, то подойдут имена элементов массива; в других случаях можно использовать числовые индексы, что упрощает выполнение операций цикла для массива. Добавление пользовательских методов В этом разделе описывается дополнительная возможность определения и применения пользовательских объектов. В пользовательском объекте в виде свойства может содержаться ссылка на другой пользовательский объект. Воспользуемся данной возможностью в рассмотренном выше примере. Допустим, необходимо добавить на страницу фотографии планет. Каждая фотография имеет свой URL, указывающий расположение файла фотографии; для каждой фотографии представлена дополнительная информация, в частности сведения об авторских правах и номер ссылки, который выводится для пользователя на странице. Один из способов обработки подобной информации заключается в создании отдельного определения объекта для базы данных фотографий. Такое определение может выглядеть следующим образом. function photo(name, URL, copyright, refNum) { this.name = name; this.URL = URL; this.copyright = copyright; this.refNum = refNum; } После этого для каждого изображения необходимо создать индивидуальный объект f о to. Ниже приведен пример одного из определений. mercuryPhoto = new photo("Planet Mercury", /images/merc44.gif", " (c)1990 NASA", 28372) ; Чтобы добавить объект f oto в объект planet необходимо описать в функции-конструкторе planet еще одно свойство. Тогда обновленный конструктор planet будет выглядеть следующим образом. function planet(name, diameter, distance, year, day, photo) { this.name = name; this.diameter = diameter; Глава 33. Функции и пользовательские объекты 1015
this.distance = distance; this.year = year; this.day = day; this.showPlanet = showPlanet; this.photo = photo; /■/ Добавленное свойство photo } После создания объектов f oto объект planet можно создать, передав еще один параметр, — объект f oto, который необходимо связать с этим объектом. // Создание нового объекта planet и хранение в нем переменных Mercury = new planet("mercury","3100 miles", "36 million miles", "88 days", "59 days", mercuryPhoto); Чтобы обратиться к свойству объекта f oto, придется указать ссылку, которая необходима для обращения к объекту р 1 ane t. copyrightData = Mercury.photo.copyright; Пользовательские объекты этого типа имеют огромный потенциал. Например, можно внедрить все копии элементов и URL-адреса изображений сетевого каталога в один документ. Поскольку пользователь выбирает элементы для дальнейшего отображения на экране (просматривает их в определенной последовательности), на обновленной странице JavaScript информация выводится моментально. Для этого нужно загрузить изображение, если оно не загружено предварительно, как описывается в главе 18. В последнем случае вся работа производится мгновенно, без ожидания загрузки следующей страницы каталога. Если вы как начинающий программист замечаете сходство между конструкцией "объект в объекте" и реляционной базой данных, то у вас великое будущее. Для нескольких объектов можно задавать один и тот же подобъект, подобно свойству. Такая ситуация напоминает деловые контакты, представленные для одной компании. Несколько дополнительных способов создания объектов В листингах 33.5 и 33.6 используются способы создания объектов, совместимые со всеми браузерами, поддерживающими сценарии. Но существует несколько дополнительных способов, предназначенных для тех, кто пользуется более современными версиями браузеров. Начиная с NN3+ и IE4+, для генерирования пустого объекта можно использовать конструктор new Ob j ect (). Просто присвойте имена свойствам и методам, как показано ниже. var Earth = new Object(); Earth.diameter = "792 0 miles"; Earth.distance = "93 million miles"; Earth.year = "365.25"; Earth.day = "24 hours"; Earth.showPlanet = showPlanet; // ссылка на функцию При создании похожих по структуре объектов, наиболее эффективно будет применяться пользовательский конструктор, приведенный в листинге 33.6. Но для отдельных объектов лучше подойдет конструктор new Ob j ect (). Для создания нового объекта можно воспользоваться сокращенными буквенными названиями. В таких случаях указывают пары имен свойств и их значений, заключенные в фигурные скобки. Таким образом можно присвоить целую конструкцию переменной, которая в дальнейшем будет выступать именем определенного объекта. Ниже приведен пример подобного конструктора объекта. var Earth = {diameter:"7920 Milis", distance:"93 million miles", year:"365.25", day:"24 hours", showPlanet:showPlanet}; 1016 Часть IV. Объекты языка JavaScript
Для разделения пары имя-значение используется двоеточие, а для разделения самих пар между собой — запятые. Часть значения пары имя-значение может быть представлена массивом (для этого используют такую структуру конструктора, как [...]) или вложенными объектами (необходим еще один набор фигурных скобок). Для создания многократно вложенных объектов можно применить и вложенные массивы, и объекты. В целом, это очень компактный способ внедрения данных в страницу для дальнейшего управления ими из сценария. Если знания CGI, XML и навыки в работе с базами данных не позволяют решить поставленную задачу, используйте серверные программы для преобразования данных XML в следующую компактную структуру JavaScript: каждая запись XML является собственным объектом JavaScript. Для большого количества записей присвойте определения объектов, заключенные в фигурные скобки, элементам массива. Тогда при выполнении сценариев на стороне клиента будет производиться итерация данных и генерироваться документ HTML для вывода данных в различных форматах (согласно установленным критериям и порядку сортировки). Определение в объекте получателя и определителя свойства В следующей версии спецификации языков ЕСМА-262, вероятно, будут описаны так называемые получатели и определители свойств. Но пока формальный синтаксис этих возможностей окончательно не определен, данную методику можно начинать исследовать только в NN6, используя временный синтаксис, который наиболее приближен к вероятному формату (в данном методе будут использоваться различные ключевые слова, пока не утвердят стандарт). Как только стандарт будет принят, уже в следующей версии Netscape Navigator начнут использовать стандартные ключевые слова. В главе 14 уже шла речь о создании получателей и определителей объекта. В этой главе был описан расширенный синтаксис свойств NN6 некоторых объектов W3C DOM, в котором также использовалась определенная доля синтаксиса DOM, представленного разработчиками Microsoft (причем очень удобного). Получателя можно определить для любого контейнера, чтобы возвратить массив вложенных элементов аналогично document .all, используемому только в Internet Explorer. Цель получателя состоит в присвоении нового свойства прототипу объекта и определении способа оценки возвращаемого свойством значения. Определитель используется для того же, но при этом с его помощью задается способ применения к объекту значения, присвоенного свойству. Оба определения написаны в форме анонимных функций таким образом, чтобы при чтении или записи значения свойства объекта можно было проводить обработку данных любой сложности. Получатели и определители присваиваются свойству prototype объекта, таким образом, у программиста появляется возможность настраивать объекты DOM и исходные объекты JavaScript. В NN6 для получателей, определителей и методов прототипа объекта используется следующий синтаксис. объект.prototype. defineGetter {"имя", function) объект.prototype. defineSetter {"имя", function) Заметьте, что символы подчеркивания, расположенные до и после имени метода, состоят из двух символов (т.е. _, _, def ineGetter, _, _). Это двойное подчеркивание определено в синтаксисе, который не будет использоваться в стандарте ЕСМА. В результате исчезнут конфликты с возможным будущим синтаксисом, используемым в этой технологии. Первым параметром метода является имя свойства, для которого определен получатель или определитель. Это может быть уже существующее имя свойства, в старом значении которого больше нет необходимости. Вторым параметром может быть ссылка на функцию; но, скорее всего, это будет анонимная функция, определенная в текущем месте кода. Используя Глава 33. Функции и пользовательские объекты 1017
анонимную функцию, можно получить преимущества текущего состояния объекта, для которого определено свойство. Для каждого свойства задайте и получателя, и определителя, даже если оно предназначается Только для чтения или только для записи. Для1 того чтобы лучше разобраться в работе данного механизма, рассмотрим получатель и определитель, используемые в главе 14 для добавления свойства innerText к элементам HTML в NN6+. Это свойство предназначено как для чтения, так и для записи, поэтому функции заданы и для получателя, и для определителя. Задание получателя выполняется следующим образом. HTMLElement.prototype. defineGetter ("innerText", function () { var rng = document.createRange(); rng.selectNode(this); return rng.toStringO ; }) В данном примере изменяется основной объект HTMLElement — объект, который в NN6 используется для создания экземпляра каждого элемента HTML на странице. После выполнения вышеописанной инструкции каждый элемент HTML на странице наследует новое свойство innerText. При чтении свойства innerText для определенного элемента вызывается анонимная функция в соответствующем получателе. Таким образом, после создания объекта текстового диапазона диапазон определяется узлу, который является текущим элементом. Это превосходный пример того, как в контексте текущего объекта можно использовать ключевое слово this для обращения к этому же объекту. В результате возвращается строковая версия выбранного диапазона. Необходимо, чтобы в функции получателя содержался оператор return и возвращенное значение имело требуемый тип данных. Обратите внимание на закрытие фигурных скобок функции и круглых скобок метода получателя. При выполнении данной функции (при каждом чтении свойства) с помощью получателя всегда возвращается текущее состояние объекта. Если со времени загрузки страницы содержимое элемента изменилось, пользователь может быть уверен, что он получает текущий текст элемента. Эта операция намного сложнее простого выполнения операторов функции т.ри загрузке страницы для определения статического представления текста элемента. Соответствующий определитель задается следующим образом. HTMLElement.prototype. defineSetter ("innerText", function (txt) { var rng = document.createRange(); rng.selectNodeContents(this); rng.deleteContents(); var newText = document.createTextNode(txt); this.appendChild(newText); return txt; }) Чтобы присвоить значение свойству объекта, нужное значение необходимо передать в переменную параметра. Такая переменная указывается в определении функции. Для рассматриваемого определителя текущий объект (this) также управляет объектом текстового диапазона. Содержимое текущего элемента удаляется, и текстовый узел, состоящий из переданного в качестве параметра текста, вставляется в элемент. Чтобы полностью обеспечить соответствие процедуре установки свойства innerText в Internet Explorer, текст возвращается. Обычно определители не возвращают значения, однако в данном примере в выражении присвоения значения свойству innerText ему определяется новый текст. Если необходимо создать свойство, предназначенное Только для чтения, следует настроить определитель для свойства, но при этом присвоить ему пустую функцию, как показано ниже. node.prototype. defineSetter ("all", function() {}) Это предотвращает появление ошибок в выражении присвоения значения свойству, предназначенному Только для чтения. Свойство, предназначенное для записи, должно иметь получателя, который возвращает null или пустую строку. 1018 Часть IV. Объекты языка JavaScript
HTMLElement.prototype. defineGetter ("outerHTML", function() {return ""}) Так как показанный синтаксис для получателя и определителя используется только в NN6, вам необходимо в точности следовать выражениям определения объекта или выражениям определения, принятым для данной версии браузера. Не забывайте, что этот синтаксис изменится в будущих версиях браузеров, как только в ЕСМА будет принят формальный стандарт вышеописанного метода. Применение пользовательских объектов Не требуются особые знания для того, чтобы определить, когда вместо массива следует воспользоваться собственным объектом. Чем больший опыт работы с пользовательскими объектами, тем легче разобраться в принципе их действия. Следовательно, более опытные программисты проектируют свои сценарии уже с учетом данной возможности, особенно, если в объекте можно использовать один или несколько методов, с ним связанных. Это, конечно, не обязательно делать начинающим программистам, но если у вас уже есть определенный опыт работы с JavaScript, рекомендуется прочесть все, что относится к пользовательским объектам, причем не один раз. Концепция объектно-ориентированного программирования Как уже отмечалось, язык JavaScript, скорее, основан на объектах, чем является объектно- ориентированным. Вместо соблюдения схемы классов, подклассов и принципов наследования (как в объектно-ориентированных языках например, Java), в JavaScript используется то, что называется наследованием прототипа. Подобная схема применима не только к исходным объектам JavaScript или объектам DOM, ее также можно применять и для пользовательских объектов. Добавление прототипа Пользовательский объект часто определяется в функции-конструкторе, с помощью которой начальные Значения обычно распределяются по свойствам объекта (как в следующем примере). function car(plate, model, color) { this.plate = plate; this.model = model; this.color = color; } var carl = new carC'AB 123", "Ford", "blue"); В NN4+, Ш4+ и W3C можно по умолчанию присвоить значения свойствам, если ни одно из них значением не обеспечивается (null, 0 или пустая строка). С помощью оператора ИЛИ (| |) вы присвоите свойству переданное значение, если таковое существует, или значение, установленное в конструкторе по умолчанию. Таким образом, вы можете изменить предыдущую функцию, чтобы присвоить свойствам значения по умолчанию. function car(plate, model, color) { this.plate = plate || "missing"; this.model = model jj "unknown"; this.color = color j| "unknown"; } var carl = new carC'AB 123", "Ford", ""); Глава 33. Функции и пользовательские объекты 1019
После того, как будут выполнены предыдущие выражения, значения свойств объекта carl станут следующими. carl.plate // значение = "АВ 123" carl.model // значение = "Ford" carl.color // значение = "unknown" Если после этого прибавить к свойству prototype конструктора новое свойство car.prototype.companyOwned = true; любой объект автомобиля, как созданный, так и не созданный, автоматически наследует новое свойство companyOwned и соответствующее ему значение. При этом для любого определенного объекта саг. значение свойства companyOwned можно отменить. Но если этого не сделать, объекты саг, свойство companyOwned которых не отменено, автоматически будут наследовать любое изменение значения prototype. companyOwned. Таким образом в JavaScript определяются значения свойства prototype. Наследование прототипа Каждый раз при чтении или записи свойства объекта в JavaScript проводится проверка соответствий для данного имени свойства, причем осуществляется она в определенной последовательности. Такая последовательность имеет следующий вид. 1. Если свойство имеет значение, присвоенное текущему (локальному) объекту, это значение можно использовать. 2. Если не имеется никакого локального значения, проверьте значение прототипа свойства конструктора объекта. 3. Структура прототипа просматривается до тех пор, пока не будет найдено соответствие свойству (со значением, ему присвоенным) либо найден "родной" объект Ob j ect. Поэтому при изменении значения свойства prototype конструктора не отменяйте значение свойства в экземпляре этого конструктора — тогда будет возвращено текущее значение свойства prototype конструктора. Вложенные объекты и наследование прототипа Для тех, кто только начинает использовать вложенные объекты, следует научиться обращать внимание на специфические ситуации, подобные тем, когда в одном объекте вызывается конструктор другого. Рассмотрим все тот же объект саг, определенный ранее. В этом сценарии считается, что объект саг является родственным корневому объекту, свойства которого общедоступны двум другим типам объектов. Один из них — транспортное средство флота компании, которое обладает свойствами корневого объекта car (plate, model, color), а также некоторыми собственными свойствами. Второй объект, в котором вновь используется объект саг, представляет автомобиль, припаркованный в гараже компании. Этот объект имеет дополнительные свойства, описывающие параметры парковки транспортных средств. Этим объясняется тот факт, что объект саг определен сам в себе. Теперь рассмотрим функцию-конструктор для записи сведений о парковке и конструктор основного объекта саг. function car(plate, model, color) { this.plate = plate || "missing"; this.model = model jj "unknown"; this.color = color jj "unknown"; 1020 Насть IV. Объекты языка JavaScript
} function carlnLot(plate, model, color, timeln, spaceNum) { this.timeln = timeln; this.spaceNum = spaceNum; this.carlnfo = car; this.carlnfо(plate, model, color); } В конструкторе carlnLot не только присваиваются значения соответствующим уникальным свойствам (timeln и spaceNum), в нем также содержится ссылка на конструктор саг, присвоенная свойству carlnf о. Это присвоение ссылки^свойству является простейшим способом, с помощью которого значения свойства, предназначенные для конструктора саг, можно передать в функцию-конструктор carlnLot. Для создания объекта carlnLot используйте следующее выражение. var carl = new carlnLot("АА 123", "Ford", "blue", "10:02AM", "31"); После выполнения этого выражения значения свойств объекта carl будут следующими. carl.timeln // значение = "10:02АМ" carl.spaceNum // значение = "31" carl.carlnfо // значение = ссылка на конструктор объекта саг carl.plate // значение = "АА 123" carl.model // значение = "Ford" carl.color // значение = "blue" В данном случае можно сказать, что было создано пять объектов carlnLot (с carl по саг5). "Прототипность" проявляется, если, например, назначить новое свойство прототипу конструктора саг. car.prototype.companyOwned = true; Даже при том, что в объектах carlnLot используется конструктор саг, из экземпляров объектов carlnLot нельзя обратиться к объекту саг как к прототипу. Так как код остается прежним (даже при том, что в конструктор саг было добавлено свойство companyOwned), ни один объект carlnLot не наследует это свойство (даже если создать новый объект carlnLot после определения нового свойства prototype для саг). Чтобы экземпляры carlnLot могли наследовать свойство prototype. companyOwned, необходимо явно подключить прототип конструктора carlnLot к конструктору саг создания экземпляров объектов carlnLot. carlnLot.prototype = new car(); В конечном счете последовательность действий будет выглядеть следующим образом. function car(plate, model, color) { this.plate = plate || "missing"; this.model = model jj "unknown"; this.color = color jj "unknown"; } function carsInLot(plate, model, color, timeln, spaceNum) { this.timeln = timeln; this.spaceNum = spaceNum; this.carlnfo = car; this.carlnfo(plate, model, color); } carsInLot.prototype = new car(); var carl = new carsInLot("123ABC", "Ford","blue","10:02AM", "32") car.prototype.companyOwned = true; После выполнения кода этого фрагмента значения свойств объекта carl будут следующими. carl.timeln // значение = "10;02АМ" carl.spaceNum // значение = "31" Глава 33. Функции и пользовательские объекты 1021
carl.carlnfo // значение = ссылке на конструктор саг carl.plate // значение = "АА 123" carl.model // значение = "Ford" carl.color // значение = "blue" carl.companyOwned ■// значение = true Разработчики NN4+ добавили в этот браузер расширение синтаксиса прототипа. Это свойство proto (при его введении задается двойное подчеркивание до и после слова proto), в котором возвращается ссылка на следующий в последовательности прототипов объект. Например, если свойства carl. proto вызываются после выполнения предыдущих операторов, можно увидеть, что значения свойств следующего объекта прототипа такие. carl. proto .plate // значение = "АА 123" carl. proto .model // значение = "Ford" carl. proto .color // значение « "blue" carl. proto .companyOwned // значение = true Это свойство применяется при отладке пользовательских объектов и вызовов цепочки наследования прототипов, но оно не является стандартом ЕСМА, Поэтому не рекомендуется использовать его в своих сценариях. Объект Object Свойства Методы constructor hasOwnProperty() prototype isPrototypeOf() propertylsEnumerable() toLocaleString() toStringO valueOf() Синтаксис Создание объекта Ob j ect. function имяКонструктора([aprl,... [,aprtf] ]) { оператор (ы) } var имяОбъекта = new имяКонструктора(["aprl", ...[,"aprN"]); var имяОбъекта= new Object(); var имяОбъекта = {свойство!:значение![, свойство2:значение2[, ...N] }} Доступ к свойствам и методам объекта Ob j ect. ссылкаНаОбъект.свойство\метод{ [параметры] ) Совместимость: WinIE4+, МасШ4+, NN3+, Mozl+, Safari 1+ Описание объекта Такое имя объекта представляет собой некоторую тавтологию, но, несмотря на это, в среде JavaScript объект Ob j ect является одним из наиболее важных. Это корневой объект, на котором базируются все остальные объекты JavaScript — Date, Array, String и т.п. Ob j ect также используется для создания пользовательских объектов (см. ранее в данной главе). 1022 / Часть IV. Объекты языка JavaScript
В принципе, никто не обращается к свойствам объекта Ob j ect. To же самое можно сказать и о многих его методах (toString () и valueOf ()), с помощью которых можно производить отладку в диалоговых окнах предупреждения (и в приложении The Evaluator). Такие окна предназначены для вывода нужной информации при обращении к объекту или его конструктору. Далее описываются наиболее популярные методы, которые используются для анализа среды прототипа экземпляра объекта. Прежде всего эти методы необходимы более опытным программистам, которые в своих сценариях используют мощную технологию моделирования объектно-ориентированных приложений. Методы hasOwnProperty (" свойство") Возвращаемое значение: булево Совместимость: WinIE5.5+, МасШ-, NN6+, Mozl+, Safari- Метод hasOwnProperty () возвращает true, если текущий экземпляр объекта обладает свойством, определенным в конструкторе или в соответствующей функции-конструкторе. Если это свойство определяется внешне (например, в результате присвоения ему свойства prototype объекта), метод возвращает false. Если использовать пример объектов саг и carlnLot, описанный ранее в этой главе, следующие выражения примут истинное значение. carl.hasOwnProperty("spaceNum"); carl.hasOwnProperty("model"); Даже при том, что свойство model определяется в конструкторе, который вызывается в другом конструкторе, оно соответствует объекту carl. Однако следующее выражение принимает значение false. carl.hasOwnProperty ("companyOwned"); Это свойство определяется для прототипа одной из функций-конструкторов и не является свойством, встроенным в экземпляр объекта. isPrototypeOf (ссылкаНаОбъект) Возвращаемое значение: булево Совместимость: WinIE5.5+, Macffi-, NN6+, Mozl+, Safari- Метод isPrototypeOf () предназначен для определения того, является ли объект, переданный в качестве параметра, прототипом текущего объекта. На практике версии этого метода в ГЕ и NN/Moz не только по-разному функционируют — они вообще не используются ни в одном браузере для корректного определения зависимости между объектами. proper ty Is Enumerable (" свойство") Возвращаемое значение! булево Совместимость: Winffi5.5+, MacIE-, NN6+, Mozl+, Safari- B терминологии спецификации ЕСМА-262 значение перечисляемо, если его можно корректно использовать в таких конструкциях, как цикл проверки свойств for-in (глава 31). В перечисляемых свойствах могут храниться значения массивов, строк и, фактически, любые объекты. Если принять во внимание спецификацию ЕСМА, данный метод не должен работать по принципу прототипов. Глава 33. Функции и пользовательские объекты 1023
Глобальные функции и выражения дополнение ко всем объектам и позаимствованным из других языков конструкциям, которые были описаны в предыдущих главах этой книги, некоторые элементы языка необходимо рассмотреть более детально. Эти элементы не предназначены для определенных объектов (или объектов вообще), поэтому их можно использовать в любой части сценария. Большинство этих функций и выражений уже использовались в приведенных листингах программ. В данной главе перечислены все существенные элементы, о которых легко забыть. В заключительной части главы приводится краткое описание объектов, которые встроены в Internet Explorer и предназначены только для использования в Windows. Более полную информацию вы найдете на информационном узле Microsoft. Прежде всего рассмотрим следующие глобальные функции и выражения, которые используются в языке JavaScript. Функции Выражения decodeURi О //и /*■... */ (комментарии) decodeURIComponent() const encodeURI() var encodeURIComponent() escape() evalO isFinite() isNaNO Number() parseFloat() parselnt() toStringO unescape() unwatch() watch()
Глобальные функции не связаны с объектной моделью документа. Наоборот, обычно их используют для преобразования данных одного типа в другой. Существует незначительно количество глобальных выражений, однако некоторые из них используются практически в каждом сценарии. Функции decodeURI (" кодировнныйит") decodeURI Component ("элементКодированногоит*) encodeURI (п строкаиш") encodeURI Component (пэлементишп) Возвращаемое Значение: строка Совместимость: Winffi5.5+, MacIE-, NN6+, Mozl+, Safari- В третьем издании стандарта ЕСМА-262, которому соответствуют Ш5.5+, NN6+ и Mozilla, описываются вспомогательные функции, которые используют для более строгого преобразования строк в допустимое строковое представление URI и наоборот. Раньше для этих операций применяли функции escape () и une scape () (они описываются далее в этой главе). Функции кодировки предназначены для преобразования любой строки в форму, которую можно использовать как универсальный идентификатор ресурса (Uniform Resourse Identifier — URI), например, адрес Web-страницы или ссылка на CGI-сценарий сервера. В отличие от латинских буквенно-цифровых символов, которые не изменяются при кодировке, в функции кодировки допустимо использовать как обычные символы, так и символы Unicode. Впоследствии они преобразуются в шестнадцатеричную форму (шестнадцатеричные числовые значения символов), которая применяется для использования в Internet. Символ "пробел", например, в шестнадцатеричном коде имеет значение %20. Возможно, наиболее существенная разница между функциями encodeURI () и escape () (и, соответственно, decodeURI () и une scape ()) состоит в том, что в последних версиях браузеров большинство символов не кодируется, хотя они и соответствуют синтаксису URI, рекомендованному в RFC2396 (http: // www. ietf. org/rf c/rf c2396 . txt). Из этого вытекает, что следующие символы нельзя кодировать с помощью функции encodeURI (). ;/?:&- + $,-_.!-*■()# Функции encodeURI () и decodeURI () используются только для уже полученных URI. URI могут быть относительными и абсолютными, но эти две функции разработаны так, что символы, которые применяются при указании протокола (://), строки поиска (например, ? и =) или уровня каталога (/), не кодируются. Функция decodeURI () предназначена для обработки URI, поступающих с серверов в виде ссылок на страницы. Однако помните, что CGI- программы некоторых серверов кодируют пробел как символ "плюс" (+), который нельзя декодировать в пробел с помощью функций JavaScript. Если в URI, который необходимо декодировать, вместо пробелов содержатся символы "плюс", к этому декодированному URI следует применить метод замены строк (в данном случае могут использоваться обычные строковые выражения). Для строк URI применяйте только те функции декодирования, которые соответствуют функциям, используемым при их кодировании. Не пытайтесь декодировать URI, созданный с помощью старой функции методом escape О, так как не все методы преобразования, используемые в нем, соответствуют современным правилам. Глава 34. Глобальные функции и выражения 1025
Разница между URI и элементом URI состоит в том, что элемент является отдельной частью URI, в которой не содержатся символы-разделители. Например, при использовании функции encodeURIComponent () для полученного URI почти все символы (кроме точек) кодируются в шестнадцатеричный вид, включая разделители каталогов. Поэтому функции преобразования элементов следует использовать только для отдельных фрагментов URI. Например, при обработке строки поиска, в которой содержится пара имя-значение, функцию encodeURI Component () можно использовать отдельно для имени и отдельно для значения. Но если эту функцию применить к паре, которая уже имеет вид имя= значение, в ше- стнадцатеричном эквиваленте также будет преобразован символ равенства. Пример Попробуйте поэкспериментировать в приложении The Evaluator (глава 13) и найти различия между кодированием полного URI и его элементов, а также кодированием и преобразованием строки URI с помощью метода escape (). Например, сравним результаты следующих трех выражений. escape("http://www.giantco.com/index.html?code=42M) encodeURI("http://www.giantco.com/index.html?code=42") encodeURIComponent("http://www.giantco.com/index.html?code=42") Указанная строка URI является допустимой для обработки, поэтому после запуска функции encodeURI () не происходит никаких изменений. Далее из строки поиска создайте строку, в которой содержится "пробел", и посмотрите, как этот символ будет обрабатываться каждой из функций. escape (" crpoicaURI" [, 1] ) unescape ("преобрСтрокаиШ") Возвращаемое значение! строка Совместимость: Winffi3+, MacIE3+, NN2+, Mozl-f, Safari- В поле адреса браузера часто можно увидеть URL, в котором содержится много символов % и чисел. Данный формат представляет собой кодированный URL (а точнее, кодированный URI). В этом формате можно отправлять большое количество слов и неалфавитно-цифровых символов в виде одной непрерывной строки, состоящей из ограниченного набора общепринятых символов. При подобном кодировании в шестнадцатеричном представлении таких символов, как пробел, первым указывается символ процента. Например, шестнадцатеричное значение пробела — 20 (значение ASCII — 32), а в закодированном виде — %2 0. Следовательно, таким образом можно кодировать все символы, включая символы табуляции и перехода на другую строку, и передавать их как простую строку, которую легко декодировать и изменять на стороне приемника. Также этот способ можно использовать для предварительной обработки большого количества строк текста, которые необходимо сохранить в виде одной строки символов в базах данных. Для кодирования строк обычного текста используйте метод escape (). Эта функция возвращает уже закодированный вариант введенного текста. var theCode = escape("Hello there"); // результат: "Hello%20there" He все (хотя многие) неалфавитно-цифровые символы конвертируются с помощью функции escape (). Исключением составляет знак "плюс", который используется в URL для разделения отдельных частей строки поиска. Если необходимо закодировать символ "плюс", следует указать для функции второй необязательный параметр — тогда этот символ будет преобразован в шестнадцатеричный код (2В). 1026 Часть IV. Объекты языка JavaScript
var a = escape ("Adding2+2") ; // результат: "Adding%202+2 var a = escape("Adding2+2",1); // результат: "Adding%202%2B2 Для декодирования полученной строки используют функцию unescape (). Она возвращает строку и преобразует все закодированные URL-строки, включая те, которые были закодированы с использованием необязательного параметра. В работе функция escape () напоминает сразу две более новые функции encodeURI () и encodeComponentURI (). Функцию escape () рекомендуется использовать для фрагментов URI (чаще всего это могут быть строки поиска). Если при выполнении сценария на этапе декодирования строк происходит сбой, проверьте, все ли функции, используемые для преобразования, одного типа; функцию unescape () применяйте только для строк URI, закодированных функцией escape (). / И наконец, вам следует знать о некоторых отличиях, которые имеют место при обработке символа @ в различных браузерах. Данный символ нельзя закодировать в Ш, хотя в NN он преобразуется в значение %40. eval (и строка") Возвращаемое значение: строка Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safari 1+ Выполнение выражения, как может заметить любой программист, является довольно важной операцией при написании сценария JavaScript (и программировании вообще). Выражение принимает некоторое значение. Однако иногда для получения определенных результатов с помощью выражения необходимо получить другое значение. Функция eval () преобразует строку таким образом, что в сценарии она расценивается, как выполняемое выражение. Пример С помощью функции eval () можно изменить значение любой инструкции или выражения JavaScript, сохраненных в виде строки. Это касается строковых эквивалентов арифметических выражений, присвоения значений объектам и обращения к методам объектов. Однако не рекомендуется часто использовать данную функцию, так как она не всегда эффективна. К счастью, для перехода от строкового имени объекта к допустимой ссылке на объект функция eval () не требуется. .Например, если в циклах сценария обрабатывается некоторое количество объектов, в именах которых используются последовательные номера, вместо того, чтобы вызвать функцию eval () для получения ссылки на объект, применяются имена объектов в качестве индексов массива. Самый неэффективный способ управления полями с именами dataO, datal и т.д. приведен ниже. function fillFieldsO { var theObj; for (var i = 0; i < 10; i++) { theObj = eval("document.forms[0].data" + i); theObj.value = i; } } Более эффективный способ — это выполнение конкатенации в скобках индекса массива. function fillFieldsO { for (var i = 0; i < 10; i++) { document.forms[0].elements["data" + i].value = i; Глава 34. Глобальные функции и выражения 1027
Перед тем, как вызвать функцию eval (), попробуйте найти способ примене- Сомт ния строкового значения индекса массива объектов. В стандарте W3C DOM л обращение к объектам можно осуществить еще проще — с помощью метода *Ш document.getElementByidO , в котором строка передается как параметр, и в результате возвращается ссылка на нужный объект. isFinite(тесло) Возвращаемое значение: булево Совместимость: WinIE4+, MacIE4+, NN4+, Mozl+, Safari 1+ Функцию isFinite () практически никто и никогда не использует. Однако следует отметить, что ее предназначение состоит в определении того, находится ли некоторое число в диапазоне допустимых для обработки в JavaScript значений. Если число не принадлежит этому диапазону, функция возвращает false. Параметр функции должен иметь числовой тип данных. i sNaN (выражение) Возвращаемое значение: булево Совместимость: Winffi3+, Macffi3+, NN2+, Mozl+, Safaril+ Для экземпляров, в которых выполняются арифметические операции с данными, поступающими из текстовых полей или других источников строковых значений, рекомендуется проверить, является ли полученное значение числом. Если значение числом не является, то при выполнении определенных вычислений может возникнуть ошибка. Пример Для предварительной проверки обрабатываемых значений используйте функцию isNaN (). Наиболее часто ее вызывают для проверки результата выполнения функций parselntO и parseFloat (). В ситуации, когда строковые значения, предназначенные для обработки в этих функциях, не могут быть преобразованы в числовые, результатом будет значение NaN (специальный символ, обозначающий "не является числом")- Таким образом, если значение не является числом, функция isNaN () возвращает true. Следовательно, эту функцию используют для выявления несовместимости данных перед выполнением с ними необходимых операций. function calc(form) { var inputValue = parselnt (form.entry.value) ,- if (isNaN(inputValue)) { alert("You must enter a number to continue."); } else { операторы вычисления Наиболее распространенная ошибка программистов при использовании данной функции состоит в том, что не все в точности соблюдают указанный регистр символов в ее имени. Часто пропускают верхний регистр в символе N. Number (" строка") parseFloat (п строка11) parselnt("строка" [, основа]) Возвращаемое значение: числовое Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safaril+ 1028 Часть IV. Объекты языка JavaScript
Все три функции предназначены для преобразования строкового значения в числовое. Функции parselnt () и parseFloat О совместимы с любыми версиями браузеров, в отличие от функции Number (), применяемой только в NN4 и Ш4. Функцию Number () используют в случаях, когда не требуется особая точность, и значение, полученное из текстового поля, обрабатывается независимо от того, принадлежит оно к типу чисел с плавающей запятой или к целым числам. В функцию передается единственный параметр — это строка, которую необходимо преобразовать в числовое значение. С помощью функции parseFloat () можно определить тип возвращенного значения: float или integer. Если в полученной строке содержится любое дробное ненулевое значение, результатом является "число с плавающей запятой". Но если строковое значение, к примеру, имеет вид 3.00, возвращается "целочисленное значение". Указав дополнительный параметр в parselnt (), можно определить основание системы исчисления преобразуемого числа. Если этот параметр не определен, компилятор JavaScript пытается определить его самостоятельно, при этом могут возникнуть некоторые проблемы. Основная проблема возникает, если строковое значение параметра parselnt () начинается с нуля, который мог быть получен из текстового поля или поля базы данных. В JavaScript числа, начинающиеся с нуля, обрабатываются как восьмеричные (основание 8). Поэтому результатом parse Int (" 010") будет десятичное значение 8. Используя функцию parselnt () при работе с десятичными числами, следует определять основание системы счисления как 10. Вы также вправе определить любое значение основания системы исчисления в диапазоне от 2 до 36. Например, для того чтобы преобразовать строку двоичного значения в десятичное, укажите основание системы исчисления равным 2, как показано ниже. var n = parselnt ("Oil", 2); // результат: 3 Аналогично выполняется преобразование строки с шестнадцатеричным значением в десятичный эквивалент — для этого следует определить основание системы счисления 16. var n = parselnt ("4F", 16); // результат: 79 Пример И в parselnt (), и в parseFloat () существует одна очень важная особенность: если переданная в качестве параметра строка начинается хотя бы с одной цифры, за которой следуют буквенные символы, в функции обрабатывается только та часть строки, в которой содержатся цифры (остальные символы не принимаются во внимание). Поэтому можно использовать parseFloatO для строки navigator .appVers ion, при обработке которой результатом будет только номер версии, а остальная часть строки анализироваться не будет. Например, в WinNN6 значение navigator. appVers ion выглядит следующим образом. 5.0 (Windows; en-US) С помощью parseFloat () можно получить только числовую часть строки. var ver = parseFloat (navigator.appVersion) Поскольку результатом является число, существует возможность выполнить сравнение, например, для проверки того, является ли версия данного браузера большей или равной 4. toString([основа] ) Возвращаемое значение: строковое Совместимость: WinIE4+, МасГ£4+, NN4+, Mozl+, Safari 1+ Глава 34. Глобальные функции и выражения 1029
Для каждого объекта языка JavaScript и каждого объекта document в DOM существует соответствующий метод toString (). Он используется для обработки (компиляции) содержимого объекта наиболее приемлемым способом. В табл. 34.1 приведены результаты применения метода toString () для каждого из преобразуемых типов объекта language. Тип объекта Результат Строковый Та же строка Численный Строковый эквивалент (числовые символы не преобразуются) Булев true ИЛИ false Массив Список элементов массива, разделенных между собой запятыми (после запятых пробел не используется) Функция Декомпилированное строковое определение функции Преобразовать в строку можно многие объекты DOM. Например, объект location возвращает собственный URL. Однако, если в объекте не содержится данных, которые можно преобразовать в строку, как правило, возвращается строка следующего вида. [object типОбъекта] Пример Метод toString () доступен во всех версиях браузеров. Для преобразования чисел с различными основаниями в их строковые эквиваленты устанавливайте значение параметра в пределах от 2 до 16. В листинге 34.1 вычисляется и выводится на экран таблица преобразования для десятичных, шестнадцатеричных и двоичных значений, принадлежащих диапазону от 0 и 20. В этом случае исходным значением является индекс, получаемый из переменной- счетчика при каждом выполнении операторов цикла. <html> <head> <title>Number Conversion Table</title> </head> <body> <b>Using toString() to convert to other number bases:</b> <hr /> <table border="l"> <tr> <th>Decimal</th> <th>Hexadecimal</th> <th>Binary</th> <script type="text/javascript"> var content = ""; for (var i = 0; i <= 20; i++) { content += "<tr>"; 1030 Часть IV. Объекты языка JavaScript
content += "<td>" + i.toString(10) + "<\/td>"; content += "<td>" + i.toString(16) + "<\/td>"; content += "<td>" + i. toString (2) + "<\/tdx\/tr>"; } document .write (content) ; </script> </tr> </table> </body> </html> Метод toString () нельзя использовать для преобразования определенных пользователем объектов в строку, имеющую смысл в обычном понимании, но программист может создать свой собственный метод, предназначенный только для этой операции. Например, если необходимо, чтобы в методе toString () пользовательский объект обрабатывался подобно массиву, определите действие метода и присвойте эту функцию свойству объекта (как показано в листинге 34.2). <html> <head> <title>Custom toString()</title> <script type="text/javascript"> function customToString() { var dataArray = new Array(); var count = 0; for (var i in this) { dataArray[count++] = this[i]; if (count > 2) { break; } } return dataArray.j oin(","); } var book = {title:"The Aeneid", author:"Virgil", pageCount:543}; book.toString = customToString; </script> </head> <body> <b>A user-defined toString() result:</b> <hr /> <script type="text/javascript"> document.write(book.toString()); </script> </body> </html> При выполнении листинга 34.2 с помощью метода toString () объекта custom можно получить значения всех элементов объекта, кроме последнего, который является ссылкой на функцию обработчика. Программист вправе сам определять имена данных и/или их форматирование. Глава 34. Глобальные функции и выражения 1031
unwatch (свойство) watch(свойство, обработчик) Возвращаемое значение: нет Совместимость: Winffi-, МасШ-, NN4+, Moz-, Safari- В NN4+ для передачи во внешние отладчики правильной информации в JavaScript представлено две глобальные функции, которые можно использовать для любого объекта (даже определяемого пользователем). Метод watch () используется для "слежения" за определенным свойством объекта. Если это свойство установлено в результате присвоения, функция вызывает другую определяемую пользователем функцию, в которую передается информация об имени свойства, а затем его старое и новое значение. С помощью функции unwatch можно "отключить" возможность наблюдения за определенным свойством. Выражения // /*...*/ Совместимость: Winffi3+, MacEE3+, NN2+, Mozl+, Safari 1+ Выражения, которые не обрабатываются компилятором JavaScript (или компилятором сервера), называются комментариями. В этих операторах программист может делать пометки о работе того или иного фрагмента сценария. С одной стороны, подробные комментарии полезны для разработчиков при создании сценария и его поддержке, но с другой стороны, при загрузке документа загружаются и все содержащиеся в нем комментарии. Для загрузки каждого байта необрабатываемого содержимого страницы требуется немного больше времени. Несмотря на это, рекомендуется использовать как можно больше комментариев, особенно при создании сценариев. В JavaScript существует два вида комментариев. Один из них состоит из двух косых черт (между которыми не используется пробел). Все символы, расположенные справа от них в этой же строке, не обрабатываются, даже если они расположены в середине строки. Можно использовать любое количество подобных однострочных комментариев для того, чтобы точно передать свою мысль. Для удобства восприятия текста между второй наклонной чертой и началом комментария ставят пробел. Далее приведен пример использования однострочных комментариев. // в этой строке описывается дальнейшее действие var = "Fred"; // комментарий этой строки // Если комментарий состоит из нескольких // предложений, начинайте каждое из них с // заглавной буквы // // Можно оставлять пустую строку, как показано выше. Для более длинных комментариев обычно используют другой синтаксис. В начале комментария располагают косую черту и звездочку (/*), а в конце те же символы, только в обратном порядке (*/). Все операторы и строки между ними компилятором не обрабатываются. Если необходимо быстро закомментировать большую часть программы для отладки сценария, выполните это с помощью многострочного комментария. Для того чтобы проще найти блоки комментариев в программе, для символов (/*) и (*/) отводят отдельные строки. Л некоторые закомментированные 1032 Часть IV. Объекты языка JavaScript
операторы */ Если разрабатываемый документ имеет сложную структуру, использование комментариев является наиболее удобным способом организации фрагментов программы и их поиска. Например, перед каждой функцией можно разместить блок комментариев, в которых будет описано ее назначение. /* calculate() Выполняются вычисления, основанные на параметрах .... Вызывается с помощью blah blah blah. */ function calculate(form){ операторы ■} const Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari- Ключевое слово const, как правило, используют при инициализации константы. В отличие от переменной, содержимое которой изменяется в процессе загрузки страницы, установленное значение константы не может быть изменено. Во многих языках программирования для идентификаторов постоянных используют прописные буквы; если в имени содержится несколько слов, их разделяют символами подчеркивания. Так программистам легче различать константы и переменные, используемые в программе. Пример Данная методика демонстрируется в листинге 34.3, код которого выполняется в NN6+/Mozl+. На приведенной странице выводятся данные о среднесуточной температуре в нескольких городах. (Возможно, при запросе этой страницы пользователем данные изменяются на сервере и сохраняются в массиве данных.) Температура ниже нуля выделяется специальным стилем. Эта температура является постоянной контрольной точкой, поэтому она хранится в константе. <html> <head> <title>const(ant)</title> <style type="text/ess"> .cold {font-weight:bold; color:blue} td {text-alignreenter} </style> <script type="text/javascript"> const FREEZING_F =32; var cities = ["London", "Moscow", "New York", "Tokyo", "Sydney"]; var tempsF = [33, 12, 20, 40, 75]; function showDataO { var tableData = ""; for (var i = 0; i < cities.length; i++) { tableData += "<trxtd>" + cities [i] + "<\/tdxtd "; tableData += (tempsF[i] < FREEZING_F) ? "class='cold»" : ""; tableData += ">" + tempsF[i] + "<\/tdx\/tr>"; } document.getElementBy!d("display").innerHTML = tableData; Глава 34. Глобальные функции и выражения 1033
} </ script >„. </head> <body onload="showData()"> <hl>The const keyword</hl> <hr /> <table id="temps"> <tr> <th>City</th> <th>Temperature</th> </tr> <tbody id="display"></tbody> </table> </body> </html> Возможно, ключевое слово const будет включено в новую версию стандарта ЕСМА-262 и станет широко использоваться в сценариях JavaScript, разрабатываемых следующими версиями браузеров. var Совместимость: Winffi3+, МасШЗ+, NN2+, Mozl+, Safaril+ Перед использованием переменную необходимо объявить (и инициализировать, установив некоторое значение) в выражении var. Бели ключевое слово var пропущено, переменная автоматически становится глобальной для текущего документа. Чтобы переменная оставалась локальной для данной функции, ее следует объявить или инициализировать (при этом укажите ключевое слово var внутри фигурных скобок функции). Если никакое конкретное значение переменной не присваивается, в ней хранится значение null. Поскольку тип переменной в JavaScript может изменяться в процессе выполнения сценария, не стоить присваивать переменной пустую строку или нуль, если это не требуется для каких-либо операций. Например, если инициализировать переменную как пустую строку, впоследствии с помощью оператора приращения (+=) можно присоединить к этой строке новое значение. Также допускается объявлять и/или инициализировать несколько переменных, используя для них один оператор var (укажите его в каждой строке для содержащихся в ней переменных). В таких случаях пары имяПеременной= значение отделяют друг от друга запятыми. var name, age, height; // простое объявление var color="green", temperature=85.6; // инициализация Имена переменных (или идентификаторы) должны представлять собой одну непрерывную строку символов, причем первый символ должен быть буквенным. Также запрещено использовать символы пунктуации, хотя символ подчеркивания допустим; он довольно часто используется для разделения нескольких слов, из которых состоит имя переменной. В именах переменных (подобно большинству идентификаторов в JavaScript) имеет значение регистр, поэтому следует называть переменные в соответствии с их назначением. Объекты WinlE Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Одной из особенностей продукции компании Microsoft является оснащение операционной системы Windows функциональными возможностями Web-браузера. Объединение браузера и операционной среды наиболее четко просматривается в средствах Internet Explorer доступа к объектам ActiveX. В версиях WinlE разработано несколько подобных объектов. С помощью некоторых из них в JavaScript можно использовать возможности Visual Basic Script (VBScript). 1034 Часть /V. Объекты языка JavaScript
Поскольку данные объекты применяются только в Windows и программных средствах ActiveX, в этом разделе специфика работы с ними в WinlE описывается не полностью. Для тех, кто совершенно не знаком с этими средствами, далее перечислены основные объекты WinlE. Более подробное описание данной технологии вы найдете на информационном узле в Microsoft Developer Network (MSDN); ниже приведены соответствующие URL. В этом разделе рассматриваются следующие объекты: ActiveXObject, Dictionary, Enumerator, FileSystemObject и VBArray. В Microsoft эти объекты считаются частью языка JScript. Однако при работе с ними можно убедиться, что они являются собственными объектами Internet Explorer, причем только его версий для Windows. ActiveXObject ActiveXObject представляет собой универсальный объект, с помощью которого можно открывать и обращаться к тому, что в терминологии Microsoft иногда называется объектами автоматизации. Объект автоматизации— это программа, которая запускается на стороне клиента или обслуживается с сервера. В ней могут содержаться локальные приложения — программы Microsoft Office, исполняемые файлы DLL и т.д. Для получения ссылки на объект используйте следующий конструктор ActiveXObj ect. var objRef = new ActiveXObject (appName.className [, remoteServerName]) ; Подобный синтаксис JScript используется в методе VBScript CreateObj ect (). Для того чтобы определить имя приложения и класса или типы, совместимые с этим приложением, необходимо иметь некоторые знания в области программирования Windows. Например, для получения ссылки на рабочий лист Excel используется следующий конструктор. var mySheet = new ActiveXObject("Excel.Sheet"); При получении ссылки на объект следует также знать имена свойств и методов объекта, к которым нужно обратиться. Ко многим элементам можно обращаться с помощью специальных средств, разработанных компанией Microsoft, например, Visual InterDev, или инструментов Visual Basic. Используя данные средства, вы вправе запросить объект для определения его свойств и методов. К сожалению, свойства ActiveXObject нельзя перечислить в обычном контролере свойств JavaScript for- in. При доступе к ActiveXObject (особенно на стороне клиента) необходимо обеспечить определенную защиту. Установка обычной защиты, разработанной в Internet Explorer, предотвращает доступ сценариев к приложениям клиента (во всяком случае, выводится запрос на подтверждение пользователем соответствующих полномочий). Говорить о том, что данные защищены надежно, нельзя. В общей среде, в которой достаточен гарантированный доступ ко всем клиентам, предлагается установка на принятие объектов ActiveX, исходящих из проверенного источника. И наконец, если вы достаточно сведущи в вопросах программирования в Windows, не нужно ожидать, что с помощью ActiveXObject у вас появится возможность вторжения в область личных данных ничего не подозревающих пользователей. Dictionary Даже если объект Dictionary и является очень полезным при написании сценариев VBScript, в JavaScript уже разрабатывается эквивалентная возможность. Объект Dictionary работает подобно массиву JavaScript, который имеет строковые значения индекса (подобно хеш-таблице Java), хотя числовые индексные значения в Dictionary также приемлемы. В данном случае индексы называют ключами. Такое средство не является родным для массивов VBScript, следовательно, объект Dictionary используется в этом языке для обеспечения дополнительных возможностей. Однако, в отличие от массива JavaScript, в данном случае следует использовать различные свойства и методы объекта Dictionary для добавления, обращения или удаления его элементов. Глава 34. Глобальные функции и выражения 1035
При создании объекта Dictionary с помощью ActiveXObject применяется следующая структура. var diet = new ActiveXObject("Scripting.Dictionary"); Вам необходимо создать отдельный объект Dictionary для каждого массива. В табл. 34.2 приведены его свойства и методы. После создания пустого объекта Dictionary заполняйте его данными, применяя к каждому элементу метод Add (). Ниже приводится пример создания объекта Dictionary для хранения названий столиц штатов США. var stateCaps = new ActiveXObject("Scripting.Dictionary") stateCaps.Add("Illinois", "Springfield"); Теперь можно обращаться к отдельным элементам, используя свойство Key (которое благодаря наследию VBScript выглядит, как метод JavaScript). Метод Key () является довольно удобным в объекте Dictionary; он возвращает массив всех ключей этого объекта в таком формате, который затем можно использовать в индексированных строковых массивах JavaScript. Свойство Описание Count Item("ключ") Key("ключ") Определяется количество элементов в Dictionary (предназначено только для чтения) Используется для чтения или записи значений элементов с именем ключ Используется для присвоения элементу нового ключевого имени Метод Описание Add ("ключ", значение) Прибавляются значения, связанные с уникальным ключевым именем Exists (н ключ") Если указанный ключ существует в словаре, возвращается булево true items () Возвращаются значения VBArray, содержащиеся в словаре Keys () Возвращаются ключи VBArray, содержащиеся в словаре Remove (" ключ") Используется для удаления ключ и его значения RemoveAl 1 () Используется для удаления всех элементов Для получения более подробной информации посетите узел http: //msdn. microsoft. com/ scripting/jscript/do c/jsobjDictionary.htm. Enumerator Объект Enumerator используется в JavaScript для обеспечения доступа к множествам, прямой доступ к элементам которых (с помощью индекса или имени) невозможен. Этот объект не используется при работе с такими множествами DOM, как document. all (в этом случае для получения ссылки на любой из элементов всегда можно использовать метод item()). Однако, если в сценарии используются объекты ActiveX, некоторые методы или свойства этих объектов могут возвращать множества, к которым нельзя обращаться данным способом или с помощью контролера свойств JavaScript for-in. Вместо этого необходимо поместить множество в объект Enumerator. Для выполнения данной операции вызовите конструктор объекта, передав множество в качестве параметра. var myEnum = new Enumerator{наборЭлементов); 1036 Часть IV. Объекты языка JavaScript
К экземплярам этого объекта можно обратиться, используя любой из четырех методов для установки "указателя" на определенный элемент и получения копии этого элемента. Другими словами, к элементу не обращаются непосредственно (т.е. не используется его порядковый номер в множестве). Вместо этого указатель перемещают на нужную позицию, а затем счи- тывается значение соответствующего элемента. Как видно из списка методов, приведенных в табл. 34.3, этот объект предназначен для обработки множества в цикле. Для управления указателем его устанавливают на позицию, соответствующую началу множества, затем значение увеличивается — таким образом обеспечивается доступ ко всем элементам. myEnum.moveFirst() for (; !myEnum.atEnd(); myEnum.moveNext()) { val = myEnum.item(); // выражения обработки значений } Метод Описание atEnd () ' Если указатель соответствует концу множества, возвращается true item () Возвращается значение текущей позиции указателя moveFirst () Указатель перемещается на первую позицию в множестве moveNext () Указатель перемещается на следующую позицию в множестве VBArray С помощью объекта VBArray в JavaScript обращаются к безопасным массивам Visual Basic. Это могут быть массивы, предназначенные Только для чтения, которые обычно возвращаются объектами ActiveX. Подобные массивы могут создаваться в разделах VBScript клиентских сценариев. Массивы Visual Basic по своей природе могут иметь любую размерность. В следующем примере создается VB-массив размерностью "3x2". <script type="text/vbscript"> Dim myArray(2, 1) иди "a" »B" »b" "С" "с" 0) 1) 0) 1) 1) 2) myArray(0, myArray(0, myArray(1, myArray(1, myArray(2, myArray(2, </script> После получения массива VB можно преобразовать его в объект, который не ограничивается интерпретатором JScript. < script type="text/javascript"> var theVBArray = new VBArray(myArray); </script> К глобальным переменным одного блока языка сценариев можно обращаться из другого блока или даже на другом языке. Но в этом случае массив уже не является массивом JavaScript. Его можно преобразовать в таковой с помощью метода VBArray. toArray () или получить информацию об объекте VBArray, используя другие методы (кратко описанные в табл. 34.4). После преобразования VBArray в массив JavaScript можно использовать эти значения в любом массиве JavaScript. Глава 34. Глобальные функции и выражения 1037
Метод Описание ч dimensions () Возвращается размерность оригинального массива get item (dimi [, dim2 [,... dimN] ]) Возвращается ссылка на массив, определенная адресами размерности ibound (dim) Возвращается низшее значение индекса для данной размерности toArray () Возвращается VBArray, преобразованный в массив JavaScript ubound {dim) Возвращается высшее значение индекса для данной размерности При использовании метода toArray () для массива с различной размерностью значения размерностей после первой "строки" просто прибавляются к массиву JavaScript (при этом вложенная структура не используется). 1038 Часть IV. Объекты языка JavaScript
Текстовые объекты тела страницы пределенное количество HTML-элементов относится к категории средств, предназначенных для решения более конкретных задач, чем управление контекстно- зависимыми объектами, рассмотренными в главе 15. В эту группу входят некоторые широко используемые элементы, например, элементы заголовка hl-h6, а также элементы, которые в данный момент используются нечасто, поскольку для обеспечения их полной поддержки не хватает технических средств даже в самых современных браузерах. В этой главе рассмотрены все виды объектов, связанные с представлением текста на странице. К ним не относятся объекты, которые представляют элементы управления формы (текстовые окна и другие элементы, рассмотренные в главе 23). Преимущественно эта глава посвящается объектам, рассматриваемым в главе 15: их свойствам, методам и обработчикам событий. В этой главе, в основном, рассмотрены средства, уникальные для каждого конкретного объекта (общие средства объектов будут описаны в других главах книги). Кроме объектов HTML-элементов, в этой главе также речь пойдет об объекте TextRange (впервые представленном в Г£4), а также о соответствующем ему объекте Range стандарта W3C DOM. Этот объект— достаточно мощное средство в сценариях, поскольку он позволяет на самом детальном уровне управлять содержимым тела страницы, отличающимся от представляемых свойствами InnerText или nodeValue элементов. Чаще всего такой объект представляет текст, заданный в виде абзацев и списков, которые пользователь видит на экране. Объекты TextRange и Range предоставляют возможность управления курсором в сценарии при выполнении операций обработки содержимого страницы (вырезания, копирования, вставки, а также утилит, производных от основных операций например, поиска и замены. Примите во внимание, что для использования средств, описание которых приведено в этой главе, вам потребуются браузеры не младше DE4+ и NN6+/W3C; в некоторых случаях необходимо будет обратиться к браузеру Ш версии 5+. К сожалению, в МасШ5+ объект TextRanqe не используется. о
Объекты элементов blockuote и q Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойства, методы и обработчики событий объектов этих HTML-элементов описаны в главе 15. Свойства Методы Обработчики событий cite Синтаксис Доступ к свойствам и методам объектов этих элементов. (IE4+) [window. ] document .all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document. getElementByld ( "идентификатор") . свойство | методе [параметры] ) Описание объектов Элемент blockuote представляет собой специальный текстовый контейнер. Как правило, браузеры начинают построение содержимого страницы с отдельной строки и делают отступ справа и слева от краев страницы приблизительно на 40 пикселей. Цитата вставляется в q-элемент, который не предусматривает перенос содержимого на следующую строку. С точки зрения объекта, единственным свойством, отличающим эти два объекта от подобного рода текстовых контейнеров, является cite (берет начало от атрибута cite в HTML 4.0). Данный атрибут обеспечивает URL-ссылку на цитату и не пересекается с атрибутами загрузки внешнего документа src и href. Свойство cite Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойство cite может содержать URL (в виде строки), указывающий на источник цитаты в элементе blockuote или элементе q. В будущем браузеры для управления документом будут содержать специальные пользовательские средства, однако ни один современный браузер, поддерживающий свойство cite, пока не осуществляет никаких действий по обработке этой информации. Объект элемента br Совместимость: WinIE4+, Macffi4+, NN6+, Mozl+, Safari 1+ Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий clear 1040 Часть IV. Объекты языка JavaScript
Синтаксис Доступ к свойствам и методам объекта элемента br. (IE4+) [window. ] document. all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ ме- тод{ [параметры] ) Описание объекта Элемент br осуществляет операции возврата каретки и перевода строки, часто применяемые при форматировании содержимого страницы. Он не обеспечивает такой междустрочный интервал, как между абзацами, что задается элементом р. Элемент br отличается от стандартных элементов и объектов HTML наличием атрибута clear. Свойство clear Значение: строка Чтение/Запись Совместимость: WinDE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойство clear определяет, как текст в элементе, следующем после элемента br, обтекает плавающий элемент (например изображение, плавающее вдоль правой границы). Поскольку браузеры последних версий не поддерживают это свойство, атрибут, на котором оно основано, в спецификации HTML 4.0 не представлен. Вместо него рекомендуется использовать атрибут clear таблицы стилей для Ьг-элемента. Свойство clear может принимать одно из следующих значений: all, left или right. См. также: свойство clear таблицы стилей. Объект элемента font Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства color face size Методы Обработчики событий Синтаксис Доступ к свойствам и методам объекта элемента FONT. (IE4+) [window. ] document. all. идентификатор. свойство \ метод([параметры] ) (IE5+/W3C) [window. ] document. getElementByld ("идентификатор") . свойство \ ме- тод{ [параметры] ) Глава 35. Текстовые объекты тела страницы 1041
Описание объекта С точки зрения стандартного способа форматирования содержимого,:элемент font вначале отображался как объект только браузерами, поддерживающими каскадные таблицы стилей, в качестве наиболее предпочтительного метода управления гарнитурой шрифта, его цветом и размером. Однако доминирующее положение таблиц стилей не означает, что вы не сможете использовать элемент font при разработке страниц с помощью средств современных браузеров — этот элемент удобнее использовать при построении небольшой страницы, которая должна быть совместимой сверху вниз (поддерживаться старыми версиями браузеров). Однако он вряд ли удовлетворит запросы программиста, желающего использовать сценарии для изменения параметров шрифтов содержимого тела страницы после загрузки страницы. Поэтому придерживайтесь эмпирического правила, согласно которому элемент font (свойства объекта элемента font) используют только в том случае, если необходимо, чтобы страница поддерживалась всеми версиями браузеров. Таблицы стилей (и их свойства) применяются при разработке страниц, отображаемых исключительно с помощью браузеров ЕЕ4+ и NN6+/W3C. Свойства color Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Moz 1 +, Safari l+ Управление цветом объекта font можно осуществлять с помощью свойства Color. Значение цвета представляется либо в виде шестнадцатеричных триплетов (например #FFCCFF), либо названия цвета, распознаваемого большинством браузеров. В любом случае, при задании значения различие между прописными и строчными символами не отслеживается. Пример Листинг 35.1 содержит код страницы, в котором продемонстрированы три свойства объекта элемента font: color, facensize.B нем также показан самый эффективный способ изменения значений этих свойств с помощью метода setAttribute (). Код этого листинга корректно выполняется всеми браузерами, хотя списки select позволяют изменить текст только в IE4+ и NN6+/W3C. Элемент р имеет дочерний элемент font, содержащий три слова, форматирование которых зависит от значений, выбранных в списках select. Каждый список задает одно из свойств объекта font, а их атрибуты name умышленно приравниваются к именам этих свойств; атрибуты value элементов option содержат строки, назначаемые в качестве значений описанных выше свойств. Каждый элемент select вызывает функцию setFontAttr (), передавая ей в качестве аргумента ссылку на себя. Первая задача функции setFontAttr () — это проверка поддержки браузером элемента font. Старые браузеры не поддерживают элементы document.all и myFont, а потому в них функция не выполняется. После успешного выполнения теста функция извлекает строку из значения value элемента select, передаваемую в качестве аргумента. Если в списке выбрано значение (отличное от пустой строки), то атрибут с названием, совпадающим с именем элемента select, получает значение. 1042 Часть IV. Объекты языка JavaScript
/ Досадная ошибка в Mac IE не позволяет корректно установить цвет текста с помощью этого кода. Правильность кода не вызывает сомнений, поскольку остальные два свойства поддаются изменению. <html> <head> * <title>Font Object Properties</title> <script type="text/javascript"> // общая функция, выполняющая все задачи function setFontAttr(select) { var choice = select.options[select.selectedlndex].value; if (choice) { document.getElementByld("myFONT").setAttribute(select.name, choice); </script> </head> <body> <hl>Font Object Properties</hl> <br /> <p>This may look like a simple sentence, but <font id="myFONT">THESE THREE WORDS</font> are contained by a FONT element.</p> <form> Select a text color: <select name="color" onchange="setFontAttr(this)"> <optionx/option> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> <option value="#FA8072">Some Hex Triplet Value</option> </selectxbr /> Select a font face: oelect name="face" onchange="setFontAttr (this) "> <optionx/option> <option value="Helvetica">Helvetica</option> <option value="Times">Times</option> <option value="Comic Sans MS, sans-serif">Comic Sans MS, sans-serif</option> <option value="Courier, monospace">Courier, monospace*:/option> <option value="Zapf Dingbats, serif">Zapf Dingbats, serif</option> </selectxbr /> Select a font size: oelect name="size" onchange="setFontAttr(this) "> <optionx/option> <option value="3">3 (Default)</option> <option value="+l">Increase Default by l</option> <option value="-l">Decrease Default by l</option> <option value="l">Smallest</option> <option value="7">Biggest</option> </select> </form> </body> </html> См, также: атрибут color таблицы стилей. Глава 35. Текстовые объекты тела страницы 1043
face Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Типом шрифта объекта font можно управлять с помощью свойства face. Как и в случае с атрибутом face (и соответствующим ему атрибутом font - family таблицы стилей), в строке с разделителем-запятой можно задать одно или несколько значений. Браузеры отображают текст с помощью шрифта, который указан самым первым в списке для текущего элемента. Первый найденный в клиентской системе тип шрифта применяется к тексту, окруженному элементом font. Сначала необходимо задать список наиболее часто используемых шрифтов. Разрешите отображать содержимое с помощью первичных гарнитур шрифта (sans-serif, serif и monospace); тем самым вы определите тип шрифта для тех систем, в которых не установлены шрифты, которые указаны в начале списка. Если вы уверены, что Windows отображает текст необходимым шрифтом, a Macintosh — другим, но похожим шрифтом с другим именем, то названия обоих шрифтов можно задать в одном и том же значении свойства. Браузер пропускает имена шрифтов, не установленных в данный момент на стороне клиента. Пример В листинге 35.1 приведен пример использования этого свойства элемента font. Вы не всегда будете видеть эффект изменения форматирования текста при выборе другого варианта шрифта в соответствующем списке, поскольку этот шрифт может быть не установлен в системе. См. также: атрибут font-family таблицы стилей. size Значение: строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Размером шрифта, указанным в элементе font, можно управлять с помощью свойства size. В отличие от рекомендуемого для использования атрибута font-size стиля, свойство size объекта элемента font (и соответствующего ему атрибута size) имеет ограничение на представляемое значение, обусловленное использованием в более ранних версиях HTML только относительного формата представления размера шрифта (1-7). Значения свойства size — это строки, иногда представленные в виде числовых значений. Можно определить относительный размер заданного по умолчанию шрифта с помощью знака "плюс" или "минус", вводимого перед значением. Например, если размер шрифта, заданный по умолчанию (в наборе установок пользователя), равен 3, то можно изменить размер текстового фрагмента, вставив его внутрь элемента font и изменив впоследствии свойство size до значения +2. Чтобы более точно задать размер шрифта с помощью других единиц измерения (пикселей или точек), можно использовать атрибут font-size таблицы стилей. Пример В листинге 35 Л приведен пример использования этого свойства элемента font. См. также: атрибут font-size таблицы стилей. Объекты элементов И1-И6 Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safaril+ Свойства, методы и обработчики событий HTML-элементов описаны в главе 15. 1044 Часть IV. Объекты языка JavaScript
Свойства Методы Обработчики событий align Синтаксис Доступ к свойствам и методам объектов элементов hl-h6. (IE4+) [window. ] document. all. идентификатор. свойство \ метод ([параметры] ) (IE5+/W3C) [window. ] document.getElementByld ("идентификатор") . свойство\ методе [параметры] ) Описание объектов Так называемые объекты заголовка (обозначаемые hi, h2, h3, h4, h5 и h6) предоставляют возможность эффективного форматирования документа, соответственно, шести различным уровням и подуровням предоставления информации. Вы можете имитировать поведение заголовков не только р-элементами, но и таблицами стилей, однако первые очень часто содержат важную контекстно-зависимую информацию о структуре документа. С помощью средств управления иерархической структурой документа браузеров IE4+ и NN6+ сценарий может генерировать собственное содержание или оглавление всех длинных документов, в процессе чего проводится поиск элементов свойства nodeName, которые принадлежат семейству hn. Поэтому для решения подобных задач следует использовать свойство элемента даже в том случае, если необходимо изменить внешний вид документа, задаваемый по умолчанию стандартным шаблоном таблицы стилей. Рассматривая эти шесть объектов с точки зрения построения сценариев, можно прийти к выводу, что они в точности такие же, как и характерные текстовые объекты, которые обладают дополнительным свойством align. Поскольку каждый hn-элемент — блоковый, то можно использовать каскадные таблицы стилей для его выравнивания, причем этот способ более удобный, чем использование соответствующих атрибутов или свойств. Таким образом, выбор за вами! Свойство align Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ С помощью строковых значений свойства align можно задать выравнивание элемента заголовка по левому краю (left), центру страницы (center) или же по правому краю (right). В языке HTML 4.0 вместо соответствующего атрибута align используется атрибут таблицы стилей text-align. См. также: атрибут таблицы стилей text-align. Объект элемента hr Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Свойства, методы и обработчики событий этих HTML-элементов описаны в главе 15. Глава 35. Текстовые объекты тела страницы 1045
Свойства Методы Обработчики событий align color noShade size width Синтаксис Доступ к свойствам и методам объектов элемента hr. (IE4+) [window. ] document. all. идентификатор. свойство \ метод( [параметры]) (IE5+/W3C) [window. ] document. get Element By Id ("идентификатор") . свойство \ методе [параметры] ) Описание объектов Элемент hr предназначен для создания горизонтальных разделителей в соответствии с параметрами, задающими размер, форму и расположение текущего элемента (как правило, определяемых атрибутами). В таблицах стилей обычно указываются соответствующие настройки. Второй способ рекомендуется использовать только при создании страниц, которые должны загружаться исключительно в браузерах, поддерживающих CSS. В браузерах Ш4+, NN6+/W3C существует возможность изменить порядок отображения элемента hr либо напрямую (используя свойства объекта элемента), либо с помощью свойств таблицы стилей. Чтобы задать ссылку на специфический элемента hr необходимо определить элементу значение атрибута-идентификатора — этот способ вы, вероятнее всего, уже привыкли использовать для решения многих задач. Свойства align Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГЕ4+, NN6+, Mozl+, Safari 1+ Управление горизонтальным выравниванием объекта элемента hr осуществляется с помощью свойства align. Задавая значения этого свойства, можно выровнять элементы на странице по левому краю (left), по центру страницы (center) или же по правому краю страницы (right). По умолчанию элемент выравнивается по центру. Пример В листинге 35.2 приведен код страницы, в котором продемонстрированы способы изменения всех пяти свойств объекта элемента hr. Для выполнения этой задачи эффективно применяется метод setAt tribute (). Эта страница загружается во всех браузерах, однако списки select позволяют изменять текст только в браузерах ГЕ4+, NN6+/W3C. Элемент hr (с идентификатором myHR) отображается с настройками по умолчанию (ширина 100%, выровнен по центру и окрашен в стандартный цвет). Каждый список задает одно из свойств объекта hr, а атрибуты name списков умышленно приравниваются к именам этих 1046 Часть IV. Объекты языка JavaScript
свойств; атрибуты value элементов option содержат строки, назначаемые в качестве значений описанных выше свойств. Каждый элемент select вызывает функцию setHRAttr (), передавая ей в качестве аргумента ссылку на себя. Первая задача функции setHRAttr() — это проверка поддержки браузером элемента font. Старые браузеры не поддерживают элементы document. all и myFont, а потому в них функция не выполняется. После успешного прохождения теста функция извлекает строку из значения value элемента select, передаваемую в качестве аргумента. Если в списке выбрано значение (отличное от пустой строки), то атрибут с названием, совпадающим с именем элемента select, получает значение. <html> <head> <title>hr Object Properties</title> <script type="text/javascript"> // общая функция, выполняющая все задачи function setHRAttr(select) { var choice = select.options[select.selectedlndex].value; if (choice) { document .getElementByldC'myHR").setAttribute(select.name, choice); ,» </script> </head> <body> <hl>hr Object Properties</hl> <br /> <p>Here is the hr element you will be controlling:</p> <hr id="myHR" /> <form> Select an alignment: <select name="align" onchange="setHRAttr(this)"> <option></option> <option value="left">Left</option> <option value="center">Center</option> <option valuer"right">Right</option> </selectxbr /> Select a rule color (IE only): <select name="color" onchange="setHRAttr(this)"> <optionx/option> <option value="red">Red</option> <option value="green">Green</option> <option value=/Hblue">Blue</option> <option value="#FA8072">Some Hex Triplet Value</option> </selectxbr /> Select a rule shading: <select name="noShade" onchange="setHRAttr(this)"> <optionx/option> <option value="true">No Shading</option> <option value="false">Shading</option> </selectxbr /> Select a rule height: <select name="size" onchange="setHRAttr(this)"> <optionx/option> Глава 35. Текстовые объекты тела страницы 1047
<option value="2">2 (Default)</option> <option value="4">4 Pixels</option> <option value="10">10 Pixels</option> </selectxbr /> Select a rule width: <select name=Hwidth" onchange="setHRAttr(this)"> <optionx/option> <option value="100%">100% (Default)</option> <option value="80%">80%</option> <option value="300">300 Pixels</option> </select> </form> </body> </html> См. также: атрибут text-align таблицы стилей. color Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Управление цветом объекта hr выполняется с помощью свойства color. Его значения могут быть представлены как в виде шестнадцатеричных триплетов (например #FFCCFF), так и с помощью названия цвета, распознаваемого большинством браузеров. В любом случае, при задании строки значения различия между прописными и строчными буквами не будет. При изменении заданного по умолчанию значения цвета исчезает "тень" разделителя (трехмерный эффект). Кроме того, существует универсальное значение, позволяющее вернуть установки цвета браузера по умолчанию после их изменения. Пример Пример изменения свойства color элемента hr приведен в листинге 35.2. См. также: атрибут color таблицы стилей. noShade Значение: булево Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safari 1+ Элемент hr, заданный с настройками по умолчанию, отображается с применением трехмерного эффекта, называемого тенью. Этот режим отображения можно отключить в сценарии, изменив значение свойства noShade на true. Однако имейте в виду, что в браузере IE4+ операция изменения свойства noShade может проводиться только в одном направлении, т.е. нельзя восстановить эффект трехмерности после того, как он был снят. Более того, при определении цвета, отличного от заданного по умолчанию, эффект трехмерности разделителя, установленный по умолчанию, исчезает. Пример Пример изменения свойства noShade элемента hr приведен в листинге 35.2. Из-за весьма странной ошибки изменение этого свойства может привести к вполне непредвиденному результату. См. также: атрибут color элемента таблицы стилей. 1048 Часть IV. Объекты языка JavaScript
size Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Размер элемента hr представлен толщиной линии. Его можно изменить с помощью свойства size. Значениями этого свойства могут быть целочисленные величины, задающие количество отображаемых пикселей. Пример Пример изменения свойства size элемента hr приведен в листинге 35.2. width Значение: целочисленное или строка Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safaril+ Значением параметра ширины разделителя можно управлять с помощью свойства width. Согласно установкам по умолчанию, элемент занимает всю ширину области родительского контейнера (как правило, body). Значение ширины может устанавливаться как в виде абсолютного количества пикселей (целочисленное значение), так и с помощью процентных единиц измерения относительно ширины родительского контейнера. Процентные значения задаются строковыми переменными, заканчивающимися символом %. Пример Пример изменения свойства width элемента hr приведен в листинге 35.2. См. также: атрибут width таблицы стилей. Объект элемента label Совместимость: WinIE4+, МасШ4+, NN6+, Mozl+, Safari 1+ Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства accessKey form htmlFor Методы Обработчики событий Синтаксис Доступ к свойствам и методам объектов элементов label. (IE4+) [window. ] document .all. идентификатор. свойство \ метод ( [параметры] ) (IE5+/W3C) [window. ] document .getElementById ("идентификатор") . свойство\ ме- тод[ [параметры] ) Глава 35. Текстовые объекты тела страницы 1049
Описание объекта Элемент label позволяет установить контекстную связь между внешним элементом управления (текстовое поле, список, переключатель) и независимым текстом, используемым для обозначения элемента управления на странице. Элемент label не управляет отображением и физическими свойствами элемента управления, поскольку эти задачи полностью возлагаются на средства HTML. Разместить надпись внутри элемента label, принадлежащего элементу управления формы, довольно важно в том случае, когда в сценарии выполняется управление иерархически упорядоченными элементами содержимого страницы. Кроме того, для получения достоверных результатов анализа данных поддержка однозначной связи между элементом управления формы и его надписью должна занимать одно из главных мест в списке первостепенных задач программиста. Свойства accessKey Значение: строка Чтение/Запись Совместимость: WinIE4+, МасГЕ5+, NN6+, Mozl+, Safaril+ Для большинства других HTML-объектов описание свойства accessKey представлено в главе 15, посвященной базовым элементам. При работе с объектом label это свойство используется так же, как и в других объектах DE. Значение односимвольной строки представляет код символа, используемого совместно.с клавишей-модификатором, которая зависит от ОС или браузера (например, <Ctrl> в версии IE для Windows), для активизации элемента управления формы с указанной надписью. Рекомендуется задавать исходное значение этого свойства с помощью атрибута accesskey элемента label. См. также: свойство accessKey базовых элементов. form Значение: ссылка на объект формы Чтение/Запись Совместимость: WinIE6+, Macffi5+, NN6+, Mozl+, Safaril+ Свойство form объекта элемента label возвращает ссылку на объект формы, содержащий элемент управления, с которым связана надпись элемента. Это свойство используется при анализе узлов сложного документа, когда важно определить контейнер формы с точки зрения надписи, а не элемента управления формы. Ссылка на объект формы, возвращаемая объектом элемента label, аналогична той, которая представлена свойством form любого объекта управления. См. также: свойство accessKey элементов input. htmlFor Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN6+, Mozl+, Safaril+ Свойство html For представляет собой строку, содержащую ГО элемента управления формы с указанной (текущей) надписью. Это значение, как правило, задается с помощью атрибута for в дескрипторе элемента label. Изменение этого значения не приводит к изменению расположения надписи, однако оно нарушает связь между надписью и элементом управления формы. 1050 Часть IV. Объекты языка JavaScript
Объект элемента marquee Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safaril+ Свойства, методы и обработчики событий этого HTML-элемента описаны в главе 15. Свойства Методы Обработчики событий behaviour start() onbounce bgColor stop() onfinish direction onstart height hspace loop scrollAmount scrollDelay trueSpeed vspace width Синтаксис Доступ к свойствам и методам объекта элемента marquee. (IE4+) [window. ] document. all. идентификатор, свойство \ метод ( [параметры] ) Описание объекта Элемент marquee — это частный элемент семейства Microsoft, обеспечивающий прокрутку текста в прямоугольнике с помощью атрибутов элемента width и height. Прокручиваемый в элементе текст размещается между открывающим и закрывающим дескрипторами элемента. Только объектная модель браузеров Ш4+ позволяет в сценарии управлять этим элементом и многими свойствами его объекта. Свойства behavior Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойство behavior задает способ перемещения текста в области прокрутки. Это свойство принимает значение одной из этих трех строк: alternate, scroll и slide. При использовании alternate направление прокрутки текста принимает два значения: вверх и вниз (или вправо и влево, что зависит от значения свойства direction). Если задано значение scroll, то это означает, что текст будет полностью прокручен внутри области перед его повторным отображением на экране. При задании значения slide прокрутка текста про- Глава 35. Текстовые объекты тела страницы 1051
исходит до тех пор, пока не отобразится последний элемент. Если в качестве значения свойства задать slide (вместо значения соответствующего атрибута дескриптора), то прокрутка текста приостановится после того, как текст достигнет границы прямоугольника. Свойство behavior имеет значение по умолчанию scroll. Пример В листинге 35.3 содержится код страницы, в котором продемонстрированы способы изменения нескольких свойств элементов marquee: behavior, bgColor, direction, scrollAmount и scroll Del ay. Браузеры NN7+/Moz позволяют изменять далеко не все эти свойства. <html> <head> <title>marquee Object Properties</title> <script type="text/javascript"> // общая функция, выполняющая все задачи function setMARQUEEAttr(select) { var choice = select.options[select.selectedlndex].value; if (choice) { document.getElementByld("myMARQUEE"). setAttribute(select.name, choice); } } </script> </head> <body> <hl>marquee Object Properties</hl> <br /> <hr /> <marquee id="myMARQUEE" width="400" height="24">This is the marquee element object you will be controllings/marquee > <form> <input type="button" value="Start Marquee" onclick="document.getElementByld('myMARQUEE1).start()" /> <input type="button" value="Stop Marquee" onclick="document.getElementByld (•myMARQUEE1) . stop () " /xbr /> Select a behavior: <select name="behavior" onchange="setMARQUEEAttr(this)"> <optionx/option> <option value="alternate">Alternate</option> <option value="scroll">Scroll</option> <option value="slide">Slide</option> </selectxbr /> Select a background color: <select name="bgColor" onchange="setMARQUEEAttr (this)"> <optionx/option> <option value="red">Red</option> <option value="green">Green</option> «coption value="blue">Blue</option> <option value="#FA8072">Some Hex Triplet Value</option> </selectxbr /> Select a scrolling direction: <select name="direction" onchange="setMARQUEEAttr(this)"> 1052 Часть IV. Объекты языка JavaScript
<optionx/option> <option value="left">Left</option> <option value="right">Right</option> <option value="up">Up</option> <option value="down">Down</option> </selectxbr /> Select a scroll amount: <select name="scrollAmount" onchange="setMARQUEEAttr(this)"> <optionx/option> <option value="4">4</option> <option *value="6">6 (Default)</option> <option value="10">10</option> </selectxbr /> Select a scroll delay: <select name="scrollDelay" onchange=nsetMARQUEEAttr(this)"> <optionx/option> <option value="50">Short</option> <option value=M85">Normal</option> <option value="125">Long</option> </select> </form> </body> </html> См. также: свойство direction объекта marquee. bgColor Значение: шестнадцатеричный триплет или имя цвета Чтение/Запись Совместимость: WinIE4+, МасГ£4+, NN-, Moz-, Safari- Свойство bgColor определяет цвет фона прямоугольной области элемента marquee. Для задания цвета текста необходимо поместить объект marquee в область действия элемента font или же определить элементу marquee атрибут color таблицы стилей. Значения всех свойств цветов могут представлять либо обычные шестнадцатеричные триплеты HTML (например #00FF00), либо названия, используемые в браузерах NN (список цветов расположен на узле: http://www.developer.netscape.com/docs/manuals/htmlguid/colortab.htm). Пример Пример использования свойства bgColor приведен ранее в листинге 35.3. direction Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safari- Значение свойства direction предоставляет возможность получить или задать направление прокрутки текста (вертикальное или горизонтальное). Существует четыре возможных варианта значений этого свойства: left, right, down, up. По умолчанию устанавливается значение left. Пример Пример использования свойства direction приведен ранее в листинге 35.3. См. также: свойство behavior объекта marquee. Глава 35. Текстовые объекты тела страницы 1053
height width Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safari- Свойства height и width представляют возможность получить или установить размер прямоугольника, в котором.размещается элемент, в пикселях. Каждое свойство задается независимо от другого. Подобно необязательным атрибутом обьектов Ш, если width или height определены в дескрипторе, то вы не сможете использовать соответствующие свойства для получения размера элементов и изменения значений по умолчанию. hspace vspace Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Свойства hspace и vspace предоставляют возможность устанавливать или изменять отступы вокруг элемента marquee. При установке значения свойства hspace происходит изменение как левой, так и правой границ элемента; свойство vspace управляет расположением верхней и нижней границ. Толщина границы не зависит от высоты и ширины элемента. loop Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- С помощью свойства loop можно указать количество повторных "прокруток" элемента marquee, задаваемых в соответствии со значением атрибута loop. Несмотря на то, что это свойство имеет статус чтения-записи, его изменение с помощью сценария не приведет к ситуации, когда обработка текста в цикле выполняется большее количество раз перед остановкой, чем это задано. Исходя из этого, такое свойство лучше рассматривать как используемое Только для чтения. scrollAmount scrollDelay Значение: целочисленное Чтение/Запись Совместимость: WinIE4+, МасШ4+, NN7+, Mozl+, Safari- Свойства scrollAmount и scrollDelay управляют скоростью и плавностью прокрутки текста элемента marquee. Количество пикселей между процессами обновления прокручиваемого текста контролируется свойством scrollAmount. Чем меньше это количество, тем меньше "скачков" будет при прокрутке (по умолчанию это значение равно 6). В то же время, можно управлять интервалом между каждым обновлением текста с помощью свойства scrollDelay (в миллисекундах). Чем меньше это число, тем чаще осуществляется обновление (по умолчанию эти значения задаются в диапазоне от 85 и 90 миллисекунд в зависимости от операционной системы). Таким образом, сочетание небольших значений свойств scrollAmount и scrollDelay приводит к наиболее плавной прокрутке содержимого. 1054 Часть IV. Объекты языка JavaScript
Пример Пример использования свойств scrollAmount и scrollDelay приведен ранее в листинге 35.3. См. также: свойство trueSpeed объекта marquee. trueSpeed Значение: булево Чтение/Запись Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- В браузере Ш имеется встроенный программный регулятор, предотвращающий быструю прокрутку элемента marquee в том случае, когда атрибуту scrolldelay или свойству scrollDelay присваивается значение, меньшее 60. Но если вы все-таки решили использовать скорость прокрутки, большую 60 (подразумевается, что значение должно быть меньше 60), необходимо также установить значение свойства trueSpeed равным true. См. также: свойство scrollDelay объекта marquee. Методы start О stop О Возвращаемое Значение: отсутствует. Совместимость: WinIE4+, MacIE4+, NN7+, Mozl+, Safari- Сценарий может запускать или останавливать (приостанавливать) работу элемента marquee с помощью методов start () или stop О. Ни один из этих методов не имеет параметров, поэтому их можно определять так часто, как это необходимо после загрузки страницы. Пом* ните, что метод start () не запускает обработчик событий onstart для объекта. Пример Пример использования методов stop() и start О и scrollDelay приведен ранее в листинге 35.3. Эти методы вызываются в обработчиках событий отдельных кнопок страницы. Обработчики событий onbounce Совместимость: WinIE4+, MacIE4+, NN-, Moz-, Safari- Обработчик событий onbounce запускается только тогда, когда свойство behavior элемента marquee принимает значение alternate. В этом возвратно-поступательном режиме каждый раз, когда прокручиваемый текст достигает границы области, перед выполнением обратного движения, запускается событие onbounce. Если вы решили надоедать посетителям вашего узла, то установите звуковое оповещение при каждом запуске события onbounce (это шутка, не делайте этого). См. также: свойство behavior объекта marquee. Глава 35. Текстовые объекты тела страницы 1055
onfinish Совместимость: Winffi4+, МасШ4+, NN-, Moz-, Safari- Обработчик событий onfinish запускается только тогда, когда значение циклической прокрутки элемента marquee равно числу 1 или больше. После выполнения последнего цикла обработки текста запускается событие onfinish. См. также: свойство loop объекта marquee. onstart Совместимость: WinIE4+, МасШ4+, NN-, Moz-, Safari- Обработчик событий onstart запускается при инициализации процесса прокрутки элементом marquee, но только после загрузки страницы. Метод start () не приводит к запуску этого обработчика событий. См. также: метод start () объекта marquee. Объект Range Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Свойства Методы Обработчики событий collapsed commonAncestorContainer endContainer endOffset' startContainer startOffset cloneContents() cloneRange() collapse() compareBoundaryPoints() compareNode() comparePoint() createContextualFragment() deleteContents() detach() extractContents() insertNode() intersectNode() isPointlnRange() selectNode() selectNodeContents() setEnd() setEndAfter() setEndBefore() setStartO setStartAfterO setStartBefore() surroundContents() toStringO 1056 Часть IV. Объекты языка JavaScript
Синтаксис > V I Создание объекта Range. var rangeRef = document.creatRange(); Доступ к свойствам и методам объекта Range. (NN6+/MOZ1 +) ссылкаНаОбъект. свойство | метод( [параметры] ) Описание объекта Объект Range относится к W3C DOM, поддерживаемой компанией Microsoft при разработке объекта TextRange. Существенные различия (немалая часть которых представляет собой почти разные словари свойств и методов) касаются режима работы и функциональных возможностей этих двух весьма подобных объектов. Несмотря на то, что Microsoft была включена в рабочую группу и принимала участие в подготовке документации W3C DOM второго уровня, ни один из участников компании не получил преимуществ в используемой модели DOM — причиной тому стало появление объекта Range. Поскольку DOM версии W3C не была представлена в Ш5.5, то о поддержке объекта Range в нем не стоит даже говорить. Между тем, для сравнения свойств двух "равнозначных" объектов просмотрите раздел, посвященный объекту TextRange (далее в этой главе). Ни один Range версии W3C DOM либо TextRange, предложенный Microsoft, не используется в браузерах МасВЕ. Назначение объекта Range в W3C DOM — это предоставление сценарию возможности управления отдельными элементами содержимого (обычно это часть текстового содержимого документов), которые не всегда представлены в иерархической структуре документа отдельными узлами. Наряду с тем, что объект Range используется для получения доступа к узлам и элементам, он также расширяет границы возможностей сценария по управлению содержимым на самом детальном уровне. Содержимое объекта Range иногда называется выделением, однако это совеем не означает, что текст выделятся на странице подобно тому, как это делается с помощью мыши. Термин "выделение" в данном случае применяется к части содержимого документа, к которой нельзя обратиться как к отдельному объекту, расположенному вне дерева узлов документа. Когда в сценарии создается объект Range, разработчику предоставляется возможность, с помощью различных методов осуществить проверку, изменение, удаление, перемещение и вставку содержимого страницы. Объект Range (речь идет об экземпляре статического объекта Range) имеет начальную и конечную точку, которые совместно определяют границы диапазона. Граничные точки диапазона определяются в виде смещения относительно положения диапазона в контейнере. Смещение вычисляется в количестве символов от границы содержимого узла (при этом игнорируются любые символы атрибутов или дескрипторов HTML). Когда обе границы оказываются на краях одного и того же узла, смещение также подсчитывается в количестве узлов в контейнере, окружающем начальную и конечную точки. Приведенный пример поможет понять изложенные выше доводы. Рассмотрим следующий упрощенный HTML-документ. <html> <body> <p>This paragraph has an <em>emphasized</em> segment.</p> </body> </html> Можно создать объект Range, который представляет текст внутри элемента em разными способами, в каждом из которых подсчет смещения содержимого выполняется по-разному. Глава 35. Текстовые объекты тела страницы 1057
1. От единственного дочернего узла элемента ет (текстовый узел). Смещение в начальной точке равно нулю, оно представляет собой расположение точки ввода перед первым символом (е в нижнем регистре); смещение в конечной точке равно 10, это расположение символа (отсчет начинается с нуля), следующего после d (в нижнем регистре) символа. 2. От элемента ет В данной ситуации дочерний текстовый узел располагается внутри элемента em. Существует только один узел, поэтому смещение в начальной точке равно 0, в то время как в конечной точке — 1. 3. От дочерних узлов элемента р (два текстовых узла и один узел элемента). Существует возможность установить значения диапазона от начальной точки до самого конца (подсчитывая символы) первого дочернего текстового узла элемента р. Затем можно установить значение конечной точки, располагаемой перед первым символом последнего дочернего текстового узла элемента р. Результирующая область определяет текст элемента em. 4. От р-элемента. С точки зрения элемента р, диапазон можно определить смещением от узла 1 (конец второго узла, вложенного в элемент р) до узла 2 (начало третьего узла). Эти непохожие друг на друга способы предоставляют большую гибкость, однако вы не всегда будете знать, как их использовать. Не стоит отчаиваться, методы объектов Range словаря W3C помогут вам выбрать подход для подсчета смещения. Начальная точка объекта Range может находиться в одном элементе, а конечная точка — в другом. Например, рассмотрим следующий HTML-код. <р> And how to introduce our <em>very special</em> guest:</p> В тексте, выделенном полужирным шрифтом, отображается содержимое объекта Range. Видно, что выделенная область пересекает границы элемента таким образом, что при замене текста в этой области не всегда удобно использовать свойства объекта HTML или свойства узла объекта. В инструкции W3C есть правила, согласно которым создатели браузеров должны предусмотреть в своих программных продуктах средства перемещения и удаления HTML- содержимого, пересекающего границы узлов. Важной характеристикой объекта Range является его размер, который может быть нулевым или составлять несколько символов. Начальная и конечная точки всегда располагаются между символами. Когда начальная и конечная точки находятся в одном и том же месте, объект Range выступает в роли указателя на место вставки текста. Управление выделениями Для создания объекта Range используйте метод document. createRange (). Приравняйте объект Range, возвращаемый этим методом, к переменной, которую впоследствии можно использовать для управления выделенной областью. var rag = document.createRange() Наряду с активным объектом Range, хранящимся в переменной, также можно использовать другие методы объекта для того, чтобы установить начальную и конечную точки области. Если область должна состоять из всего содержимого узла, то используйте два эффективных метода: selectNode () и select Con tents (). Основной параметр для обоих методов — это ссылка на узел, содержимое которого необходимо включить в область. Различие между этими двумя методами заключается в способе подсчета смещения для области (эти методы рассмотрены детально ниже в этой главе). Другой набор методов (setStartBef ore (), set Star t After {), setEndBef ore (), setEndAf ter ()) предоставляет возможность установки значения каждой точки по отдельности относительно расположения границ узла. Чтобы более точно задать 1058 Часть IV. Объекты языка JavaScript
границы области, используйте методы setStart () и setEnd (), позволяющие определить исходный узел (указывающий начало отсчета смещения) и целочисленное значение смещения. Если требуется указать точку вставки (например, необходимо вставить определенное содержимое в существующий узел), расположите конечную точку в выбранном месте, а затем запустите метод collapse (). Параметр метода определяет, в каком месте (в конечной или начальной точке области) должен запуститься метод collapse. Набор других методов позволяет сценариям напрямую управлять содержимым области. Можно копировать (cloneContents ()), удалять (dele teCon tents (), extract Contents ()), вставлять узел (insertNode ()) и даже размещать содержимое области в новом родительском узле (surroundContents ()). Некоторые свойства позволяют сценариям проверять информацию об области (например, значения смещения), содержащих их контейнерах, кроме того, просмотреть сведения о состоянии области и данные о внешнем наиболее близком узле, содержащем начальную и конечную точку. Браузер NN содержит дополнительный метод управления объектом Range (который фактически является методом объекта, включающего в себя Range) — он называется createContextual Fragment (). Этот метод позволяет сценариям создать полноценный узел (Document Fragment) из произвольных строк содержимого HTML (данная особенность пока еще не предложена в W3C DOM). Описываемый метод изначально был разработан как дополнительный, который в конечном счете стал свойством innerHTML в браузере NN6+/Mozl+. Управления объектом Range используется специфический набор операторов, необходимых для выполнения самых простых задач. При использовании объекта Range обычно выполняют три основных действия. 1. Создание текстовой области. 2. Установка начальной и конечной точек. 3. Провести изменение или перемещение области. Как только вы почувствуете себя уверенно в управлении объектом Range, то сразу поймете, что он обеспечивает достаточно высокий уровень гибкости в сценарии, особенно при управлении содержимым тела страницы. Чтобы получить сведения об основных способах применения объекта Range в сценариях, просмотрите примеры, описывающие отдельные свойства и методы, представленные в следующих разделах. Свойства collapsed Значение: булево Чтение/Запись Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safaril+ Свойство collapsed сообщает о том, установлены ли начальная и конечная точки области в одном и том же элементе документа. Если значение эквивалентно true, то начальный и конечный контейнеры области совпадают, совпадают также и значения смещений. Это свойство может использоваться для проверки того, представляет ли выделенная область место вставки содержимого перед новым узлом. if (mg. collapsed) { rng. insertNode (ссылка На НовыйУзел) } Глава 35. Текстовые объекты тела страницы 1059
Пример Используйте в приложении The Evaluator встроенный объект rng для изучения свойства collapsed. Перезагрузите страницу и включите в выделение следующий узел, rng.selectNode(document.body) Введите в верхнее текстовое поле a.collapsed. Это выражение возвратит результат false, поскольку конечная точка выделения другая. См. также: свойства endContainer, endOf f set, startContainer, startOf f set; метод Range.collapse(). coxnmonAnces torCon tainer Значение: ссылка на объект узла Чтение/Запись Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari 1+ Свойство commonAncestorContainer возвращает ссылку на узел в дереве документа, в котором расположены начальная и конечная точки диапазона. Нередко начальная точка области находится в одном узле, а конечная — в другом. В этом случае обобщенный узел состоит из обоих узлов (как правило, это узел document. body). В спецификации W3C DOM разделяемый обобщенный узел называется корневым узлом области (термин, который предоставляет больше информации). Пример Используйте в приложении The Evaluator встроенный объект rng для изучения свойства commonAncestorContainer. Перезагрузите страницу. Установите начальную точку непосредственно перед началом содержимого элемента туЕМ, а конечную — в конце внешнего элемента туР. rng.setStartBefore(document.getElementByld("туЕМ").firstChild) rng.setEndAfter(document.getElementByld("туР").lastChild) Удостоверьтесь, что выделение включает узел my EM (слово all) и заканчивается элементом туР. rng. toStringO Проверьте также, что контейнеры конечных точек представляют разные узлы. rng.startContainer.tagName rng.endfcontainer.tagName Наконец, узнайте, какой узел содержит обе конечные точки. rng.commonAncestorContainer.id Вы получите результат туР, поскольку именно он содержит узлы туР и туЕМ. См. также: свойства endContainer, endOf f set, startContainer, startOf f set; все методы set и select объекта Range. endContainer startContainer Значение: ссылка на объект узла Чтение/Запись Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Свойства endContainer и startContainer возвращают ссылку на узел дерева иерархической структуры документа, содержащий начальную и конечную точки области, соответственно. Имейте в виду, что объектная модель автоматически рассчитывает размер 1060 Часть IV. Объекты языка JavaScript
контейнера, сам же контейнер может и не соответствовать необходимой ссылке, используемой для установки начальной и конечной точек области. Например, при использовании метода selectNode () для установки начальной и конечной точек области, окружающей необходимый узел, контейнеры конечных точек наиболее вероятно будут попадать в следующие по уровню узлы. Таким образом, если сначала необходимо расширить область для включения в нее узла, содержащего текущую начальную точку, используется значение, возвращаемое свойством st art Container, в качестве параметра метода setStartBef ore (). rng.setStartBefore(rng.startContainer) Пример Используйте в приложении The Evaluator встроенный объект rng для изучения свойств endContainer и startContainer. Перезагрузите страницу и включите в выделение узел туЕМ. rng.selectNode(document.getElementByld("туЕМ") Изучите контейнеры начальной и конечной точек выделения. rng.startContainer.id rng.endContainer.id Поскольку в выделении содержится весь элемент туЕМ, то начальная и конечная точки выделения находятся за его пределами. Таким образом, контейнером последних выступает объект туР, который содержит элемент туЕМ. См. также: свойства commonAncestor, endOf f set, startOf f set, а также все методы set и select объекта Range. endOffset startOffset Значение: целочисленное Чтение/Запись Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safaril+ Свойства endOf f set и startOffset возвращают целочисленное значение количества символов или узлов, которое определяет расположение начальной и конечной точек области, соответственно. Эти смещения указаны для узлов, выполняющих роль контейнеров для области (см. свойства Range. endContainer и Range. startContainter, описанные ранее в этой главе). Когда граница области находится на границе узла (или, лучше сказать, "между" узлами), возвращаемое целое число задает количество узлов (отсчет начинается с нуля от граничного контейнера). Если граница области находится посередине текстового узла, возвращаемое целое число представляет собой индекс символа внутри этого узла. Каждая граница имеют свою систему измерения (символы или узлы, в зависимости от используемых контейнеров), что нередко приводит к путанице (если не быть достаточно внимательным). При этом возвращаемое целое число для конечной точки может быть меньшим, чем значение для начальной точки. Рассмотрим следующие вложенные элементы. <р> This paragraph has an <em>emphasized</em> segment.</p> Следующий оператор устанавливает значение начальной точки области внутри первого узла, а также конечную точку области в закрывающем элементе ЕМ узла var rng = document.createRange(); rng.setStart{document.getElementByld("myP").FirstChild,19); rng.setEndAfter(document.getElementByld("myEM")); Глава 35. Текстовые объекты тела страницы 1061
Используя полужирный шрифт для представления текста области и символ вертикальной черты (|) для определения границ в пределах узлов, можно представить, как выполняется описанный выше сценарий. <р icWmyP" >This program has | an <em id="myEMM >emphasized</em> | segment.</p>; Поскольку начало области находится в текстовом узле (первый дочерний узел элемента р), значение start Of f set равно 19; оно определяет расположение символа а относительно an относительно начала узла, его содержащего. Однако конечная точка находится в конце элемента em. Сценарий распознает эту точку как границу узла и поэтому осуществляет подсчет значения endOf f set внутри содержимого внешнего контейнера— элемента р. Значение endOf f set равно 2 (текстовый узел элемента р имеет индекс 0; элемент em имеет индекс 1; конечная точка находится в начале последнего текстового узла элемента р, имеющего индекс 2). При создании сценариев значения endOf f set и start Offset используются достаточно часто; также часто применяются свойства endContainer и startContainer для получения целочисленных значений смещения. Пример Используйте в приложении The Evaluator встроенный объект rng для изучения свойств endOf f set и start offset. Перезагрузите страницу и включите в выделение узел туЕМ, а затем сместите начальную точку за пределы символов текстового узла ту Р. rng.selectNode(document.getElementByld("myEM")) rng.setStart(document.getElementById("myP").firstChild, 7) Изучите типы узлов контейнеров начальной и конечной точек выделения. rng.startContainer.nodeType rng.endContainer.nodeType Тип контейнера начальной точки имеет индекс 3 (текстовый узел), а контейнер конечной точки равен 1 (элемент). Определите смещение начальной и конечной точек выделения. rng.startOffset rng.endOffset См. также: свойства endContainer, startContainer, все методы set и select объекта Range. Методы cloneContents () cloneRange() Возвращаемое значение: ссылка на узел Document Fragment; ссылка на объект Range Совместимость: Winffi-, Macffi-, NN7+, Mozl+, Safari 1+ Метод cloneContents () (не поддерживаемый в браузере NN6, однако совместимый с будущими его версиями) хранит копию содержимого объекта Range и возвращает ссылку на эту копию. Копия хранится в памяти браузера, но не является частью дерева узлов документа. Метод cloneRange () (используется в NN6+) выполняет те же действия с областью и хранит копию области в памяти браузера. Область может содержать части соседних узлов; она не обязательно находится в одном элементе узла. Именно поэтому данные области относятся к типу Document Fragment (один из типов узлов W3C DOM). Поскольку Document- Fragment — это реальный узел, его можно использовать в других методах узлов дерева 1062 Часть IV. Объекты языка JavaScript
документов, в которых узлы представлены в виде параметров. Вы можете смело клонировать текстовую область для того, чтобы вставить полученные копии в другом месте документа. Наоборот, метод cloneRange () предназначен для работы с объектами Range. Если вы будете управлять не только содержимым области, но и всем объектом Range, то этот метод возвратит ссылку на него (см. случай, когда область заключает в себя весь документ). Метод cloneRange () можно использовать для получения копии области, что позволяет сравнить конечные точки текущей и другой области (задача выполняется с помощью метода Range. compareBoundaryPoints ()). Пример Используйте в приложении The Evaluator встроенный объект rng для изучения метода cloneContents. Перезагрузите страницу и включите в выделение узел ту Р. rng.selectNode(document.getElementById{"myP") Скопируйте исходное выделение и сохраните его в переменной Ь. b = rng.cloneContents() Переместите исходное выделение так, чтобы точка его вставки располагалась в конце тела страницы. Для этого сначала расширьте его для включения элемента body, а затем сверните в конце выделения. rng.selectNode(document.body) rng.collapse(false) Далее вставьте копию выделения в конце элемента body, rng.insertNode(b) Если вы прокрутите страницу вниз, то увидите, что копия текста не помещается в границы выделения, что приводит к ошибке выполнении метода insertNode (). Но вы всегда можете воспользоваться методом appendChildO или insertBefore О, чтобы добавить копию выделения в иерархическую структуру документа. См. также: методы Range. compareBoundaryPoints (), extractContents (). collapse ( [начальноеБулевоЗначениё]) Возвращаемое значение: отсутствует. Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari 1+ Метод collapse () используется для сжатия области от ее текущего размера до точки вставки символа. Сжатие области выполняется в том случае (хотя на первый взгляд это и кажется лишним), когда в функции сценария обрабатывается содержимое тела страницы или большая часть ее текста. Например, в типичном цикле сценария подсчета количества слов создается текстовая область, полностью содержащая тело страницы. Чтобы начать процедуру подсчета слов, нужно сжать область до точки вставки, расположенной в ее начале. Затем, используя метод expand (), присвоить области первое слово текста (и увеличьте счетчик, если метод expand () возвращает значение true). С этого момента область расширится в направлении "от" первого слова. Может потребоваться сжать область в конце текущего выделения так, чтобы дальнейший поиск начинался со следующего текущего слова. Впоследствии метод collapse () будет выполняться с несколько измененными параметрами. Необязательный параметр метода collapseO — это булево значение, задающее расположение точки вставки после сжатия области (в конце или в начале текущей области). Действия по умолчанию эквиваленты значению true. Это означает, что пока метод collapse () не перенастроен противоположным образом, он будет преобразовывать область в точку вставки, располагающуюся перед текущей областью. Данный метод удобно использовать Глава 35. Текстовые объекты тела страницы 1063
вначале сценария подсчета количества слов, поскольку сжатие текстовой области лучше проводить именно здесь. Для последующих преобразований текста потребуется сжать область таким образом, чтобы результирующая точка вставки находилась после текущей области. Таким образом, в методе collapse () рекомендуется задать параметр false. Пример Чтобы ознакомиться с примерами использования метода collapse (), обратитесь к листингам 35.11 и 15.14. См. также: методы Range. set End (), Range. setStart (). compareBoundaryPoints(целоеЧисло, ссылкаНаИсходнуюОбласть) Возвращаемое значение: целочисленное (-1,0 или 1) Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ Создание нескольких объектов областей и присвоение их разным переменным не является проблемой. Вы можете использовать метод compareBoundaryPoints () для сравнения относительного расположения начальной и конечной точек областей. Одна область представляет собой объект, который используется для вызова метода compareBoundaryPoints (), другая же область — это второй параметр метода. Порядок, в котором происходит обращение к этим областям, влияет на результаты, полученные на основе значения первого параметра. Значением первого параметра может быть одна из четырех констант, являющихся свойствами статического объекта Range: Range. START_TO_START, Range. START_TO_END, Range. END_TO_START и Range. END_TO_END. Что именно определяют эти значения для текущей области, зависит от того, что указано в качестве второго параметра и точки, с которой проводится сравнение. Например, рассмотрим следующее содержимое страницы, которое включает две текстовые области, определенные внутри нее. It was the best of times. Первая текстовая область (в данном случае она присвоена переменной rngl) отображается полужирным шрифтом, в то время как вторая текстовая область (rng2) представлена полужирным курсивом. Другими словами, переменная rng2 вложена в rngl. Можно сравнить начальное место расположения переменной rngl относительно rng2 с помощью значения Range . START_TO_START, заданного в качестве первого параметра метода compareBoundaryPoints(). var result = rngl.compareBoundaryPoints(Range.START_TO_START, rng2); Значение, возвращаемое методом compareBoundaryPoints (), является целочисленным. Если места расположения обеих анализируемых точек совпадают, то значение возвращаемой переменной равно 0. Если начальная точка так называемой исходной области располагается после области, из которой запускается метод, возвращаемое значение равно -1; в противном случае возвращаемое значение равно 1. Таким образом, можно сделать вывод: поскольку начальная точка rngl находится после начальной точки rng2, то методом возвращается значение переменной, равное -1. При изменении оператора для запуска метода в точке rng2 результат будет эквивалентен 1. var result = rng2.compareBoundaryPoints(Range.START_TO_START, rngl); На практике этот метод применяется для получения информации о том, совпадают ли обе области, совпадает ли одна и та же точка границ обеих областей, и начинается ли одна область там, где заканчивается другая. 1064 Часть IV. Объекты языка JavaScript
Пример Страница, представленная листингом 35.4, позволяет сравнивать текстовые диапазоны в NN6+/Moz. Нижний абзац содержит элемент span, в который включен объект Range, назначаемый фиксированному текстовому узлу в процессе загрузки страницы (в функции init ()). Этот фиксированный диапазон будет использоваться при сравнении с текстовым выделением. После создания выделения в сценарии используются все четыре варианта метода compareBoundary Points () для сравнения начальной и конечной точек выделения и фиксированного диапазона. В первом столбце таблицы показано значение, возвращенное методом, а в третьем столбце приведено описание полученных результатов. Чтобы ознакомиться с работой сценария этой страницы, сначала выделите первое слово фиксированного текстового диапазона (медленно перетащите указатель над красным текстом). Как видите, начальные точки обоих диапазонов пока одинаковые, поскольку возвращается значение 0. Метод compareBoundary Points () в любом случае применяется по отношению к фиксированному текстовому диапазону, поэтому сравнение выполняется с точки зрения этого диапазона. Таким образом, в первой строке таблицы для параметра START_TO_END указано, что начальная точка фиксированного диапазона следует раньше конечной точки выделения; в результате возвращается значение -1. Существуют и другие типы выделений: ■ начало в тексте перед фиксированным диапазоном и конец— в фиксированном диапазоне; ■ начало в тексте в фиксированном диапазоне и конец — за пределами фиксированного диапазона; ■ начало и конец в тексте фиксированного диапазона; ■ начало и конец в тексте перед фиксированным диапазоном; ■ начало в тексте после фиксированного диапазона. Изучите возвращаемые результаты в каждом из случаев. <html> <head> <title>TextRange.compareBoundaryPoints() Method</title> <style type="text/ess"> td {text-align:center} .propName {font-family:Courier, monospace} #fixedRangeElem {color:red; font-weight:bold} </style> <script type="text/javascript"> var fixedRange; function setAndShowRangeData() { try { var selectedRange = window.getSelectionO; selectedRange = selectedRange.getRangeAt(0); var resultl = fixedRange.compareBoundaryPoints( Range.STARTJTO_END, selectedRange); var result2 = fixedRange.compareBoundaryPoints( Range . START__TO_START, selectedRange) ; var result3 = fixedRange.compareBoundaryPoints( Range.END_TO_START, selectedRange); Глава 35. Текстовые объекты тела страницы 1065
} var result4 = fixedRange.compareBoundaryPoints( Range.END_TO_END, selectedRange); document.getElementByld("Bl").innerHTML = result1; document.getElementByld("comparel").innerHTML = getDescription(resultl); document.getElementByld("B2").innerHTML = result2; document.getElementByld("compare2").innerHTML = getDescription(result2); document.getElementByld("B3").innerHTML = result3; document.getElementByld("сотрагеЗ").innerHTML = getDescription(result3); document.getElementByld("B4").innerHTML = result4; document.getElementByld("compare4").innerHTML = getDescription(result4); } catch(err) { alert("Vital Range or Selection object services are not yet implemented in this browser."); } function getDescription(comparisonValue) { switch (comparisonValue) { case -1 : return "comes before"; break; case 0 : return "is the same as"; break; case 1 : return "comes after"; break; default : return "vs."; } } function init() { fixedRange = document.createRange(); fixedRange.selectNodeContents(document. getElementByld("fixedRangeElem").firstChild); fixedRange.setEnd(fixedRange.endContainer, fixedRange.endContainer.nodeValue.length); } </script> </head> <body onload="init()"> <hl>TextRange.compareBoundaryPoints() Method</hl> <hr /> <p>Select text in the paragraph in various places relative to the fixed text range (shown in red). See the relations between the fixed and selected ranges with respect to their start and end points.</p> ^table id="results" border="l" cellspacing="2" cellpadding="2"> <tr> <th>Property</th> <th>Returned Value</th> 1066 Часть IV. Объекты языка JavaScript
<th>Fixed Range vs. Selection</th> </tr> <tr> <td class="propName">StartToEnd</td> <td class="count" id="Bl">&nbsp;</td> <td class="count" id="Cl">Start of Fixed <span id=Mcomparel">vs.</span> End of Selection</td> </tr> <tr> <td class="propName">StartToStart</td> <td class="count" id="B2">&nbsp;</td> <td class="count" id="C2">Start of Fixed <span id="compare2">vs.</span> Start of Selection</td> </tr> <tr> <td class=npropName">EndToStart</td> <td class="count" id="B3">&nbsp;</td> • <td class="count" id="C3">End of Fixed <span id="compare3">vs.</span> Start of Selection</td> </tr> <tr> <td class="propName">EndToEnd</td> <td class="count" id="B4">&nbsp;</td> <td class="count" id="C4">End of Fixed <span id="compare4">vs.</span> End of Selection</td> </tr> •</table> <hr /> <p onmouseup="setAndShowRangeData()">Lorem ipsum dolor sit, <span id="fixedRangeElem">consectetaur adipisicing elit </span>, sed do eiusmod tempor incididunt ut labore et dolore aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </body> </html> compar eNode (ссылкаНаУзел) Возвращаемое значение: целочисленное (-1, 0 или 1) Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari 1+ Этот метод возвращает целочисленный код, который указывает расположение определенного узла относительно диапазона. Ссылка на узел представляет единственный аргумент метода. Возвращаемые целочисленные коды могут быть представлены и встроенными константами: Range.NODE_BEFORE, Range.NODE_AFTER, Range.NODE_BEFORE_AND_AFTER, Range .NODE_INSIDE. Первые два параметра вполне очевидны; третий параметр описывает случай, когда узел начинается перед диапазоном, а заканчивается после него. Четвертая константа, наоборот, описывает случай полного включения узла в диапазон. См. также: метод compare Point (). comparePoint (ссылка НаУзел, смещение) Возвращаемое значение: целочисленное (0,1, 2 или 3) Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari 1+ f Глава 35. Текстовые объекты тела страницы 1067
Этот метод возвращает целочисленный код, который указывает расположение определенного узла относительно диапазона после смещения. Аргументы метода — это ссылка на узел и смещение (количество элементов или символов в текстовом узле). Возвращаемые целочисленные константы задают расположение узла относительно точки, а не диапазона. Значение -1 указывает расположение перед начальной точкой диапазона, 1 — после конечной точки диапазона, а 0 — в самом диапазоне. См. также: метод compareNode (). createContextualFragment("текст") Возвращаемое значение: узел Document Fragment в W3C DOM Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Метод createContextualFragment () — это метод объекта Range браузера NN6 (расширение объекта Range в >УЗС DOM). Данный метод предоставляет способ, согласно которому с помощью средств W3C DOM второго уровня иерархической структуры узлов можно создать строку текста HTML (без или с помощью дескрипторов HTML) для вставки или добавления ее в существующее дерево узлов. В результате развития браузера NN6 этот метод заполнил "пробел11 в функциональных средствах и в конечном счете был одобрен для использования в браузерах Netscape (что уравновесило свойство inner HTML в браузерах Microsoft). В данном методе устранена необходимость создания сложного элемента HTML в результате построения последовательностей методов document. createElement () и document. createTextNode () для каждого фрагмента. Кроме того, лишней оказалась и возможность перенастройки дерева узлов, предшествующая вставке в существующий документ текстового фрагмента. Однако наличие свойства inner HTML во всех объектах элементов уменьшает значение метода createContexualFragment (), позволяя использовать один и тот же код в различных браузерах. Параметром метода createCont exual Fragment () может быть любой текст, включая дескрипторы HTML. Однако для активизации метода необходимо иметь готовый объект Range. Последовательность операций по созданию узла для области документа должна быть следующей. var rng = document.createRange(); rng.seleetNode(document.body) // подойдет любой узел var fragment = rng.createContextualFragment("<H1>Howdy</HI>"); Как и область документа, узел не является частью дерева узлов документа до тех пор, пока вы не используете ее в качестве параметра одного из методов — Node. insert Be f ore () или Node. appendChild (). Пример Используйте встроенный объект rng приложения The Evaluator для замены части дерева узлов документа. Сначала создайте фрагмент на основе встроенного диапазона. b = rng.createContextualFragment("<span style='font-size:22pt'> a bunch of</span>") Этот фрагмент содержит элемент span, в котором располагается текстовый узел. Теперь вы можете изучить свойства фрагмента, введя в нижнее поле приложения Ь. Чтобы заменить элемент туЕМ страницы новым фрагментом, используется метод с г eateQontextual Fragment () внешнего элемента ту Р. document.getElementByld("туР").replaceChild(b, document.getElementByld("туЕМ")) 1068 Часть IV. Объекты языка JavaScript
Теперь фрагмент становится полноправным дочерним узлом элемента туР. Вы можете ввести в верхнем поле приложения следующее выражение для получения копии текстового узла элемента span. document .getElementById( "myP") .childNodes [1] .firstChild. node Value См. также: объект Node (глава 15). deleteContents() Возвращаемое значение: отсутствует Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safari 1+ Метод deleteContents () удаляет все содержимое текущей области дерева документа. После удаления область уменьшается до точки вставки, которая просто разделяет содержимое (если такое существует) соседних узлов. Расположение границ области содействует тому, браузер переопределяет расположение элемента, заключенного внутрь области, после удаления последней. Простое удаление — это такое удаление, при котором границы области симметричны. В качестве примера рассмотрим следующий фрагмент НШЬ с выделенной полужирным шрифтом областью. <p>One paragraph with an <em>emphaeis</em> inside.</p> После удаления содержимого этой области исчезнет текстовый узел внутри элемента em, но сам элемент em останется в дереве документа (без дочерних узлов). Наряду с этим область может определяться в качестве второго дочернего узла элемента р, как показано ниже. <p>One paragraph with an <em>emphaeis</em> inside.</p> При удалении содержимого области также удаляются текстовый узел и узел элемента em, при этом элемент р имеет единственный полноценный тестовый дочерний узел (хотя в этом случае между словами an и inside будет находиться дополнительный пробел, поскольку при сжатии элемента em пробел автоматически не удаляется). В случае несимметричности границ области браузер сделает все возможное, чтобы обеспечить целостность дерева узлов документа посде удаления. Рассмотрим следующий фрагмент HTML-кода и выделенную в нем область. <p>One paragraph with an <em>emphasis</em> inside.</p> После удаления содержимого выделенной области дерево узлов документа для этого фрагмента кода будет выглядеть следующим образом. <p>One paragraph <em>emphasis</em> inside.</p> Область сжимается в точку вставки после дескриптора <ет>. .Однако примите к сведению, что элемент em будет "заботиться" о тексте, который все еще остается под его управлением. Возможны также и другие комбинации расположения границ области и узлов. Поэтому всегда проверяйте, являются ли границы области асимметричными, перед выполнением удаления и применением новых параметров. Пример Используйте встроенный объект rng приложения The Evaluator для знакомства с методами удаления текстовых узлов и элементов. Сначала назначьте текстовый диапазон текстовому узлу, содержащемуся в элементе туЕМ. rng.setStart(document. getElementByld ("myEM").firstChild, 0) rng.setEnd(document.getElementByld("myEM").lastChild, document.getElementByld("myEM").lastChild.length) Проверьте существование диапазона, введя в нижнее поле а, чтобы ознакомиться с его свойствами. Оба контейнера представлены тестовыми узлами (на самом деле это один и тот же текстовый узел), поэтому смещение измеряется в символах. Глава 35. Текстовые объекты тела страницы 1069
Далее удалите содержимое диапазона. rng.deleteContents() Курсивное слово all удаляется из дерева узлов, а вот элемент ту ЕМ — нет. Чтобы доказать это, добавьте в элемент новый текст. document.getElementByld("myEM").innerHTML = "a band of " Курсивное начертание элемента em применяется к новому тексту, как и должно быть. Измените границы диапазона, чтобы включить в него элемент myEM. rng. selectNode (document. get-Element By Id ("myEM" ) ) Опять изучите свойства объекта Range, введя rng в нижнее поле приложения. Контейнер представлен элементом р, который содержит элемент em. Смещение измеряется в узлах, а не символах. Удалите содержимое диапазона. rng.deleteContents() В результате пропадет не только курсивный текст, но и весь элемент myEM; элемент туР получит два дочерних узла. Чтобы проверить это, введите в верхнее поле приложения следующие два выражения. document.getElementByld("myP").childNodes.length document.getElementById("myP").childNodes[0].nodeValue Объедините два сестринских узла, выполнив метод normalize () их контейнера. document.getElementByld("myP").normalize() Для проверки полученного результата подсчитайте количество дочерних узлов. См. также: метод Range. extraContents (). detach() Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Метод detach () извещает браузер о необходимости извлечь текущий объект области из DOM. В процессе этой операции размер объекта области приравнивается нулю, что приводит к ошибке сценария при попытке получения доступа к нему. Если необходимо, то можете назначить используемой переменной значение новой области. Не спешите удалять область после завершения всех необходимых операций (в конечном счете, задействованные для области ресурсы браузера не столь велики). Практика "уборки за собой мусора" весьма поощрительна, особенно если сценарий повторно создает и управляет рядом новых выделенных областей. См. также: метод document. createRange (). extractContents() Возвращаемое значение: ссылка на узел Document Fragment Совместимость: Winffi-, MacIE-, NN7+, Mozl+, Safari 1+ Метод extractContents () удаляет содержимое области и возвращает ссылку на узел фрагмента документа, хранящегося в памяти браузера, однако больше не являющегося частью дерева узлов документа. Содержимое области может состоять из частей нескольких узлов и находиться за пределами одного узла элемента. Таким образом, ее данные относятся к типу Document Fragment (один из типов узлов W3C DOM). Поскольку Document Fragment — это реально существующий узел, его можно использовать в других методах дерева документа, в которых узлы выступают в качестве параметров. В любом случае можно извлечь текстовую область из одного места документа и вставить ее в другую часть. 1070 Часть IV. Объекты языка JavaScript
Пример В приложении The Evaluator используйте встроенный объект rng для изучения метода extract Contents (). Для начала включите в этот встроенный объект текст элемента тпуР. rng.selectNode(document.getElementByld("myP")) Далее извлеките содержимое диапазона и сохраните его в переменной Ь. b = a.extractContents() Вставьте извлеченный фрагмент в конец тела страницы. document.body.appendChild(b) Если прокрутить страницу, то можно ознакомиться с добавленным текстом. См. также: методы cloneContents (), deleteContents (). insertNode (ссылкаНаУзел) Возвращаемое значение: отсутствует Совместимость: WinlE-, Macffi-, NN7+, Mozl+, Safari 1+ Метод insertNode () вставляет узел в начальной точке текущей области. Вставляемый узел может быть фрагментом текстового узла, а его создателем может быть любое соответствующее средство, например, метод document. createNode () или любой метод извлечения узла из структуры документа. Пример Листинг 35.5 демонстрирует возможности метода insertNode (), а также элемента select. В данном примере вы также найдете упрощенный вариант функции отмены операций изменения текстовых данных. В странице, представленной этим кодом, пользователь может выделить произвольный текст абзаца, а сценарий автоматически преобразует его символы в прописные. Эта задача требует выполнения нескольких операций, в частности, создания выделения с помощью метода window.getSelection(). После проверки существования в вьщелении текста (вьщеление не свернуто) оно будет представлено объектом Range (чтобы текст можно было сохранить в глобальной переменной). После этого вьщеление удаляется из дерева узлов документа и отображается как свернутая точка вставки. Копия выделения в форме объекта Range сохраняется в объекте undoBuf f er, позволяющем вставить удаленный текст в исходное место. В сценарии создается новый текстовый узел, содержащий прописной вариант исходного текста. Метод insertNode () вставляет преобразованный текст в свернутую точку вставки. В процессе отмены операции действия выполняются в обратном порядке. Исходное расположение и текстовые строки извлекаются из объекта undoBuf f er. После создания объекта Range с исходными начальной и конечной точками исходный текст, преобразованный в текстовый узел, вставляется в свернутую точку вставки. Для полноты картины объект undoBuf f er возвращается в исходное состояние. <htmX> <head> <title>NN Selection Object Replacement</title> <script type="text/javascript"> var undoBuffer = {rng: {}, txt:""}; function convertSelection() { Глава 35. Текстовые объекты тела страницы 1071
var sel, grossRng, netRng, newText; try { sel * window.getSelectionO ; if (isel.isCollapsed) { grossRng = sel.getRangeAt(0); undoBuffer.txt = grossRng.toStringO; undoBuffer.rng.startContainer = # grossRng.startContainer; undoBuffer.rng.startOffset = grossRng.startOffset; undoBuffer.rng.endContainer = grossRng.endContainer; undoBuffer.rng.endOffset = grossRng.endOffset; sel.deleteFromDocument() ; netRng = sel.getRangeAt(0); newText = document.createTextNode(undoBuffer.txt. toUpperCase()); netRng.insertNode(newText); netRng.commonAncestorContainer.parentNode.normalize(); } } catch(err) { alert("Vital Range or Selection object services are not yet implemented in this browser."); .> function undoConversionO { var rng, oldText; if (undoBuffer.rng) { rng = document.createRange(); rng.setStart(undoBuffer.rng.startContainer, undoBuffer.rng.startOffset); rng.setEnd(undoBuffer.rng.endContainer, undoBuffer.rng.endOffset); rng.extractContents(); oldText = document.createTextNode(undoBuffer.txt); rng.insertNode(oldText); undoBuffer.rng = {}; undoBuffer.txt = ""; </script> </head> <body> <hl id="Hl_l">NN6+/Moz Selection Object Replacement</hl> <hr /> <p id="P_l" onmouseup="convertSelection()">This paragraph contains text that you can select. Selections are deleted and replaced by all uppercase versions of the selected text.</p> <button onelick="undoConversionO">Undo Last</button> <button onclick="location.reload(true)">Start Over</button> </body> </html> intersectsNode (ссылхаНаУзел) Возвращаемое значение: булево Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safaril+ 1072 Часть IV. Объекты языка JavaScript
Этот метод возвращает булево значение, указывающее на перекрывание (true) или неперекрывание (false) диапазона, и такое значение указывается в виде аргумента узла. См. также: метод compareNode (). isPointlnRange(ссылкаНаУзел, смещение) Возвращаемое значение: булево Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safaril+ Этот метод возвращает булево значение, указывающее на включение (true) или непопадание (false) определенного в качестве аргумента узла и смещенного узла в текущий диапазон. selectNode(ссылкаНаУзел) selectNodeContents(ссылкаНаУзел) Возвращаемое значение: отсутствует Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari 1+ Методы selectNodeO и selectNodeContents О — это наиболее удобные методы для задания начальной и конечной точек, между которыми размещается узел или его содержимое. Тип узла, который применятся в качестве параметра в обоих методах (текстовый узел или узел элемента), зависит от контейнера области и единиц измерения смещения точек (см. свойства контейнера и измерение смещения точек в объекте Range, описанные выше в этой главе). Используйте метод selectNode (), если необходимо определить узел элемента как такой, что должен быть выделен в виде области. Начальный и конечный узлы новой области — это самые близкие соседние узлы элемента. Смещение точек определяется в родительском узле выделяемого узла. Если вы выделяете текстовый узел, то его узел-контейнер для обоих точек диапазона принадлежит родительскому элементу текстового узла. При использовании метода selectNodeContents () узлы начального и конечного контейнеров представляют собой один и тот же элемент, определенный как параметр. Значения смещений определяются в виде количества узлов в этом элементе. Если выделить содержимое текстового узла, то последний будет выступать в роли родительского узла для начального и конечного элементов; при этом область сжимается в начале выделенного текста. Обычно узлы элементов определяются как параметры в любом из методов, что позволяет включить в область отдельные элементы (с помощью метода selectNode ()) или только их содержимое (метод selectNodeContents ()). Пример Используйте встроенный обьект rng приложения The Evaluator для изучения методов selectNodeO и selectNodeContents (). Начните с изменения границ этого объекта таким образом, чтобы он включил в себя элемент туР. rng.selectNode(document.getElementByld("туР")) Введите в нижнее поле а, чтобы ознакомиться со свойствами объекта диапазона. Поскольку он полностью включает узел абзаца, то его контейнером будет выступать элемент body (родительский элемент для элемента туР). Теперь измените диапазон так, чтобы он включал только содержимое элемента туР. rng.selectNodeContents(document.getElementByld("туР")) Щелкните на кнопке List Properties для повторного ознакомления со свойствами диапазона. Теперь контейнером диапазона является элемент р. См. также: методы setEndO, setEndAfterО, setEndBefore(), setStartO, setStratAfter(), setStartBefore(). Глава 35. Текстовые объекты тела страницы 1073
setEnd(ссылкаНаУзел, смещение) setstart(ссылкаНаУзел, смещение) Возвращаемое значение: отсутствует Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari 1+ Вам предоставляется возможность независимого задания начальной и конечной точек текстовой области. Для этого используются методы setStartO и set End (). Возможно, эти методы не настолько удобны, как selectNode () или selectNodeContents (), однако они позволяют получить окончательный наиболее точный результат относительного расположения границ области. Первый параметр обоих этих методов — это ссылка на узел. Такая ссылка может указывать на элемент или текстовый узел. Ваш выбор в данной ситуации также определяет систему исчисления, применяемую к целочисленному значению смещения, задаваемому в качестве второго параметра. В случае, если первый параметр является узлом элемента, смещение под- считывается как приращение дочерних узлов внутри определенного элемента узла. Если первый параметр представляет собой текстовый узел, то смещение подсчитывается как приращение символов внутри текстового узла. При определении начальной и конечной точек области с помощью этих методов ограничения на симметричность границ области не накладываются. Одна из границ может быть определена относительно текстового узла, а другая — относительно узла элемента (или наоборот). Для задания конечной точки области, равной последнему узлу или символу внутри текстового узла (в зависимости от единиц измерения параметра смещения), используйте свойство length. Например, для задания конечной точки в конце последнего узла элемента (предполагается, что во внешнем элементе существует несколько вложенных элементов и текстовых узлов) используется первый параметр. rng.setEnd(document.getElementByld("myP"), document .getElementByldC'myP").childNodes.length); Эти выражения достаточно громоздкие, поэтому лучше использовать сокращенную ссылку на значения параметров, как показано ниже. В данном случае конечная точка задается после последнего символа последнего узла элемента р. var nodeRef = document.getElementByldC'myP").lastChild; rng.setEnd(nodeRef.nodeValue.length); В двух предыдущих примерах (в которых использовалось свойство length), вы могли убедиться, что значения свойства всегда указывают на узел или позицию символа, находящиеся после последнего объекта области, так как процесс определения индекса объекта начинается с нуля. Обратите также внимание на то, что конец области и конечную точку узла можно определить с помощью четырех следующих методов: setEndAfter (), setEndBeforeO, setStartAf ter (), setStartBef ore (). Если необходимо задать конечную точку не на границе узла, то используйте методы setEnd () и setStart (). Пример Используйте встроенный объект rng приложения The Evaluator для знакомства с методами setEnd () и setStart (). В первом диапазоне назначьте начальную и конечную точки так, чтобы включить в него второй узел (элемент туЕМ) элемента myP. rng.setStart(document.getElementByldC'myP"), 1) rng.setEnd(document.getElementByldC'myP"), 2) Текст, включенный в диапазон, состоит из слова all и пробела, который представлен элементом ту ЕМ." Чтобы доказать это, введите в верхнее текстовое поле следующее выражение (Safari 1.0 возвращает некорректное значение). rng.toStringO 1074 Часть IV. Объекты языка JavaScript
Если щелкнуть в области результатов справа от слова all, то можно доказать существование пробела. Проверяя свойства диапазона (введите в нижнее поле а), вы замените, что диапазон начинается перед и заканчивается после элемента туЕМ. Далее измените начальную точку, разместив ее в первом текстовом узле элемента ту Р. rng.setStart(document.getElementByld("royP").firstChild, 11) Щелкните на кнопке List Properties, чтобы получить сведения о свойствах startContainer (текстовый узел) и start Offset (расположение символа начальной точки) диапазона. Как и следовало ожидать, свойства, определяющие конечную точку диапазона, не изменились. Введите в верхнем поле приложения rng. toString (), чтобы убедиться во включении в диапазон текста обоих узлов элемента туР. См. также: методы selectNode (), selectNodeContents (), setEndAf ter (), setEndBefore(), setStartAfter(), setStartBefore(). setEndAfter(ссылхаНаУзел) setEndBefore{ссылхаНаУзел) setStartAfter(ссылкаНаУзел) setStartBefore(ссылхаНаУзел) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari 1+ Начальную и конечную точки текстовой области можно задать в соответствии с существующими границами узла с помощью указанных четырех методов. Ключевые слова before и after в именах методов используются для того, чтобы определить, какую границу узла использовать в качестве границы области. Например, применение методов setStartBef ore () и setEndAf ter () для одного и того же узла элемента в качестве параметра аналогично использованию метода selectNode () для того же элемента. В качестве параметра одного из этих методов можно определить текстовый узел. Поскольку эти методы оперируют только границами узлов, значения смещения всегда определяются с учетом расположения узла, а не символа. Возьмите на заметку, что границы области необязательно должны быть симметричными (другими словами, одна граница может располагаться внутри одного узла, а другая — внутри другого). Пример Используйте встроенный объект rng приложения The Evaluator для изучения методов setEndAfter(), setEndBefore(), setStartAfter() и setStartBefore(). Начните с установки начальной и конечной точек так, чтобы в диапазон попал элемент туЕМ, содержащийся в элементе туР. rng.setStartBefore(document.getElementByld("туЕМ")) rng.setEndAfter(document.getElementByld("myEM")) Текст, включенный в диапазон, состоит из слова all и пробела, который представлен элементом туЕМ. Чтобы доказать это, введите в верхнее текстовое поле следующее выражение (Safari 1.0 возвращает некорректное значение). rng.toString() Далее измените начальную точку так, чтобы диапазон начинался с первого текстового узла элемента туР. rng.setStartBefore(document.getElementByld("туР").firstChild) Глава 35. Текстовые объекты тела страницы 1075
Введите в нижнее поле приложения rng, чтобы ознакомиться со свойствами start- Container (должно приравниваться к элементу р) и endContainer (должно приравниваться к элементу em) диапазона. См. также: методы selectNode (), selectNodeContents (), setEnd (), setStart (). surroundContents(ссылкаНаУзел) Возвращаемое значение: отсутствуют Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari 1+ Метод surroundContents О используется для заключения текущей области в новый родительский элемент. Новый родительский элемент указывается как параметр метода. В процессе выполнения метода ни один из элементов или узлов дерева документа не удаляется и не перемещается, однако текущая область становится дочерним узлом нового узла. Если текущая область совпадает с уже существующим узлом, то связь между областью и его родительским узлом рассматривается как между "дедом и внуком". Применив этот метод, можно поместить выделенный посетителем страницы текст в элемент span, позволяющий отобразить свое содержимое с помощью специальных шрифтов или других параметров таблицы стилей. Если узел элемента используется в качестве нового родительского узла, имеющего свои собственные дочерние узлы, то эти узлы удаляются перед тем, как элемент располагается в новом контейнере. Поэтому для получения наиболее прогнозируемых результатов используйте в качестве параметра метода surroundContents () узлы без содержимого. Пример В листинге 35.6 показан пример использования метода surroundContents О для вставки диапазона в новый элемент. В процессе загрузки страницы глобальная переменная newSpan сохраняет элемент span, использующийся как прототип элементов, которые будут представлять новые родительские узлы. После выделения текста в одном из двух абзацев выделение преобразуется в диапазон. Далее метод surroundContents () вставляет этот диапазон в элемент newSpan. Поскольку элемент span относится к классу hi lite, то он приобретает все стили, заданные для класса. # NN7 и Mozilla (по крайней мере до версии 1.4) неправильно выполняют этот ме- /Ншитещ тод при использовании диапазонов, полученных на основе объектов selection * .^-^ или диапазонов, не выровненных в элементе. <html> <head> <title>Range.surroundContents() Method</title> <style type="text/ess"> .hilite {background-color:yellow; color:red; font-weight:bold} </style> <script type="text/javascript"> var newSpan = document.createElement("span"); newSpan.с1assName = "hilite"; function highlightSelectionO { var sel, rng; try { sel = window.getSelectionO ; 1076 Часть IV. Объекты языка JavaScript
if (Isel.isCollapsed) { rng = sel.getRangeAt(0); rng.surroundContents(newSpan.cloneNode(false)); catch(err) { alert("Vital Range or Selection object services are not yet implemented in this browser."); </script> </head> <body> <hl>Range.surroundContents() Method</hl> <hr /> <p onmouseup="highlightSelection()">These paragraphs contain text that you can select. Selections are surrounded by span elements that share a stylesheet class selector for special font and display characteristics.</p> <p onmouseup="highlightSelection()">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </body> </html> См, также: методы selection. getRangeAt (), Range. extraContents (). toStringO Возвращаемое значение: строка Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari 1+ С помощью метода toString () можно извлечь копию основного текста, расположенного в текущей области. Полученным таким образом текстом не управляет ни один из существующих в дереве документа дескриптор HTML или узел. Этим методом также можно пользоваться для получения текста на основе выделения, создаваемого пользователем, после преобразования этого текста в текстовую область. Пример Используйте встроенный в приложение The Evaluator объект rng для изучения метода toString (). Введите в верхнее текстовое поле следующее выражение. rng.selectNode(document.getElementByld("myP")) rng.toString() Если вы введете в верхнее поле rng, то увидите содержимое диапазона. Но не позвольте ввести себя в заблуждение. В верхнее текстовое поле вводятся исполняемые выражения. Назначение объекта диапазона текстовому полю приводит к внутреннему выполнению метода toString(). См. также: методы selection.getRangeAt (), Range. extraContents (). Глава 35. Текстовые объекты тела страницы 1077
Объект selection Свойства Методы Обработчики событий anchorNode anchorOffset focusNode focusOffset isCollapsed rangeCount type typeDetail addRange() clear() collapse() collapseToEnd() collapseToStart() containsNode() createRange() deleteFromDocument() empty() extend() getRangeAt() removeAllRanges() removeRange() selectAHChilren () toStringO Синтаксис Доступ к свойствам и методам объектов элемента selection следующий. (IE4+) [window.]document.selection.свойство\метод{) (NN6+/Moz) window.selection.свойство]метод О Описание объекта Объект selection представляет собой свойство объекта document, которое обеспечивает Доступ сценария к любому тексту документа или средствам управления текстом, используемым сценарием или посетителями. Объект selection, состоящий из одного или более символов, всегда выделяется на странице; более того, только один объект selection может быть активным в текущее время. Когда на странице посетителю дается указание выделить текст для выполнения с ним определенного действия, можно (и нужно) воспользоваться преимуществами, предоставляемыми объектом selection. Наиболее удобный случай применения объекта selection (сточки зрения обработки) — это событие onmouseup. Такое событие срабатывает после каждого отпускания кнопки мыши, при этом сценарий может анализировать объект document. selection на включение в него выделяемого текста (с помощью свойства type). Если вы собираетесь выполнить действие с выделением, то, возможно, у вас не будет возможности сделать это сразу, щелкнув на кнопке или ссылке. В некоторых версиях браузеров и операционных систем щелчок на одном из элементов страницы автоматически приводит к отмене выделения текущего элемента или текста. 1078 Часть IV, Объекты языка JavaScript
В браузере NN6+/Moz объект selection представлен в дереве узла документа, при этом происходит определение начальной и конечной точек выделения. Когда посетитель медленно перемещает указатель мыши вдоль текста, узел, в котором производится выделение, получает статус анкерного, а узел, содержащий конечную точку выделения, — активного. Для выделения, которое выполняется двойным или тройным щелчком, направление между анкерным и активным узлами задается принимаемой по умолчанию системой письма (например, слева направо в русском язьже). В большинстве случаев в браузере NN6+/Moz объект selection представлен так же, как и объект Range в модели W3C DOM, который содержит методы сжатия и расширения выделения. Однако, в отличие от области, текст, сжимаемый с помощью объекта selection, выделяется на странице. Если ваши сценарии должны управлять узлами внутри выделения, то используйте метод getRangeAt () объекта selection, возвращающий объект Range, граничные точки которого совпадают с граничными точками выделения. Свойства anchorNode focusNode Значение: ссылка на узел Только чтение Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Эти два свойства возвращают ссылку на узел, с которого начинается (anchorNode) и заканчивается (focusNode) выделение. Если выделение изменить с помощью метода addRange (), то эти свойства определяют границы последнего добавленного диапазона. См. также: свойства anchorOf f set и f ocusOf f set. anchorOffset focusOffset Значение: целочисленное Только чтение Совместимость: WinlE-, Macffi-, NN6+, Mozl+, Safari- Эти два свойства возвращают количество символов или узлов между началом выделения, а также анкерным (anchorOf fset) и активным (focusOf fset) узлами. Символы используются в текстовых узлах, а узлы — в узлах элементов. Если выделение изменяют с помощью метода addRange (), то эти свойства определят смещение текущего добавленного диапазона. См. также: свойства anchorNode и focusNode. isCollapsed Значение: булево Только чтение Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Это свойство возвращает булево значение, которое определяет равенство или неравенство анкерного узла активному узлу. Если границы одинаковы, то свойство принимает значение t rue (выделение имеет нулевую длину). См, также: свойства anchorNode и focusNode. rangeCount Значение: целочисленное Только чтение Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Глава 35. Текстовые объекты тела страницы 1079
Это свойство возвращает количество объектов Range, содержащихся в выделении. Выделение, создаваемое пользователями вручную, всегда включает один объект Range. Метод addRange () позволяет включить в выделение несколько объектов Range. См. также: метод getRangeAt (). type Значение: строка Только чтение Совместимость: WinlE-, МасШ-, NN6+, Mozl+, Safari- Свойство type возвращает элемент Text, но только при условии существования выделения на странице. В противном случае свойство возвращает значение None. Сценарий использует эту информацию для определения существования выделения на странице. if (document.selection.type == "Text") { // процедура выделения } Компания Microsoft в своей документации обращает внимание на то, что это свойство иногда возвращает значение Control, что связано с режимом редактирования значения. Пример Листинг 35.7 содержит пример использования нескольких объектов selection в Ш. После создания выделения (выберите первый переключатель) вы можете ознакомиться со значением свойства selection, type и до, и после создания объекта (отображается в строке состояния). После удаления выделения свойство type должно принять значение None. <html> <head> <title>selection Object</title> <script type="text/javascript"> function processSelectionO { if (document.choices.process[0].checked) { status * "Selection is type: *" + document.selection.type; setTimeout("emptySelection()", 2000); } else if (document.choices.process[1].checked) { var rng = document.selection.createRange(); document.selection.clear(); } } function emptySelectionO { document.selection.empty(); status = "Selection is type: " + document .selection", type; } </script> </head> <body> <hl>IE selection Object</hl> <hr /> <form name="choices"> <input type="radio" name="process" checked="checked" />De-select after two seconds<br /> <input type="radio" name="process" />Delete selected text. 1080 Часть IV. Объекты языка JavaScript
</form> <p onmouseup="processSelection()">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur.</p> </body> </html> См. также: метод TextRange. select (). typeDetail Значение: см. текст Только чтение Совместимость: WinIE5.5+, Macffi-, NN-, Mozl+, Safari- Это свойство служит заполнителем для приложений, в которых используются компоненты браузера. Таким образом, в указанном свойстве сохраняется дополнительная информация о выделении. См. также: свойство type. Методы addRange(ссылкаНаДиапазон) Возвращаемое значение: отсутствует Совместимость: Winffi-, MacIE-, NN6+, Mozl+, Safari- Этот метод используется для добавления диапазона в выделение на странице. С его помощью выделение может пополняться несколькими объектами Range. См. также: метод removeRange (). clear () Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Чтобы удалить из документа текущее выделение, воспользуйтесь методом clear (). Для посетителя метод clear () выполняет действие, аналогичное присвоению свойству TextRange. text пустой строки. Отличие между этими способами заключается в том, что метод clear () можно использовать, не создавая текстовую область для выделения. После удаления выделения свойством selection. type возвращается значение None. Пример Пример использования метода clear () приведен в листинге 35.7. См. также: метод selection. empty (). col lapse (ссылкаНаУзел, смещение) Возвращаемое значение: отсутствует Совместимость: Winffi-, МасГЕ-, NN6+, Mozl+, Safari- Глава 35. Текстовые объекты тела страницы 1081
Данный метод сворачивает текущее выделение в точку, определяемую аргументами. Первый аргумент определяет текстовый узел или узел элемента, в который перемещается свернутый диапазон. Второй аргумент указывает на количество символов или узлов, на которые перемещается свернутый узел в определенном первым аргументом узле. См. также: методы col lapseToEnd () и collapseToStart (). со11apseToEnd() collapseToStart() Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Указанные методы сворачивают текущее выделение в точку конца или начала выделения, соответственно. См. также: метод collapse (). containsNode (ссылкаНаУзел, флаг) Возвращаемое значение: булево Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Данный метод возвращает булево значение, указывающее на включение определенного узла в текущее выделение. Первый аргумент определяет анализируемый узел, а флаг указывает на то, как включается узел в выделение: полностью или нет (обычно в качестве аргумента флаг передается null). createRange() Возвращаемое значение: объект text Range Совместимость: WinIE4+, МасШ-, NN-, Moz-, Safari- Чтобы создать текстовую область для пользовательского выделения в браузере Г£, следует применить метод createRange () объекта selection. Точно не известно, почему метод для объекта selection называется createRange (), в то время как текстовые области для других действительных объектов создаются с помощью метода createTextRange (). Результатом работы обоих методов является окончательно обработанный объект Text Range. Пример Примеры использования метода createRange () приведены в листингах 15.36 и 15.45. См. также: объект TextRange. deleteFromDocument() Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Этот метод удаляет текущее выделение из дерева узлов документа. См. также метод: removeRange (). empty () Возвращаемое значение: отсутствует Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- 1082 Часть IV. Объекты языка JavaScript
Метод empty () предназначен для отмены текущего выделения в браузере Ш. После снятия выделения свойство selection, type возвращает значение None. Метод empty () работает так же, как и команда UnSelect, запускаемая с помощью метода execCommand () для документа. Если выделение создается на основе объекта Text Range (с помощью метода TextRange. select ()), то метод empty () применяется только для видимого выделения; он не влияет на текстовую область. Пример Пример использования метода empty () приведен в листинге 35.7 (ранее в этой главе). См. также метод: select ion. clear (). extend (ссилкаНаУзел, смещение) Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Данный метод расширяет границы выделения до указанного узла и элемента в узле. Начальная точка (анкерный узел) выделения остается неизменной; изменяется только конечная точка (активный узел) выделения. getRangeAt(иидехсДиапазона) Возвращаемое значение: объект Range Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Указанный метод определяет объект Range в выделении по индексу (rangeIndex). С помощью свойства rangeCount можно легко определить количество диапазонов в выделении. См. также метод: rangeCount (). removeAllRanges () Возвращаемое значение: отсутствует Совместимость: Winffi-, МасШ-, NN6+, Mozl+, Safari- Этот метод удаляет все диапазоны из выделения; выделение становится пустым. Вместо выполнения этого метода, вы можете приравнять свойство rangeCount к нулю. См. также: метод: removeRange (). removeRanges() Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Данный метод удаляет указанный диапазон из текущего выделения, но не из дерева узлов документа. См. также метод: remove All Range (). s e 1 ее t Al 1 Chi 1 dr en (ссылкаНаУзелЭлемента) Возвращаемое значение: отсутствует Совместимость: Winffi-, Macffi-, NN6+, Mozl+, Safari- Этот метод указывает на включение в выделение указанного в аргументе узла и всех его дочерних узлов. Глава 35. Текстовые объекты тела страницы 1083
toStringO Возвращаемое значение: строка Совместимость: WinlE-, MacIE-, NN6+, Mozl+, Safari- Этот метод возвращает сроковое представление выделения — содержимое тела страницы минус дескрипторы и атрибуты. Объекты Text и TextNode Совместимость: WinIE5+, Macffi5+, NN6+, Mozl+, Safari 1+ Свойства Методы Обработчики событий attributes* cnildNodes* data firstChild* lastChild* length* localName* namespaceURI* nextSibling* nodeName* nodeType* nodeValue* ownerDocument * parentNode* prefix* previousSibling* appendChildO * appendData() cloneNode()* deleteDataO hasChildNodesO* insertBeforeO * insertDataO normalize()* removeChildO * replaceChildO * replaceDataO splitText() substringData() * См. главу 15. Синтаксис Доступ к свойствам и методам объектов этих элементов. (IE5+/W3C) [window. ] document.getElementByld ("идентификатор11) . ссылкаНаТекс- товыйУзел. свойство \ метод () Описание объектов Описание особенностей объекта Text W3C DOM и NN6+ такое же однообразное и утомительное, как и изучение объекта TextNode, представленного в IE5+. Все они являются однотипными и принадлежат к объектам документа— текстовым узлам, содержащим текст элементов HMTL (информация о назначении текстовых узлов в иерархической структуре объектов документа приведена в главе 14). Создание нового текстового узла с помощью сценария выполняется одина- 1084 Часть IV. Объекты языка JavaScript
ково в обоих объектных моделях — с помощью метода document. createTextNode (). Рассмотрение особенностей этих двух объектов не будет простым, поскольку версия W3C DOM является строго объектно-ориентированной (в ней текстовый узел— это экземпляр объекта CharacterData, который, в свою очередь, содержится в объекте Node). Аналогичный объект в Ш не настолько сложен и структурирован. Например, объект Text в W3C DOM имеет же свойства и методы, которые представлены для CharacterData и Node; объект TextNode в IE обладает только теми свойствами и методами, которые необходимы для управления исключительно средствами DOM, представленными Microsoft. Вызов методов объектов выполняется одинаково, поскольку имена объектов никогда явно не указываются в сценарии. Наоборот, операторы сценария всегда ссылаются на текстовые узлы другими способами, (например, с помощью свойств дочерних узлов элемента или переменной, которой присваивается результат выполнения метода document. createTextNode ()). Как отличалось, объекты используют ряд общих свойств и методов. Объект Text в W3C DOM имеет несколько методов, при вызове которых в именах указываются "данные". Эти свойства и методы заимствованы у объекта CharacterData, также представленного в W3C DOM. Они рассматриваются в следующих разделах этой главы. Всегда проверяйте, поддерживает ли соответствующий браузер свойства и методы, рассматриваемые ниже. Свойства data Значение: строка Чтение/Запись Совместимость: Winffi5+, МасШ5+, NN6+, Mozl+, Safari 1+ Свойство data содержит строку, включающую в себя текстовый узел. Его значение идентично свойству nodeValue текстового узла. Для получения подробной информации о свойстве node Value обратитесь к главе 15. Пример В сценарии демонстрации возможностей свойства nodeValue по замене текста (глава 1) вы можете использовать и свойство data. См. также: свойство nodeValue, характерное для всех объектов элементов. Методы appendData (" текст11) deleteData(смещение, количество) insertData (смещение, " текст11) replaceData(смещение, количество, "тексти) substringData(смещение, количество) Возвращаемое значение: см. текст Совместимость: Winffi6+, МасГЕ5+, NN6+, Mozl+, Safari 1+ С помощью этих шести методов объекта Text W3C DOM в сценарии обеспечивается управление текстом внутри текстового узла. Методы, изменяющие данные узла, автоматически изменяют значения как свойства data, так и свойства nodeValue. Глава 35. Текстовые объекты тела страницы 1085
Назначение этих методов очевидно в большинстве случаев. Любой метод, предусматривающий использование параметра смещение, использует получаемое целочисленное значение для обозначения начальной точки операции удаления, вставки или замены текста в существующем текстовом узле. Смещение задается с "нулевым отсчетом", что подразумевает равенство параметра смещение для первого символа строки текста узла. Параметр количество — это другое целочисленное значение, однако оно отображает количество символов в обрабатываемом тексте. В качестве примера рассмотрим текстовый узел, содержащий такие данные. abcdefg Этот узел может представлять на странице элемент или только что созданный узел, значение которого успешно присвоено переменной, еще не вставленной на страницу. Для удаления трех символов этого текстового узла необходимо выполнить следующий оператор. ссылкаНаТекстовыйУзел.deleteData(0,3) В результате содержимое узла будет иметь такой вид. defgh Как и для метода replaceData (), длина текста, заменяющего исходную часть, не должна совпадать со значением параметра количество. Параметр количество совместно с параметром смещение определяет текст, который удаляется и заменяется новым. Метод substringData () аналогичен методу строка. substr () базового языка JavaScript. В нем параметры отображают смещение, с которого начинается чтение строки и количество считываемых символов. При выполнении метода substringData () для текстового узла вы получите тот же результат, что и при использовании метода node Value. substr (), но только в том случае, когда оба метода запускаются из стандартного объекта текстового узла. Только один из вышеописанных пяти методов (substringData ()) возвращает строку. Пример Страница, представленная листингом 35.8, позволяет в полной мере изучить методы appendData(), deleteData(), insertData(), replaceData(), substringData() в NN6+/Moz/Safari. Текстовый узел, который выполняет методы, представлен простым предложением, сохраненным в элементе р. Каждый метод связан с кнопкой, а также двумя-тремя текстовыми полями, в которые вводятся его аргументы. Пусть вас не смущает длина листинга. Каждая операция метода выполняется в отдельной функции, поэтому весь код страницы довольно объемный. Каждый метод имеет строгое ограничение на применение. Чтобы обработать их, все методы вызываются в конструкции try/catch. Исключения перенаправляются в функцию handleErrors (), которая отображает на экране соответствующие предупреждения. <html> <head> <title>Data Methods of a W3C Text Object</title> <script type="text/javascript"> function doAppend(form) { var node = document.getElementById("myP").firstChild; var newString = form.appendStr.value; try { node.appendData(newString); } catch(err) { 1086 Часть IV. Объекты языка JavaScript
handleError(err) ; } } function doDelete(form) { var node = document.getElementByld("myP").firstChild; var offset = form.deleteOffset.value; var count * form.deleteCount.value; try { node.deleteData(offset, count); } catch(err) { handleError(err) ; } } function dolnsert(form) { var node = document.getElementByld("myP").firstChild; var offset = form.insertOffset.value; var newString = form.insertStr.value; try { node.insertData(offset, newString); } catch(err) { handleError(err); } } function doReplace(form) { var node = document.getElementByld("myP").firstChild; var offset = form.replaceOffset.value; var count = form.replaceCount.value; var newString = form.replaceStr.value; try { node.replaceData(offset, count, newString); catch(err) { handleError(err) ; } } function showSubstring(form) { var node = document.getElementByld("myP").firstChild; var offset = form.substrOffset.value; var count = form.substrCount.value; try { alert(node.substringData(offset, count)); } catch(err) { handleError(err); } } // обработчик событий для этих методов function handleError(err) { switch (err.name) { case "NS_ERROR_DOM_INDEX_SIZE_ERR": alert("The offset number is outside the Глава 35. Текстовые объекты тела страницы 1087
allowable range."); break; case "NS_ERRORJX)MJTOT_NUMBER_ERR": alert("Make sure each numeric enbry is a valid number."); break; default: alert("Double-check your text box entries."); } } </script> </head> <body> <hl>Data Methods of a W3C Text Object</hl> <hr /> <p id~"myP" style="font-weight:bold; text-align:center"> So I called myself Pip, and became to be called Pip.</p> <form name="choices"> <pxinput type="button" onclick="doAppend(this.form) " value="appendData()" /> String:<input type="text" name="appendStr" size="30" /></p> <pxinput type="button" onclick="doDelete (this, form) " value="deleteData()" /> Offset:<input type="text" name="deleteOffset" size="3" /> Count:<input type="text" name="deleteCount" size="3" /></p> <pxinput type="button" onclick="doInsert (this, form) " value="insertData()" /> Offset:<input type="text" name="insertOffset" size="3" /> String:<input type="text" name="insertStr" size="30" /></p> <pxinput type="button" onclick="doReplace (this.form) " value="replaceData()" /> Offset:<input type="text" name="replaceOffset" size="3" /> Count:<input type="text" name="replaceCount" size="3" /> String:<input type="text" name="replaceStr" size="30" /></p> <pxinput type =" but ton" onclick= "showSubstring( this, form) " value="substringData()" /> Offset:<input type="text" name="substrOffset" size="3" /> Count:<input type="text" name="substrCount" size="3" /></p> </form> </body> </html> См, также: методы объектов элементов appendChildO , removeChildO , re- placeChildO. splitText(смещение) Возвращаемое значение: объекты Text или Text Node Совместимость: Winffi6+, МасГ£5+, NN6+, Mozl+, Safari 1+ Метод split Text () выполняет сложные действия довольно быстро. Целочисленный параметр смещение представляет индекс символа в текстовом узле (отсчет начинается с нуля), с которого текущий узел делится на два узла. После выполнения метода для текущего текстового узла, последний будет содержать только текст, начинающийся с начальной точки и заканчивающийся индексом смещения. Данный метод возвращает ссылку на текстовый узел, данные которого начинаются с символа смещения и заканчиваются последним символом исходного узла. Посетители не замечают никаких изменений в используемом тексте: этот 1088 Часть IV. Объекты языка JavaScript
метод влияет только на структуру узлов документа. Применение этого метода приводит к тому, что элемент HTML, содержащий только один текстовый узел, в результате содержит два текстовых узла. Обратное действие (слияние объектов текстовых узлов в единый объект) выполняется методом normalize () браузераNN6+ (глава 15). Пример Используйте приложение The Evaluator для изучения метода split Text (). Вначале удостоверьтесь, что у элемента существует туЕМ один дочерний узел и его свойство node Value равно значению all. document.getElementByld("myEM").childNodes.length document.getElementByld("myEM").firstChiId.nodeValue Далее разделите текстовый узел на две части после первого символа. document.getElementByld("myEM").firstChild.splitText(1) Оба текстовых узла включены в элемент. document.getElementByld("myEM").childNodes.length Каждый текстовый узел содержит "свою" часть исходного текста. document.getElementByld("myEM").firstChild.nodeValue document.getElementByld("myEM").lastChild.nodeValue Если вы работаете в NN6+/Moz/Safari, то восстановите текстовые узлы с помощью следующих выражений. document.getElementByld ("myEM") .normalize () document.getElementByld("myEM").childNodes.length См, также: метод normalize () (глава 15). Объект TextRange Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Свойства Методы Обработчики событий boundingHeight collapse() boundingLeft compareEndPoints() boundingTop duplicate() boundingWidth execCommand() htmlText expand() offsetLeft* findText() offsetTop getBookmark() text getBoundingClientRect() getClientRects* inRange() isEqual() move() moveEnd() Глава 35. Текстовые объекты тела страницы 1089
Окончание таблицы Свойства Методы Обработчики событий moveStart() moveToBookmark() moveToElementText() moveToPoint() parentElement() pasteHTMLO queryCommandEnabled() queryCommandlndeterm() queryCommandstate() queryCommandSupported() queryCommandText() queryCommandValue() scrollIntoView() select() setEndPoint() * См. главу 15. Синтаксис Создание объекта TextRange. var rangeRef = document.body.createTextRange(); var rangeRef = buttonControlRef.createTextRange(); var rangeRef = textControlRef.createTextRange(); var rangeRef = document.selection.createTextRange(); Доступ к свойствам и методам объекта TextRange. (IE4+) rangeRef . свойство | метод ( [параметры] ) Описание объекта В отличие от большинства объектов, рассмотренных в третьей части данной книги, объект TextRange в Ш не связан ни с одним специфическим элементом HTML. Объект TextRange — это абстрактный объект, представляющий текстовое содержимое на странице (включая содержимое текстовых элементов управления формы) между начальной и конечной точками (границами области). Посетителю не обязательно знать о существовании объекта TextRange, поскольку не существует требований, предъявляемых к объекту TextRange по физическому выделению текста на странице (хотя объект TextRange и может использоваться для добавления к сценариям средств автоматического выделения текста; сценарий также может преобразовать выделение, созданное посетителем, в объект TextRange для дальнейшей обработки). Назначение объекта TextRange — это добавление сценариев средствами проверки, внесения изменений, замены и вставки содержимого страницы. В Ш начальная и конечная точки объекта TextRange определяются специфическим образом в зависимости от положения 1090 Часть IV. Объекты тыка JavaScript
символов внутри элемента, в котором создается область (обычно это элемент body, хотя также могут быть и определенные текстовые элементы управления). Место расположения символов текста страницы никоим образом не зависит от кода элементов, которые представлены дескрипторами HTML. Именно этот фактор и отличает объект Text Range от других методов и свойств элементов HTML, позволяющих изменять или копировать текст элементов (например, свойства inner Text и outerText). Начальная точка объекта TextRange может находиться в одном элементе, в то время как конечная — в другом. В качестве примера рассмотрим следующий фрагмент HTML-кода. <P>And now to introduce our <EM>very special</EM> guest:</P> Текст, выделенный полужирным шрифтом, представляет содержимое объекта TextRange. Видно, что область пересекает границы элемента таким образом, что свойства элемента HTML становятся неудобными при проведении замены содержимого области другим текстом. Однако даже а данном случае наблюдаются определенные проблемы. Простая замена текста области другим текстом делает обязательным в сценарии (или браузере) упорядочивание результата в соответствии с элементом em. Проблема возникает по той причине, что объект TextRange управляет только текстом, но никак не элементами. (Ваш текстовый процессор будет иметь подобную проблему, если создаваемое выделение начинается с курсивного начертания, а заканчивается полужирным, и вы при этом еще пытаетесь заменить фразу другим фрагментом.) Важной характеристикой объекта TextRange является возможность включения в область нескольких элементов или ни одного. Если начальная и конечная точки области находятся в одной и той же позиции, то в этом случае область выступает в роли точки введения текста. Когда объект TextRange представляет текст внутри элементов управления, метод select () объекта TextRange используется для отображения места введения текста в определенной сценарии части. Поэтому с помощью средств объекта TextRange можно сделать так, чтобы сценарий постоянно отображал курсор введения текста в конце существующего текста в диалоговом окне или в текстовом поле при активизации элемента управления. Управление текстовыми областями Для создания объекта TextRange воспользуйтесь методом createTextRange () объекта document. body или любого другого объекта элемента управления. Если необходимо преобразовать выделенный текст в текстовую область, то для этого выполните специальный метод createRange () объекта document .selection. Независимо от того, как создается область, она включает в себя весь текст объекта, используемого для ее получения. Другими словами, начальная точка области будет находиться в самом начале текста, а конечная — в самом конце. Отметьте, что при создании объекта TextRange на основе элемента BODY текст, находящийся внутри элементов управления, не является частью текста объекта TextRange (так как при ручном выделении текста страницы содержимое поля не выделяется). После создания объекта TextRange (назначенного переменной) обычно выполняются стандартные действия, включающие запуск многих привычных методов объекта, предназначенных для уменьшения размера области. Некоторые методы (move (), moveEnd (), moveStart () и setEndPoint ()) предусматривают ручное указание места расположения начальной и конечной точек. Параметры некоторых методов задаются в виде количества слов и даже предложений, поэтому не каждое действие приводит к утомительному подсчету символов. Еще один метод, moveToElementText (), автоматически включает область в соответствующий именованный элемент. Часто используемый метод collapse () размещает начальную и конечную точки в одном и том же месте— в начале или в конце текущего выделения. Такой подход используется в том случае, когда в сценарии повторяются операции обработки области (подсчет слов, поиск и замена). Метод expand () позволяет расширить Глава 35. Текстовые объекты тела страницы 1091
область таким образом, чтобы в нее поместить целые слова, предложения или же другую область, находящуюся за пределами точки вставки. Вероятно, наиболее "мощным" методом является f indText (). Он позволяет сценарию выполнить одноразовый или глобальный поиск, а также замену текстовых фрагментов страницы. После помещения необходимого текста в область в сценарии будут доступны дополнительные методы управления вьщелениями. К выполняемым операциям добавляется прокрутка содержимого страницы, которая позволяет посетителю видеть выделенный текст (scrollIntoViewO), а также представление текста на экране (select ()), что обеспечивает с ним наглядную обратную связь, необходимую для предотвращения внештатных ситуаций (например, для вставки курсора в текстовые элементы управления). Доступ к полной библиотеке дополнительных команд можно получить с помощью метода exec Command (). К таким операциям относится копирование текста в буфер и форматирование содержимого страницы, которое проводится в результате изменения свойств таблиц стилей. Чтобы заменить текст области новым фрагментом, полученным сценарием, измените свойство text данной области. Использование объекта Text Range является довольно сложной задачей, поскольку для ее выполнения необходимо пользоваться сложными комбинациями операторов. Обычно для управления объектом Text Range требуется выполнить три основных действия. 1. Создать текстовую область. 2. Установить начальную и конечную точки. 3. Изменить или переместить область. Как только вы научитесь управлять этим объектом, то сразу поймете, какой высокий уровень гибкости он предоставляет в сценарии, по крайней мере, при изменении содержимого страницы. Детальная информация об использовании объекта Text Range в сценарии приведена ниже в разделах, посвященных отдельным свойствам и методам. Совместимость с браузерами Объект Text Range доступен только IE4+ для Windows. Браузеры ГЕ5+ для Мае не предусматривают поддержку Text Range. В W3C DOM и NN6+ применена иная концепция построения объектов области, задейст- вующая объект Range. Однако основные способы управления объектом Range остаются такими же, как и для объекта Text Range: создание, установка начальной и конечной точек, изменение области. Версия W3C (как и сама W3C DOM) наиболее подходит для работы с иерархической структурой узлов документа. Свойства и методы объекта Range, в основном, ориентированы на управление узлами, терминологии объекта Range отлична от используемой для объекта Text Range, представленного в Г£. В настоящее время еще неизвестно, когда будет применен (и будет ли вообще применен ) в Г£ объект Range, характерный дпяУ/ЗС. Отметим, что объект Range испытывает недостаток в нескольких методах, которые эффективно используются для управления объектом Text Range, в частности, методах f indText () и selectO. С другой стороны, примененный в NN6+/Moz объект Range поддерживается в браузерах для любых ОС. Возникает резонный вопрос: почему бы не создать сценарий, который мог бы управлять обоими типами объектов. Несмотря на то что основная последовательность операций, выполняемых с объектами, общая для всех браузеров, синтаксические структуры для этого используются разные. В табл. 35.1 представлен итоговый набор свойств и методов, используемых обоими браузерами, а также соответствующая им терминология (иногда доступ к значению свойства одного объекта можно получить с помощью метода другого объекта). Возьмите 1092 Часть IV. Объекты языка JavaScript
на заметку то, что способы перемещения отдельных граничных точек не представлены в таблице, поскольку соответствующие методы каждого объекта (например, метод moveStart () объекта Text Range соответствует методу set Start () объекта Range) используют разные пространственные принципы. Таблица 35.1. Общие хараетеристики объшот TextRange и Range Объект TextRange Объект Range text toStringO collapse () collapse() compareEndPoints() compareEndPoints() duplicate() clone 0 moveToElementText() selectContents() parentElement() commonParent Совместное управление текстовой областью в двух рассматриваемых объектных моделях одной страницы обеспечивается ветвлением сценария для каждого типа объекта или созданием отдельного программного интерфейса приложения, которые позволяют активизировать специальные функции, выполняющие ветвление. Для Г£ также необходимо написать сценарий, в котором устраняются ошибки сценария, вызванные применением объекта в MacOS или других операционных системах, не принадлежащих к семейству Windows. Свойства boundingHeigth boundingLe£ t boundingTop boundingWidth Значение: целочисленное Только чтение Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Каждая текстовая область имеет физический объем и расположение на странице, даже если невозможно увидеть выделение на странице. Курсор введения текста (речь идет о сжатой текстовой области) представляет собой прямоугольник; его высота идентична высоте строки основного текста, в котором представлена выделенная область, а ширина равна нулю. При использовании свойств boundingHeight и boundingWidth объекта TextRange текстовую область прямоугольника можно измерять в пикселях. Если текстовая область состоит из нескольких параллельно расположенных линий, определение размера прямоугольника сводится к вычислению размера отдельных маленьких прямоугольников, содержащих текст (способ, идентичный заключению текста в поле — см. описание объекта Text Re с tangle в конце этой главы). Таким образом, даже если область состоит из одного символа в конце строки и другого, находящегося в начале следующей строки, рабочий прямоугольник будет настолько широк, насколько широким является элемент абзаца. Прямоугольник текстовой области имеет физическое расположение на странице. Верхняя левая координата прямоугольника (в зависимости от границ окна браузера) описывается с помощью свойств boundingTop и boundingLef t. На практике текстовые области, соз- Глава 35. Текстовые объекты тела страницы 1093
данные для выделений, в Ш при прокрутке страницы могут представлять недостоверные значения свойства boundingTop. Для получения достоверных результатов необходимо использовать свойства of f setTop и of f setLef t. Пример В листинге 35.9 приведен простой пример использования свойств boundingHeigth, boundingLef t, boundingTop, boundingWidth (и двух свойств смещения) объекта TextRange. После выделения текста в абзаце значения всех шести свойств отображаются в таблице. Если изменить размер окна с помощью обработчика onresize, то значения этих свойств будут автоматически обновлены. Например, если вы щелкнете в абзаце, не перетаскивая указатель мыши, то свойство boundingWidth примет значение ноль. Эта операция эквивалентна назначению объекта TextRange в качестве точки вставки. <html> <head> <title>TextRange Object Dimension Properties</title> * <style type="text/css"> td {text-alignreenter} .propName {font-family: Courier, monospace} </style> <script type="text/javascript"> function setAndShowRangeData() { var range = document.selection.createRange(); Bl.innerText = range.boundingHeight; B2.innerText = range.boundingWidth; B3.innerText = range.boundingTop; B4.innerText = range.boundingLeft; B5.innerText = range.offsetTop; B6.innerText = range.offsetLeft; } </script> </head> <body onresize="setAndShowRangeData()"> <hl>TextRange Object Dimension Properties</hl> <hr /> <p>Select text in the paragraph below and observe the "bounding" property values for the TextRange object created for that selection.</p> <table id="results" border="l" cellspacing="2" cellpadding="2"> <tr> <th>Property</th> <th>Pixel Value</th> </tr> <tr> <td class="propName">boundingHeight</td> <td class="count" id="Bl">&nbsp;</td> </tr> <tr> <td class="propName">boundingWidth</td> <td class="count" id="B2">&nbsp;</td> </tr> <tr> 1094 Часть IV. Объекты языка JavaScript
<td class="propName">boundingTop</td> <td class="count" id="B3">&nbsp;</td> </tr> <tr> <td class="propName">boundingLeft</td> <td class="count" id="B4">&nbsp;</td> </tr> <tr> <td class="propName">offsetTop</td> <td class="count" id="B5">&nbsp;</td> </tr> <tr> <td class="propName">offsetLeft</td> <td class="count" id="B6">&nbsp;</td> </tr> </table> <hr /> <p onmouseup="setAndShowRangeData()">Lorem ipsum dolor sit amet, consectetaur adipisicing elit, sed do eiusmod temper incididunt ut labore et dolore magna aliqua. Ut enim adminim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat, Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseruntmollit anim id est laborum Et harumd und lookum like Greek to me, dereud facilis est er expedit.</p> </body> </html> См. также: свойства объектов элементов of f set Left, of f setTop (глава 15). htmlText Значение: строка Чтение/Запись Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Свойство htmlText возвращает HTML-текст, находящийся в текстовой области. Если начальная и конечная точки области находятся на границах элемента, то дескрипторы HTML этого элемента становятся частью значения свойства htmlText. Если же область начинается в одном элементе и заканчивается в другом, то дескрипторы, определяющие текст в заключительной части, становятся частью htmlText. Это свойство имеет статус Только для чтения, поэтому HTML-код нельзя вставлять или заменять в текстовой области (детальная информация об управлении HTML-кода приведена при описании метода pasteHTML () и команды вставки, выполняемой методом exec Command () в следующем разделе). Пример В приложении The Evaluator вы сможете детально изучить свойство htmlText. Введите в верхнее текстовое поле следующее выражение, а с результатами ознакомьтесь в нижней области, а = document.body.createTextRange() Далее используйте метод f indText () для установки начальной и конечной точки текстовой области, включающей слово all, которое представляет элемент em, включенный в элемент туР. a.findTextC'all") Глава 35. Текстовые объекты тела страницы 1095
Данный метод возвращает true, если текст найден и включен в текстовую область. Для проверки этого определите значение свойства text области, а.text Поскольку текстовая область содержит весь текст элемента, свойство html Text включает дескрипторы элемента. a.htmlText Если в дальнейшем вы будете определить другие текстовые фрагменты, описываемые свойствами text и html Text, то сначала восстановите текстовую область, включающую в себя все тело страницы. а.expand("textEdit") Вы ознакомитесь с методом expand () далее в этой главе. См. также: свойство text. text Значение: строка Чтение/Запись Совместимость: WinEE4+, МасШ-, NN-, Moz-, Safari- Свойство text предназначено для получения или изменения строки видимых символов, составляющих текстовую область. Браузер регулирует отдельные проблемы, вызванные изменением области, имеющей вложенные элементы. Как правило, вложенный элемент (и любое связанное с ним форматирование) удаляется, а новый текст становится частью текста контейнера, хранящего начальную точку текстовой области. Кроме того, если область начинается в середине одного элемента и заканчивается в тексте родительского элемента, то дескриптор, включающий в себя начальную точку, охватывает весь текст. Пример Пример использования свойства text для замены найденного текста приведен в листинге 35.11, в котором рассматривается метод f indText (). См. также: свойство htmlText. Методы collapse О Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ-, NN-, Moz-, Safari- Уменьшение текущего размера текстовой области до размера курсора введения символов позволяет выполнить метод collapse (). Данный метод более важен, чем может показаться на первый взгляд, особенно при использовании его в функции, обрабатывающей текст тела страницы или большую часть текста документа. Например, при выполнении обычного цикла подсчета слов изначально создается область, включающая в себя весь текст тела документа (или текст элемента text area). Если область создана, ее начальная точка находится в начале текста, а конечная — в самом конце. Чтобы подсчитать слова, в начальной точке необходимо свернуть область до размеров курсора. Затем с помощью метода expand () задайте в качестве содержимого области первое слово просматриваемого текста (далее счетчик увеличивается, если метод expand () возвращает значение true). Вокруг первого слова образуется область. Далее необходимо сжать текущую область, чтобы поиск продолжался со следующего слова. Запустите метод collapse () еще раз, но на этот раз изменив его исходные параметры. 1096 Часть IV. Объекты языка JavaScript
Необязательный параметр метода collapse () — это булево значение, которое позволяет проводить сжатие в начале или в конце текущей области. Работа этого метода по умолчанию приводит к возвращению значения true, что означает следующее: пока не произойдет изменение значения, метод collapse () будет сжимать текстовую область до размеров курсора, располагаемого перед исходной областью. Данный вариант достаточно эффективно применяется в примере с подсчетом слов, поскольку текстовая область сжимается в начале текста перед началом вычислений. Однако для последующего перемещения по словам текстовой области ее необходимо сжать таким образом, чтобы курсор отображался после текущего слова. В методе collapse () следует указать второй параметр false. Пример В листингах 35.11 и 35.14 вы детально ознакомитесь с методом collapse (). См. также: методы RangeCollapse (), TextRange. expand (). compareEndPoints (" текст14, ссылкаНаОбласть) Возвращаемое значение: целочисленное (-1, 0 или 1) Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Создание сложных объектов TextRange и присвоение их различным переменным не вызывает затруднений. Для сравнения относительного расположения начальной и конечной точек двух областей необходимо использовать метод compareEndPoints (). Одна область представляет собой объект, который используется для активизации метода compareEndPoints (), а другая область является вторым параметром метода. Порядок параметров не имеет значения, поскольку первый параметр метода определяет, какая точка и в какой области будет сравниваться. Первый параметр принимает значение одной из четырех строк: StartToEnd, StartToStart, EndToStart и EndToEnd. Эти значения определяют точку текущей области, сравниваемую с точкой заданного в качестве второго параметра. Для примера рассмотрим текст тела страницы, который содержит две области, определенные с помощью такого выражения. It was the best of times. Первая текстовая область (в данном случае ее значение присвоено переменной rngl) отображается полужирным начертанием, а вторая (rng2) — полужирным курсивом. Другими словами, переменная rng2 вложена в переменную rngl. С помощью параметра StartToStart метода compareEndPoints () можно сравнить расположение начальных точек rngl и rng2. var result = rngl.compareEndPoints("StartToStart", rng2); Возвращаемое методом compareEndPoints () значение, как правило, целочисленное. Если расположение обеих рассматриваемых точек совпадает, то возвращается значение нуль. Если первая точка находится перед второй, то возвращаемое значение будет -1. Если же первая точка расположена после второй, то значение будет равно 1. Из рассмотренного выше примера следует, что начальная точка rngl находится после начальной точки rng2, следовательно, методом возвращается значение -1. При изменении оператора таким образом, чтобы он запускался для rng2, как показано ниже var result = rng2.compareEndPoints("StartToStart", rngl), можно получить результат 1. На практике этот метод применяется для получения информации о том, совпадают ли две области, совпадает ли одна и та же точка обеих областей и начинается ли одна область там, где заканчивается другая. Глава 35. Текстовые объекты тела страницы 1097
Пример Страница, представленная листингом 35.10, предназначена для проведения операций сравнения. В ее нижнем абзаце содержится элемент span, в который включен объект Text- Range. В этом объекте после загрузки страницы (функция init ()) сохраняется текст элемента span. Фиксированная область — это удобная точка отсчета при выделении текста абзаца. После создания выделения выполняются все четыре версии метода compareEnd- Points (), с помощью которого сравниваются начальная и конечная точки выделения с фиксированной областью. В первом столбце таблицы указывается значение, возвращенное методом, а в третьем приведено более понятное описание этого значения. Чтобы ознакомиться с работой страницы, выделите первое слово в фиксированной области (дважды щелкните на нем). Как видите, начальные точки в обоих случаях (выделение и область) одинаковы— метод возвращает значение 0. Поскольку во всех случаях метод compareEndPoints () выполняется по отношению к фиксированной области, любое сравнение осуществляется с точки зрения этой области. Таким образом, в первом столбце таблицы для параметра StartToEnd указывается, что начальная точка фиксированной области располагается перед конечной точкой выделения (значение -1). Вы можете создать и другие типы выделений. ■ Текстовый фрагмент, который начинается перед фиксированной областью и заканчивается в области. ■ Текстовый фрагмент, который начинается в фиксированной области и заканчивается за пределами области. ■ Текстовый фрагмент, который начинается и заканчивается в фиксированной области. ■ Текстовый фрагмент, который начинается и заканчивается перед фиксированной областью. ■ Текстовый фрагмент, который начинается и заканчивается после фиксированной области. Изучите все без исключения варианты выделений и возвращаемые методом значения, чтобы понять, как он работает. <html> <head> • <title>TextRange.compareEndPoints() Method</title> otyle type= "text/ess"> td {text-align:center} .propName {font-family:Courier, monospace} #fixedRangeElem {color:red; font-weight:bold} </style> ocript type="text/javascript"> var fixedRange; function setAndShowRangeData() { var selectedRange = document.selection.createRange(); var result1 = fixedRange.compareEndPoints("StartToEnd", selectedRange); var result2 = fixedRange.compareEndPoints("StartToStart", selectedRange); var result3 = fixedRange.compareEndPoints("EndToStart", selectedRange); var result4 = fixedRange.compareEndPoints("EndToEnd", 1098 Часть IV. Объекты языка JavaScript
selectedRange); Bl.innerText = resultl; comparel.innerText = getDescription(resultl); B2.innerText = result2; compare2.innerText = getDescription(result2); - B3.innerText = result3; сотрагеЗ.innerText = getDescription(result3); B4.innerText = resuit4; compare4.innerText = getDescription(result4); } function getDescription(comparisonValue) { switch (comparisonValue) { case -1 : return "comes before"; break; case 0 : return "is the same as"; break; case 1 : return "comes after"; break; default : return "vs."; function init() { fixedRange = document.body.createTextRange(); fixedRange.moveToElementText(fixedRangeElem); } </script> </head> <body onload="init()"> <hl>TextRange.compareEndPoints() Method</hi> <hr /> <p>Select text in the paragraph in various places relative to the fixed text range (shown in red). See the relations between the fixed and selected ranges with respect to their start and end points.</p> <table id*"results" border="l" cellspacing="2" cellpadding="2"> <tr> <th>Property</th> <th>Returned Value</th> <th>Fixed Range vs. Selection</th> </tr> <tr> <td class="propName">StartToEnd</td> <td class="count" id="Bl">&nbsp;</td> <td class="count" id="Cl">Start of Fixed <span id="comparel">vs.</span> End of Selection</td> </tr> <tr> <td class="propName">StartToStart</td> <td class="count" id="B2">&nbsp;</td> ' <td class="count" id="C2">Start of Fixed <span id="compare2">vs.</span> Start of Selection</td> Глава 35. Текстовые объекты тела страницы 1099
</tr> <tr> <td class="propName">EndToStart</td> <td class=Mcount" id="B3">&nbsp;</td> <td class="count" id="C3">End of Fixed <span id="compare3">vs.</span> Start of Selection</td> </tr> <tr> <td class="propName">EndToEnd</td> <td class="count" id="B4">&nbsp;</td> <td class="count" id="C4M>End of Fixed <span id="compare4">vs.</span> End of Selection</td> </tr> </table> <hr /> <p onmouseup="setAndShowRangeData()">Lorem ipsum dolor sit, <span id="fixedRangeElem">consectetaur adipisicing elit </span>/ sed do eiusmod tempor incididunt ut labore et dolore aliqua. Ut enim adminira veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> </body> </html> См. также: метод Range. compareEndPoints (). duplicate() Возвращаемое значение: объект Text Range Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Метод duplicate () возвращает объект TextRange, являющийся моментальной копией текущего объекта TextRange. В некотором отношении между двумя объектами существует односторонняя связь. При изменении свойства text копии без перемещения начальной и конечной точек исходной области, последняя приобретает свойства нового текста. Однако если переместить начальную или конечную точки оригинала, то свойства text и html Text, соответственно, изменятся (а копия будет сохранять исходные характеристики, даже после изменения оригинала). Таким образом, описанный метод можно использовать при создании аналога текста одной отдельной части документа в других его частях. Пример Вы можете использовать приложение The Evaluator для изучения метода duplicate (). Начните с создания объекта TextRange, который содержит текст элемента туР. а = document.body.createTextRange() a.moveToElementText(myP) Далее создайте копию исходной области и сохраните ее в переменной Ь. b = a.duplicate() Этот метод Не возвращает значение, поэтому в области результатов страницы сообщение не выводится. Переместите исходную область так, чтобы ее точка вставки располагалась в конце тела страницы, и сверните область в конечную точку. а. expand ('" textedit") a.collapse(false) 1100 Часть IV. Объекты тыка JavaScript
Вставьте в эту точку копию объекта. a.text = b.text Прокрутите страницу вниз и ознакомьтесь со вставленным текстом. См. также: методы Range . clone (), Text Range. isEqual (). execCommand (" имяКоманды" [, флаг [, значение] ] ) Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- В ГЕ4+ для Win32 сценарии могут получить Доступ к достаточно большому количеству команд* управляющих точками вставки, абстрактными текстовыми областями и выделениями, представленными объектом Text Range. Доступ к этим командам обеспечивается с помощью метода execCommand (), который запускается объектами TextRange и document (подробные сведения о методе document. execCommand () приведены в главе 18; см. также список команд по управлению документом и выделением, представленный в табл. 18.3). Первый обязательный параметр— это имя команды, которую необходимо выполнить. Только набор предопределенных команд предоставляет сценариям уникальные возможности, которые нельзя получить с помощью объектной модели Ш и средств таблиц стилей. Большое значение имеет команда, позволяющая копировать содержимое текстовой области в буфер обмена. Другие команды предназначены для изменения стилей или вставки дескрипторов HTML в позиции сжатой текстовой области. Последние операции рекомендуется реализовы- вать с помощью других средств, однако они включены в табл. 35.2 для полноты изложения (информация о других командах приведена в табл. 18.3). Команда 135,2. Команды метода TextRange. execCommand (} Параметр Описание Bold нет сору нет Cut ^ нет Delete нет InsertButton Insert.Fieldset InsertHoritontalRule InsertlFrame InsertInputButton InsertInputCheckbox идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки Помещает текстовую область в пару дескрипторов <ь> Копирует текстовую область в буфер обмена Копирует текстовую область в буфер обмена и удаляет его из элемента управления или документа Удаляет текстовую область Вставляет дескриптор <button> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <f ieldset > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <hr> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <if rame> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type= "button" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type=" checkbox" > в точке курсора, присваивает атрибуту id значение параметра Глава 35. Текстовые объекты тела страницы 1101
Продолжение табл. 35.2 Команда Параметр Описание InsertinputFiieUjpload InsertInputHidden InsertInputImage InsertInputPassword InsertInputRadio InsertInputReset InsertInputSubmit InsertInputText InsertMarquee InsertOrderedList InsertParagraph InsertSelectDropdovm InsertSelectListbox InsertTextArea InsertUnorderedList Italic Overwrite идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки идентификатор строки нет булево Paste нет Вставляет дескриптор <input type= "FileUpload" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type= "hidden" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор < input type= " image " > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type= "password" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type= "radio" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type=" reset" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <input type=" submit" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор < input type=н text" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <marquee> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <ol> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <р> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор < select type=" select -one "> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <select type=" select- multiple" > в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <textarea> в точке курсора, присваивает атрибуту id значение параметра Вставляет дескриптор <ul> в точке курсора, присваивает атрибуту id значение параметра Помещает текстовую область в пару дескрипторов <i> Задает режим вставки текста: перезапись (true) или добавление (false) Вставляет текущее содержимое буфера обмена в точку курсора или выделение 1102 Часть IV. Объекты языка JavaScript
Окончание табл. 35.2 Команда Параметр Описание piayimage нет Запускает просмотр динамических изображений, если они присвоены атрибугу dynsrc элемента img Ref resh нет Перезагружает текущую страницу stopimage нет Останавливает просмотр динамических изображений, если они присвоены атрибугу dynsrc элемента img underline нет Помещает текстовую область в пару дескрипторов <и> Второй необязательный параметр — это булев флаг, дающий указания команде отображать любые средства пользовательского интерфейса, которые могут быть связаны с командой. Значение этого флага, принятое по умолчанию, — false. В третьем параметре некоторые команды задают значение атрибута, необходимое для нормального выполнения команды. Например, во время вставки нового абзаца в точке курсора происходит присвоение атрибугу id элемента р значения идентификатора. В этом случае синтаксис кода команды имеет вид. myRange.execCommand("InsertParagraph", true, "myNewP"); Метод execCommand () возвращает булево значение true, если команда успешно выполнена; соответственно, false,— если не выполнена. Некоторые команды могут возвращать значения (например, определяющие тип шрифта выделения), однако Доступ к возвращаемым значениям можно получить только с помощью метода queryCommandValue (). Команды, представленные в табл. 35.2, управляют текстовыми областями, однако существуют дополнительные команды, управляющие целыми выделениями (табл. 18.3), они зачастую намного эффективнее при первичной обработке текстовой области. Например, рассмотрим функцию, задачей которой является нахождение каждого экземпляра обычного слова в документе и выделение его фона желтым цветом. Такая функция использует средства метода f indText () текстовой области для нахождения каждого экземпляра. Затем метод select () выделяет соответствующий текст, и только после этого выполняется команда BackColor. Рассмотрим следующий код. function hilitelt(txt) { var rng = document.body.createTextRange(); for (var i = 0; rng.findText(txt); i++) { rng.select(); rng.execCommand("BackColor", "false", "yellow"); rng.execCommand("Unselect"); //подготовка к следующему поиску rng.collapse(false); )' В данном случае метод execCommand () используется для изменения HTML-содержимого эффективнее, чем операция заключения существующего текста внутри нового дескриптора. Недостатком данного метода можно считать то, что способ назначения цвета фона текстовому фрагменту в данном случае недостаточно гибкий (IE помещает текст в дескриптор <f ont > с атрибутом style, которому присвоено значение background-color -.yellow). Вероятно, этот способ несколько отличается от того, который вы реализовали бы самостоятельно. Пример Приложение The Evaluator успешно применяется для изучения метода вставки текста в буфер обмена компьютера. Начните с создания текстовой области для элемента туР. а = document.body.createTextRange() а.moveToElementText(myP) Глава 35. Текстовые объекты тела страницы 1103
Далее используйте команду execCommand О для копирования этой области в буфер обмена. а.execCommand("Сору") Чтобы проверить, занесен ли текст в буфер обмена, воспользуйтесь командой Вставить (Paste) меню Правка (Edit). См. также: некоторые методы команд запросов объекта Text Range. expand("единица") Возвращаемое значение: булево Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Обычный метод expand () может расширить любую область (сжатую или нет) на следующий символ, слово, предложение или даже отдельную область (например, область вокруг текста элемента body, если она создана методом document. body. createTextRange ()). Параметром метода является строка, задающая текстовый элемент, на который расширяются внешние границы области: character, word, sentence или textedit. При успешном завершении операции метод возвращает значение true; иначе — false. При запуске для сжатой области метод expand () сначала определяет слово или предложение, окружающее курсор. Однако эта операция выполняется недостаточно точно. Если существует текст, предшествующий предложению, к которому должно произойти расширение, но этот текст не заканчивается точкой, метод expand () расширяет границы до тех пор, пока не найдет следующую точку или начало области. В листинге 15.14 показано, как на практике реализуется этот "феномен". При расширении от точки курсора на символ, метод расширяет область до следующего символа в направлении, заданном используемой системой письма. Если точка курсора находится в конце области, то область не может расшириться в строну следующих элементов. В этом случае метод expand () возвращает значение false. Нередко встречаются ситуации, когда в большом сценарии необходимо взаимно заменить начальную и конечную точки исходной области в процессе многократного выполнения методов collapse () и expand (). Расширение до целой области — это способ, с помощью которого можно начать управление текстом сразу после создания выделенной области. Пример Пример использования метода expand () приведен в листинге 15.14. См. также: метод TextRange. collapse (). f indText (nискомаяСтрока" [, диапаэонПоиска, флаги]) Возвращаемое значение: булево Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Одним из наиболее часто используемых методов объекта TextRange является f indText (), назначение которого состоит в просмотре текстовой области от начальной точки до конечной с целью поиска необходимого объекта (в строке поиска различие строчных и прописных символов не проводится). Если экземпляр найден в области поиска, то область сжимается до размеров найденного экземпляра и на ней фокусируется внимание посетителя. В этом случае метод возвращает значение true; в противном случае метод возвращает значение false; перемещения начальной и конечной точек области не происходит. В вышеописанной операции осуществляется поиск текста, реально представленного на странице, а не текста атрибута или дескриптора. 1104 Часть IV. Объекты языка JavaScript
Необязательные параметры позволяют управлять дополнительными средствами управления поиском. Существует возможность ограничения диапазона области, в которой проводится поиск. Параметр диапазонПоиска содержит целочисленное значение количества символов диапазона поиска, отсчитанное от начальной точки. Чем больше это значение, тем в большей части области проводится поиск. Отрицательные значения изменяют направление поиска— он выполняется от текущей начальной точки. Если необходимо провести поиск в обратном направлении до начала области (однако при этом не известно, как далеко находится начальная точка области) определите произвольное большое число, которое гарантировано больше количества символов до начальной точки. Необязательный параметр флаги указывает, учитывается ли в процессе поиска регистр символов (например, строчные и прописные буквы), и/или выполняется поиск только целых слов. Этот параметр содержит обычное целочисленное значение, в котором суммируются числа для обоих флагов. Результирующее значение будет представлено по-разному в зависимости от количества флагов и их состояний. Значение для поиска отдельных слов — 2; при необходимости различать регистр — 4. Если вы хотите применить только один флаг, то укажите соответствующее число. Заметьте, что для одновременного задания обоих флагов следует использовать оператор побитового исключающего ИЛИ (л), который возвращает максимальное значение 6. Общепринятое назначение метода f indText () — это поиск и замена текста, а также форматирование определенного экземпляра строки внутри области. Итеративный процесс поиска предусматривает определенный уровень контроля за ходом выполнения операции. Поскольку поиск всегда начинается с начальной точки текущей области, перемещение точки начала поиска в конец последней найденной строки является обязательным. Это перемещение позволяет в следующем сеансе метода f indText () просмотреть не всю исходную область сначала, а только непросмотренную ее часть. Поскольку метод f indText () не позволяет переопределять точку поиска для текущей области и продолжает просмотр начальной области, то с помощью метода collapse (false) необходимо обязательно переместить начальную точку поиска в конец последней найденной строки. Для выполнения повторного поиска можно воспользоваться циклом while или for. Возвращаемое булево значение метода f indText () может выступать в роли условия выполнения цикла. Если количество успешных попыток выполнения цикла не имеет значения для сценария, то в данном случае лучше использовать конструкцию while. while (rng.findText(searchString)) { rng.collapse(false); } Также можно воспользоваться циклическим счетчиком for, который обеспечивает подсчет найденных экземпляров строк. for (var i = 0; findText(searchString); i++) { rng.collapse(false); } Некоторые операции управления областью (например, набор команд, запускаемых методом exec Command ()) требуют, чтобы до их запуска выделение уже существовало. Поэтому будьте готовы к использованию метода select () после того, как метод f indText () найдет искомую область текста. Пример В листинге 35.11 приведен код страницы, в котором показано два способа выполнения операции поиска и замены текста, в которой учитываются такие параметры, как регистр символов и нахождение полного слова. Оба подхода требуют создания объекта Text Range для Глава 35. Текстовые объекты тела страницы 1105
всего тела страницы, хотя его начальная точка будет смещена в начало элемента div, содержащего искомый текст. Одна из функций, выполняющая операцию замены и вставки текста, запрашивает у пользователя разрешения на замену всех найденных экземпляров искомого текстового фрагмента. Методы select () и scrollIntbviewO вызывают с целью показать пользователю заменяемый текст. Обратите внимание, что даже после отказа от замены текста фрагмент сворачивается в конечную точку найденной области, чтобы новый поиск начинался со следующего слова. Если бы в коде страницы не использовался метод collapse (), то поиск в данном случае превратился бы в бесконечный цикл нахождения одного и того же текста. Поскольку учет количества операций поиска не ведется, то в данном случае используется программная конструкция while. Вторая функция поиска текста заменяет все найденные экземпляры и выводит сведения об их количестве. Количество замененных экземпляров искомого текста представлено счетчиком цикла после завершения всех итераций (совпадений больше не найдено). chtml> <head> <title>TextRange.findText() Method</title> <script type=Mtext/javascript"> // глобальная переменная диапазона, используемая в Undo var rng; // возвращение аргументов третьего параметра findTextO function getArgs(form) { var isCaseSensitive = (form.caseSensitive.checked) ? 4 : 0/ var isWholeWord = (form.wholeWord.checked) ? 2 : 0; return isCaseSensitive x isWholeWord; } // запрашиваемый поиск и замена function sAndR(form) { var srchString = form.searchString.value; var replString = form. replaceSt ring, value,- if (srchString) { var args = getArgs(form); rng = document.body.createTextRange(); rng.moveToElementText(rights); clearUndoBuffer(); while (rng.findText(srchString, 10000, args)) { rng.select(); rng.scrollIntoView(); if (confirm("Replace?")) { rng.text = replString; pushUndoNew(rng, srchString, replString); } rng.collapse(false); } } } // незапрашиваемый поиск и замена со счетчиком function sAndRCount(form) { var srchString = form.searchString.value; var replString = form.replaceString.value; 1106 Часть IV. Объекты языка JavaScript
var i; if (srchString) { var args = getArgs (form) ; rng = document.body.createTextRange(); rng.moveToElementText(rights); for (i = 0; rng.findText(srchString, 10000, args); i++) { rng.text = replString; pushUndoNew(rng, srchString, replString); rng.collapse(false); if (i > 1) { clearUndoBuffer(); document.getElementByld("counter").innerText = i; } // НАЧАЛО КОДА БУФЕРА ОТМЕНЫ // глобальные переменные буфера var newRanges = new Array(); var origSearchString; // сохранение исходной строки писка и закладок каждого // замененного диапазона function pushUndoNew(rng, srchString, replString) { origSearchString = srchString; rng.moveStart("character", -replString.length); newRanges[newRanges.length] = rng.getBookmark(); } // очистка массива и строки поиска function clearUndoBuffer() { document.getElementByld("counter").innerText = "0"; origSearchString = ""; newRanges.length = 0; } // выполнение отмены function undoReplace() { if (newRanges.length && origSearchString) { for (var i = 0; i < newRanges.length; i++) { rng.moveToBookmark(newRanges[i] ) ; rng.text = origSearchString; } document.getElementByld("counter").innerText = i; clearUndoBuffer(); </script> </head> <body> <hl>TextRange.findText() Method</hl> <hr /> <form> <p>Enter a string to search for in the following text: <input type*"text" name»"searchString" size»"20" value="Law" /> &nbsp; <input type»"checkbox" name="caseSensitive" />Case-sensitive &nbsp; <input type="checkbox" name="wholeWordn />Whole words only</p> Глава 35. Текстовые объекты тела страницы 1107
<p>Enter a string with which to replace found text: <input type="text" name="replaceString" size="20" value="legislation" /></p> <pxinput type = "button" value="Search and Replace (with prompt)" onclick="sAndR(this.form)" /></p> <p><input type="button" value="Search, Replace, and Count (no prompt)" onelick="sAndRCount(this.form)" /> <span id="counter">0</span> items found and replaced.</p> <p><input type="button" value="Undo Search and Replace" one1ick="undoReplace()" /></p> </form> <div id="rights"> <h2xa id="articlel" name="articlel">ARTICLE I</ax/h2> <p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the government for a redress of grievances.</p> <h2xa name="article2">ARTICLE II</ax/h2> <p>A well regulated militia, being necessary to the security of a free state, the right of the people to keep and bear \ arms, shall not be infringed.</p> <h2xa name="article3">ARTICLE III</ax/h2> <p>No soldier shall, in time of peace, be quartered in any house, without the consent of the owner, nor in time of war, but in a manner to be prescribed by law.</p> <h2xa name="article4">ARTICLE IV</ax/h2> <p>The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures shall not be violated, and no warrants shall issue, but upon probable cause, supported by oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.</p> <h2xa name="article5">ARTICLE V</ax/h2> <p>No person shall be held to answer for a capital, or otherwise infamous crime, unless on a presentment or indictment of a grand jury, except in cases arising in the land or naval forces, or in the militia, when in actual service in time of war or public danger; nor shall any person be subject for the same offense to be twice put in jeopardy of life or limb; nor shall be compelled in any criminal case to be a witness against himself, nor be deprived of life, liberty, or property, without due process of law; nor shall private property be taken for public use, without just compensation.</p> <h2xa name="article6">ARTICLE VI</ax/h2> <p>In a21 criminal prosecutions the accused shall enjoy the right to a speedy and public trial, by an impartial jury of the state and district wherein the crime shall have been committed, which district shall have been previously ascertained by law, and to be informed of the nature and cause of the accusation; to be confronted with the witnesses against him; to have compulsory process for obtaining witnesses in his favor, and to have the assistance of counsel for his defense.</p> <h2xa name="article7">ARTICLE VII</ax/h2> <p>In suits at common law, where the value in controversy 1108 Часть IV. Объекты языка JavaScript
shall exceed twenty dollars, the right of trial by jury shall be preserved, and no fact tried by a jury shall be otherwise re-examined in any court of the United States, than according to the rules of the common law.</p> <h2xa name=narticle8">ARTICLE VIII</ax/h2> <p>Excessive bail shall not be required, nor excessive fines imposed, nor cruel and unusual punishments inflicted.</p> <h2xa name="article9M>ARTICLE IX</ax/h2> <p>The enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people.</p> <h2xa name=narticlelO">ARTICLE X</ax/h2> <p>The powers not delegated to the United States by the Constitution, nor prohibited by it to the states, are reserved to the states respectively, or the the people. </p> </div> </body> </html> Предоставление доступа к функции поиска и замены текста — это только половина задачи. Вам еще предстоит обеспечить в сценарии поддержку функции отмены выполненных изменений. С этой целью в сценарий вставлен код "буфера", в котором сохраняются сведения о состоянии документа до замены текста. Этот "буфер" представлен двумя переменными. Первая переменная, originSearchString, — это обычная строка, которая используется при проведении поиска данных. В ней сохраняется текст, который в случае отмены действия вставляется вместо замененного текста. Вторая глобальная переменная представляет собой массив закладок объекта TextRange (см. метод getBookmark () далее в этой главе). В массиве сохраняются ссылки, которые рядовому пользователю практически ни о чем не скажут, зато браузер эффективно использует их для быстрого нахождения мест вставки зате- нененного текста. Значения двух глобальных переменных сохраняются при вызове метода pushUndoNew (), который выполняется при каждой операции замены текста. Установка свойства text текстовой области выполняется таким образом, что она сворачивается в конечную точку нового текста. Поскольку закладка включает сведения о замененном тексте, перед ее сохранением начальная точка текстовой области должна смещаться обратно в начало замененного. Функция pushlntoNew () получает строку с замененным текстом, а метод move St art () использует количество символов в последней. После сохранения в массиве всех закладок отмена действий выполняется в обычном цикле for, вставленном в функцию undoReplace (). Проверив существование данных в "буфере" отмены, функция просматривает массив закладок и заменяет сохраненным в них текстом ранее замененный текст документа. Преимущество использования закладок состоит в том, что отмена действий выполняется только по отношению к тексту, ранее измененному командой поиска-замены. См. также: метод TextRange. select (). getBookmark() Возвращаемое значение: строка / Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- В контексте объекта TextRange закладка отличается от того средства, которое вы используете в браузере для сохранения ссылок на наиболее часто посещаемые узлы (добавление новых элементов в список избранных Web-страниц). Наоборот, закладка представляет собой строку, определяющую текстовую область, в том числе сведения о ее расположении в документе, тексте Глава 35. Текстовые объекты тела страницы 1109
и т.д. Просматривать эту строку бесполезно, так как она содержит данные, представленные в битовой форме. Никакой полезной информации из этой строки вы не получите, если, конечно, рассматривать ее с точки зрения обычного языка. Однако закладка предоставляет сценарию возможность сохранения текущего состояния текстовой области таким образом, что к ней можно было вернуться в следующем сеансе работы. Метод getBookmark () возвращает строковое представление копии текущей текстовой области. Некоторые другие операторы сценария могут корректировать объект TextRange в соответствии с используемой спецификацией закладки с помощью метода moveToBookmark () (см. далее в этой главе). Пример Листинг 35.11 содержит пример использования метода getBookmark () в операции поиска и замены текста (при создании массива закладок). В этом же примере метод moveToBookmark () применяется для отмены выполненных действий. См. также: метод TextRange. moveToBookmark (). inRange(ссылкаНаОбласть) Возвращаемое значение: булево Совместимость: WinIE4+, Macffi-, NN-, Moz-, Safari- Существует возможность сравнения физической протяженности текста двух различных областей. Эта задача выполняется с помощью метода inRange (). Вы просто запускаете метод в большей из двух областей и передаете ссылку, представленную в качестве основного параметра метода, на меньшую область. Если заданная параметром область находится в области или эквивалентна той текстовой области, в которой запускается метод, то методом возвращается значение true; в противном случае— false. Пример Используйте приложение The Evaluator для ознакомления с методом inRange (). Следующие выражения генерируют две текстовые области: для элемента туР абзаца и элемента туЕМ, вложенного в первый. а = document.body.createTextRange() a.moveToElementText(туР) b = document.body.createTextRange() b.moveToElementText(myEM) Поскольку текстовая область для элемента туР больше другой, то вызов для нее метода inRange () приводит к возвращению значения true, a.inRange(b) Если обратить последнее выражение, то можно заметить, что больший элемент не включен в меньший. b.inRange(a) См. также: метод TextRange. inEqual (). isEgual (ссылкаНаОбластъ) Возвращаемое значение: булево Совместимость: WinIE4+, МасШ-, NN-, Moz-, Safari- Если сценарий имеет ссылки на два независимо инициированных объекта TextRange, то для проверки идентичности этих двух объектов можно использовать метод is Equal (). Ука- 1110 Часть IV. Объекты языка JavaScript
занный метод ищет совпадение текста, требуя, чтобы для двух областей он совпадал посимвольно. При этом содержимое одной области считается идентичным содержимому исходной области (например, содержимое элементов управления или основного текста). Для определения того, содержится ли одна область в другой, без метода inRange () просто не обойтись. Пример Изучить метод is Equal () вам поможет все то же приложение The Evaluator. Начните с создания двух текстовых областей: для элемента туР абзаца и элемента туЕМ, вложенного в первый. а = document.body.createTextRange() a.moveToElement(myP) b = document.body.createTextRange() b.moveToElement(myEM) Поскольку обе области выключают в себя разные текстовые диапазоны, то они не равны. Выполните следующее выражение. a.isEqual(b) Если изменить границы первой области так, чтобы она включила только элемент ту ЕМ, то текстовые области станут равными. a .moveToElement (myEM) a.isEqual(b) См. также: метод TextRange. inRange (). move("единица"[, количество]) Возвращаемое значение: целочисленное Совместимость: WinIE4+, Macffi-, NN-, Moz-, Safari- Метод move () выполняет две операции. Во-первых, метод преобразует текущую текстовую область в курсор и располагает его в месте конечной точки текущей области. Потом он перемещает курсор относительно символа, слова или предложения в необходимом направлении. Первым параметром метода выступает строка, определяющая элемент смещения (character, word, sentence или textedit). Значение textedit перемещает курсор в начало или конец всей исходной области. Если пренебречь вторым параметром, то по умолчанию его значение будет равно 1. В противном случае необходимо определить целочисленное значение, представляющее количество элементов, на которое сжатая область должна перемещаться вперед (при положительном значении) или назад (при отрицательном значении). Метод возвращает целочисленное значение, отображающее точное количество элементов, на которые можно переместить курсор. Если определить большее количество элементов, чем содержится в области, то возвращаемое значение предоставит точную информацию о том, насколько далеко можно переместить курсор. Отметьте, что область все еще остается сжатой после выполнения метода move (). Расширение области вокруг определенного текста — это задача других методов. Также метод move () можно использовать в сочетании с методом select () для позиционирования курсора ввода текста в текстовом окне или области. Таким образом можно написать сценарий для текстового поля, в котором после активизации или загрузки всей страницы курсор размещается в конце введенного текста. Функция, выполняющая эти действия, представлена ниже. function setCursorToEnd(elem) { if (elem) if (elem.type && (elem.type=="text" || Глава 35. Текстовые объекты тела страницы 1111
elem.type=="textarea")){ var rng = elem.createTextRange(); rng.move("textedit"); rng.select(); Впоследствии можно запустить этот метод в функции обработчика событий onf ocus текстового поля. <input type="text"...onfocus="setCursorToEnd(this)"> Вышеописанная функция включает несколько уровней проверки наличия ошибок; например, запуск функции действительным объектом, выступающим в качестве параметра, а также использование свойства type объекта, значение которого может содержать текстовую область, созданную для его содержимого. Пример Приложение The Evaluator представляет собой идеальную среду для изучения метода move (). Чтобы увидеть, как этот метод определяет количество элементов, на которое смещается указатель мыши, создайте текстовую область, включающую элемент туР. а = document.body.createTextRange() а.moveToElementText(myP) Далее введите следующее выражение для сворачивания и перемещения диапазона обратно на 20 слов. a.move(Mword", -2 0) Щелкните на кнопке Evaluate и изучите полученные результаты. Значение 2 0 отображается до тех пор, пока метод не сместит область на 20 слов. Достигнув начала тела страницы, в качестве результата метод возвратит значение 0. См, также: методы TextRange. moveEnd (), TextRange. moveStart (). moveEnd("единица"[, количество] ) moveStart("единица"[, количество]) Возвращаемое значение: целочисленное Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Методы moveEnd () и moveStart () подобны методу move (), однако каждый из них выполняется либо только в начальной, либо только в конечной точке текущей области, соответственно. Другими словами, область не сжимается после перемещения точки. Эти методы предоставляют возможность распилить или сжимать область на необходимое количество элементов, перемещая только одну из границ области. Первым параметром выступает строка, определяющая элементы смещения (character, word, sentence или text edit). Значение text edit перемещает курсор в начало или в конец исходной текстовой области. Таким образом, если необходимо переместить конечную точку текущей области в конец тела страницы (или текстового элемента управления), используйте метод moveEnd (" text edit"). Если пренебречь вторым параметром, то его значение по умолчанию будет равно 1. В противном случае можно определить целочисленное значение, отображающее количество элементов, на которые сжатая область перемещается вперед (положительное значение) или назад (отрицательное значение). Перемещение любой точки за пределы области приводит к сжатию и перемещению последней в положение, определенное методом. Метод возвращает целочисленное значение, отображающее точное количество 1112 Часть IV. Объекты языка JavaScript
элементов, на которые можно переместить курсор. Если указать большее количество элементов, чем реально существует символов, то возвращаемое значение предоставит информацию о том, насколько вы ошиблись. Пример Используйте приложение The Evaluator для знакомства с методами moveEnd () и move - Start (). Начните с создания текстовой области и включения в нее элемента ту ЕМ. а = document.body.createTextRange() а.moveToElementText(myEM) Чтобы ознакомиться с тем, как перемещение указателя сказывается на тексте области, введите в нижнее поле значение а и просмотрите свойства текстовой области. Особое внимание обратите на свойства html Text и text. Далее введите следующее выражение, чтобы сместить конец области на одно слово вперед. а.moveEnd("word") Щелкните на кнопке List Properties, чтобы удостовериться во включении в область следующего после элемента em слова. Введите каждое из приведенных ниже выражений в верхнее поле и изучите полученные результаты, а также свойства области (кнопка List Properties). a.moveStart("word", -1) a.moveEnd("sentence") Обратите внимание, что значение по умолчанию 1 приводит к смещению области в начало текущего предложения. Если переместить начальную точку обратно на одно предложение, то отсутствие точки перед элементом туР приведет к неожиданным результатам. Наконец, сместите начальную точку обратно на 20 символов и понаблюдайте за тем, как она достигает начала элемента body. a.moveStart("word", -20) В определенный момент возвращается значение 0. Это происходит в случае достижения начальной точкой начала страницы (дальше ей смещаться попросту некуда). См. также: методы Text Range. move (). moveToBookmark("строка") Возвращаемое значение: булево Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Если снимок текстовой области сохранялся в переменной (с помощью метода getBook- mark ()), то в этом методе в качестве параметра используется строка закладки, определяющая то состояние текстовой области, в котором она находилась при создании. При успешном выполнении метода возвращается значение true, и в текстовую область заключается строка текста, первоначально сохраненного с помощью метода get Bookmark (). Содержимое текстовой области может изменяться до такой степени, что его восстановление станет невозможным. В этом случае методом возвращается значение false. Пример Пример использования метода moveToBookmark () был приведен ранее в этой главе в листинге 35.11. С его помощью отменяются выполненные в тексте документа изменения. См. также: метод TextRange. getBookmark (). Глава 35. Текстовые объекты тела страницы 1113
moveToElementText (ссылкаНаОбъехтЭлемента) Возвращаемое значение: отсутствует Совместимость: WinDE4+, Macffi-, NN-, Moz-, Safari- Самый быстрый способ заключить текстовую область в HMTL-элемент страницы состоит в выполнении метода moveToElementText (). Любая действительная ссылка на объект элемента HTML принимается как основной параметр, однако не пытайтесь использовать в ней строковую версию идентификатора (по крайней мере до тех пор, пока она не помещена в метод document. get Element By Id () (ГЕ5+). После того как границы области будут заключены 9 элемент, свойство области html Text представит полные дескрипторы элемента. Пример Примеры применения метода moveToElementText () вы найдете в этой главе в листингах 35.10 и 35.11. См. также: метод TextRange. parentElement (). moveToPoint (х, у) Возвращаемое значение: отсутствует Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Метод moveToPoint () уменьшает текущую текстовую область до размеров курсора и перемещает его в указанное положение текущего окна или фрейма браузера. С помощью горизонтальной (х) и вертикальной (у) координат, заданных в пикселях в качестве параметров, можно управлять местом расположения сжатой области. Место расположения определяется относительно окна, а не документа, который можно прокрутить в любом направлении. Выполнение метода moveToPoint () — это эквивалент щелчка посетителя в окне браузера. Для расширения сжатой текстовой области перед введением в нее символа, слова, предложения используется метод expand (). # Применение метода moveToPoint () в текстовой области, определенной для йНшПш&щ элементов управления формы, может вызвать сбой в работе браузера. Метод ока- * ^" зывается безопасным для объекта document. body даже тогда, когда значения координат х, у совпадают с областью текстового элемента управления. Однако такое размещение текстовой области не вызывает установку курсора в элементе управления формы. Пример Используйте приложение The Evaluator для изучения метода moveToPoint (). Начните с создания текстовой области, в которую включен весь объект body, а = document.body.createTextRange() Выполните метод moveToPoint (), чтобы переместиться в текстовую область результатов. а.moveToPoint(100,100) Если ввести в нижнее поле а и ознакомиться с его свойствами, то htmlText и text будут пустыми, поскольку точка вставки не имеет отображаемого на экране содержимого. Если, например, вы сместите начальную точку области назад на символ, то эти свойства будут заполнены данными элемента body (расположенными перед элементом textarea). Введите следующее выражение в верхнее поле и выполните его несколько раз. a.moveStart("character", -1) Теперь введите в нижнее поле а и повторно изучите его свойства. См. также: методы TextRange. move (), TextRangeMoveStart (), TextRangeMoveEnd (). 1114 Часть IV. Объекты языка JavaScript
parentElement() Возвращает: ссылку на объект элемента Совместимость: WinIE4+, МасГЕ-, NN-, Moz-, Safari- Метод parentElement () возвращает ссылку на следующий внешний контейнер элемента HMTL, содержащий границы области. Если границы текстовой области находятся на границах обычного элемента, то метод parentElement () возвращает ссылку на его объект. Если границы расположены в разных элементах, то объект, возвращаемый методом, представляет элемент, содержащий текст наименьшей вложенной части области. В отличие от метода expand () и других методов перемещения области, "понимающих" текстовые конструкции (слова и предложения), метод parentElement О предназначен только для управления объектами элементов. Поэтому если область сжата в курсор в основном тексте, то ее с помощью метода parentElement (), представляющего собой параметр метода move- ToElementText (), можно расширить, чтобы заключить элемент HTML. rng.moveToElementText(rng.parentElement()); Пример И вновь вы можете использовать приложение The Evaluator для детального знакомства с методом parentElement (). Создайте текстовую область, включающую элемент туЕМ. а = document.body.createTextRange() a.moveToElementText(myEM) Введите следующее выражение в нижнее поле, чтобы ознакомиться с объектом, возвращаемым изучаемым методом. а.parentElement() Если прокрутить список до свойства outerHTML, то легко заметить, что родительским для текстовой области будет элемент туЕМ. Сместите конечную точку области на одно слово. а.moveEnd("word") Поскольку добавленное слово принадлежит элементу туР, то теперь свойство outerHTML будет равно именно ему. См. также: методы TextRange. expand (), TextRange. move (), TextRangeMove- Start(), TextRangeMoveEnd(). pasteHTML ("HTML-текст") Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасГЕ-, NN-, Moz-, Safari- Несмотря на то, что метод execCommand () выполняет команды, вставляющие элементы HTML в текстовую область, вероятно, было бы намного проще вставить полностью сформированный НМТЬкод в текущую текстовую область (допускается, что вы работаете с текстовой областью вместо даже более простых значений свойства outerHTML объекта элемента). Вставка строки, представленной в виде параметра, осуществляется с помощью метода pasteHTML (). Тщательно проанализируйте ситуацию перед тем, как использовать метод pasteHTML (). HTML-текст, вставляемый в текстовую область, требует от метода размещения дополнительных дескрипторов вокруг содержимого (они используются для обеспечения достоверности результирующего HTML-кода). Например, если вы пытаетесь заменить текстовую область, содержащую часть текста элемента Р элементом LI, метод pasteHTML () разделит элемент Р на две части, поскольку элемент Р не является контейнером для отдельного элемента LI. Глава 35. Текстовые объекты тела страницы 1115
Это разделение может нарушить иерархическую структуру документа, так как разделенный элемент Р предполагает использование одного и того же идентификатора для обеих частей. Существующие ссылки на элемент Р будут нарушены, так как теперь ссылка возвращает массив двух одноименных объектов. Пример В приложении The Evaluator можно смело экспериментировать с методом pasteHTML (). Цель следующих выражений— изменить дескриптор <ет> на <span>, атрибут style которого устанавливает цвет исходного текста таким же, как и в элементе em. а = document.body.createTextRange() a.moveToElementText(myEM) Вы можете подставить HTML-данные в метод pasteHTML в виде аргумента, однако намного удобнее (с точки зрения будущего тестирования сценария) пользоваться временной переменной. b = "<span style='color:red'>" + a.text + "</span>" Мы применили текст текущей текстовой области, поскольку он не изменяется. Вставим в текущую область новые HTML-данные. a.pasteHTML(b) В результате элемент em будет удален из объектной модели, но его заменит элемент <span>. Узнаем HTML-код элемента туР. туР.innerHTML Как отмечалось ранее, метод pasteHTML () — это не единственный способ вставки и замены HTML-кода в документе. Но он эффективен, когда пользователь выбирает на странице текст, требующий замены, поскольку в данном случае можно использовать метод document . selection. createRange (), чтобы создать на основе выделения текстовую область. См. также: метод insertAdjacenHTML (), свойство outerHTML. queryCommandEnabled("имяКоманды") queгуCommandIndeterm("имяКоманды") queryCommandstate("имяКоманды") queryCommandSupported("имяКоманды") queryCommandText ("имяКоманды11) queryCommandValue("имяКоманды") Возвращаемое значение: см. метод document. queryCommandEnabled () Совместимость: WinIE4+, MacIE-, NN-, Moz-, Safari- Описание метода document. queryCommandEnabled () приведено в главе 18. select() Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ-, NN-, Moz-, Safari- Метод select () проводит выделение текста внутри границ текущей области. В некоторых операциях (например, запрашиваемого поиска и замены), пользователь может отобразить текст текущей области путем выделения той части, которая должна быть заменена. В некоторых других операциях, особенно в командах, вьшолняемых методом execCommand О, управление те Часть IV. Объекты языка JavaScript
осуществляется только для вьщеленного текста документа: Таким образом, использование объекта TextRange после применения метода select () предоставляет возможность задать границы области так, чтобы можно было обработать текст любой командой. Текст, выделенный с помощью метода select (), становится объектом selection (рассмотрен выше в этой главе). Пример Пример использования метода select () приведен в листинге 35.11 ранее в этой главе. См. также: объект selection. setEndPoint("тип", ссылхаНаОбъехтЯапде) Возвращаемое значение: отсутствует Совместимость: WinIE4+, МасШ-, NN-, Moz-, Safari- В отличие от метода moveEnd (), задающего конечную точку текущей области в виде количества символов, слов, предложений, а также целой области, с помощью метода setEndPoint () можно задать расположение границы (не обязательно конечной) текущей области относительна границы другой текстовой области, ссылка на которую задается в качестве второго параметра. Первый параметр определяет одну из четырех возможных ситуаций. Принимаемое значение управляет тем, какая из границ текущей области должна изменять свое расположение, а также какую границу другой области считать точкой отсчета. В табл. 35.3 представлены четыре возможных типа этого параметра и их значения. Тип Описание startToEnd Перемещает начальную точку текущей области в конец другой области startTostart Перемещает начальную точку текущей области в начало другой области EndTostart Перемещает конечную точку текущей области в начало другой области EndToEnd Перемещает конечную точку текущей области в конец другой области Отметим, что метод перемещает только одну границу текущей области за один сеанс работы. Если вы хотите сделать обе границы идентичными, необходимо дважды запустить данный метод (причем один раз с параметром StartTostart, а другой — с EndToEnd). Если быть точными, то метод isEqual () для этих областей возвратит значение true. Однако при задании граничной точки с помощью метода setEndPoint () можно столкнуться с некоторыми неожиданными результатами, когда преобразованная текстовая область "растягивает" составные элементы. Не удивляйтесь, если новый текст HTML расширенной области не будет содержать дескрипторы внешних контейнеров элемента. Пример Примените приложение The Evaluator для изучения метода setEndPoint (). Создайте две независимые текстовые области: для элементов туЕМ и туР. а = document.body.createTextRange() a.moveToElementText(тур) b = document.body.createTextRange() b.moveToElementText(myEM) Перед смещением граничных точек сравните HTML-содержимое областей. a.htmlText b.htmlText Глава 35. Текстовые объекты тела страницы 1117
Переместите начальную точку области а в место расположения конечной точки области Ь. а.setEndPoint("StartToEnd", b) Если вы ознакомитесь с HTML-кодом области а a.htmlText, то заметите, что дескриптор <р> из а пропал. Это прекрасный пример ошибочного использования метода setEndPoint (), вызванного рассмотрением только видимого на странице текста, а не самих дескрипторов. См. также: методы TextRange. moveEndO, Text Range, move Start О, Text- Range.moveToElementText(). Объект TextRectangle Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Свойства Методы Обработчики событий bottom left right top Синтаксис Доступ к свойствам объекта Text Range. [window. ] document. all. идентификатор. getBoundingClientRect () . свойство [window.]document.all.идентификатор.getCIientRects() [i] .свойство Описание объекта Объект TextRectangle добавляет к сценарию концепцию, описанную в спецификации HTML 4.O. В соответствии с ней отображаемый текст элемента занимает прямоугольную область на странице, достаточную по размеру для заключения всего текста. Для одного слова высота прямоугольника равна размеру шрифта, используемого для отображения слова, а его ширина не является большей, чем длина строки текста. Для последовательности слов, составляющих сложные строки, высота прямоугольника зависит от количества строк, а ширина — от расстояния между крайней левой и крайней правой границей символов (даже в том случае, когда прямоугольник включает другой текст, не являющийся частью элемента). Извлекая объект TextRange с помощью метода getBoundingClientRect (), помните, что этот объект заключается в прямоугольную область с текущими размерами. Изменение размеров страницы вызывает изменение размеров существующего прямоугольника, содержащего текст элемента. Однако копия объекта TextRange, созданная раньше, останется прежней (значения ширины и высоты не будут изменяться, что не отражает физического преобразования элемента). После изменения размеров окна или внесения изменений в содержимое страницы любой зависимый объект TextRange необходимо повторно скопировать для измененного элемента. 1118 Часть IV. Объекты языка JavaScript
Свойства bottom left right top Значение: целочисленное Чтение/Запись Совместимость: Winffi5+, MacIE-, NN-, Moz-, Safari- Координаты четырех границ, заданные в пикселях, определяют расположение любого объекта Text Rectangle. Эти координаты определяются относительно окна или фрейма, в котором отображается страница. Если необходимо выровнять элемент с внедренными объектами Text - Rectangle, то при задании значений координат следует учесть прокрутку тела страницы. На наш взгляд, левый край Text Re с t an le не всегда включает крайние левые пиксели отображаемого текста. Вам следует учитывать этот факт при выравнивании настоящего элемента относительно Text Re с tangle. Пример На странице, представленной листингом 35.12, вы можете щелкнуть на четырех вложенных элементах, что позволит изучить принципы управления объектом Text Re с tangle. При щелчке на одном из элементов свойства объекта Text Re с tangle используются для установки размера позиционируемого элемента, который выделяет пространство прямоугольника. Будьте внимательны и не перепутайте прямоугольник, который отображается на экране с самим объектом Text Re с tangle. Операции изменения размера позиционируемого элемента и отображения его на экране выполняются с помощью отдельной функции (setHiliter ()). Она вызывается в функции обработки события onclick (handleClickO). В результате обработчик onresize вызывает код, получающий размер текущего прямоугольника, на котором выполнен щелчок, и изменяющий соответствующим образом позиционируемый элемент. Удалите из дескриптора <body> обработчик onresize и понаблюдайте, что же произойдет после изменения размера окна браузера. <title>TextRectangle Object</title> <script type="text/javascriptn> // сохранение ссылки на последний элемент, // на котором выполнен щелчок var lastElem; var rectLeftCorrection = 2; // обработка щелчков function handleClickO { var elem = event.srcElement; if (elem.className && elem.className == "sample") { lastElem = elem; setHiliter(); } else { Глава 35. Текстовые объекты тела страницы 1119
hideHiliterO ; function setHiliterO { if (lastElem) { var textRect = lastElem.getBoundingClientRect{); hiliter.style.pixelTop = textRect.top + document.body.scrollTop; hiliter.style.pixelLeft = textRect.left + document.body.scrollLeft - rectLeftCorrection; hiliter.style.pixelHeight = textRect.bottom - textRect.top; hiliter.style.pixelWidth = textRect.right - textRect.left; hiliter.style.visibility = "visible"; function hideHiliterO { hiliter.style.visibility = "hidden"; lastElem = null; } </script> </head> <body onclick="handleClickO" onresize="setHiliter()"> <hl>TextRectangle Object</hl> <hr /> <p>Click on any of the four colored elements in the paragraph below and watch the highlight rectangle adjust itself to the element's TextRectangle object.</p> <p class="sample">Lorem ipsum dolor sit amet, <span class="sample" style="color:red">consectetaur adipisicing elit</span>, sed do eiusmod temper <span class="sample" style="color:green">incididunt ut labore et dolore <span class="sample" style="color:blue">magna aliqua</span>. Ut enim adminim veniam, quis nostrud exercitation ullamco</span> laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit involuptate velit esse cillum dolore eu fugiat nulla pariatur.</p> <div id="hiliter" style="position:absolute; background-color:salmon; z-index:-l; visibility:hidden"> </div> </body> </html> См. также: методы объектов элементов getBoundingClientRect 0, getClient- Rects () (глава 15). 1120 Часть IV. Объекты языка JavaScript
Приложения
Справочник по объектам браузера и JavaScript
Базовый язык JavaScript/JScript/ECMAScript Аггаум 30 constructor И4-Е4 сопсаЦвш»2)М4>1Е4 jotaT cnafTF4 POPQT44.W5.5 reverseO^4 sioe(i4fl)N4«4 sort{compamFuncyE* spicaOj. items ft»*.*" toLocateStringO ** *" toStringQr' игвЬЖО" —am— Date 29 constructor »*♦■"» getf=uBYearON4- ^ prototype и**4 getYearO oetMonthO getDateO eetDayO getHoureO geftfinuteaO getSecondsO gafTlmeO gatMWaocondaQ "*••* gelUT<yulYearQN4J2 getUTCHouTsON4"л getUTCM«utesON4J2 getUTCSecondeO ***• J2 getUTCMWaocondsQ ^^ setYeartva/) eetFulYeHve/y*1-^ setMonttHvaO setDate(va/) эвЮеу(ив/) setHoure(ya/) setMlnutes( va/) setSeconds( va/) setMKseconds( too"4"12 8etTvne(raO setUTCFuIYear( va//*»-л setUTCMontrKva/MJ2 eetUTCOaletvarf^.JZ setUTCOay(va/)r*4'J2 setLITCHouratva/)1*».02 9etUTCMnutes< va/У*»-л 8erUTCSecoods( va//**.л setUTCM*seconds< valf* л getTlmazoneOnsetO toOatoStringOWSS toGMTStringO toLocaJeDateStringO *<"• ^ toLocateStringO toLccatoTimeStringO w* ^ toStringO toTmeStringO1655 toLTTCStringO*44. J2 Dale^MrseCoBfoSMng ■) Oate.UTC(oate values) String 27 constructor *•*■C4 anchc^'ancnorName*) lengtfi ЫдО prototype**».л bhnkO botoX) сЬагАЦМех) charCodeAta/])*4-*4 cc*x*t( string?)*4^4 fixedO tontcc4or(# irggbb) rontsize(1to7) frornCharCode{n' •)<1)N4-C4 1пйекСНГ«** M) itatesO lastindexOtCs*r-[./T) link{L/«.) loceJeComparefl N°. W5-5 materKregajp^'E4 reptecetnBeexp.sfrf*4-IE4 ввагегКлэдви))»*4'|Е4 smalO spW(c/iar)N3.(2).iE4 strikeO sutK) substrtstart.tengtri)'*4. *4 substring/irrtA.lrrte) supO toLocateLowerCaseO **• w5-5 toLocaleUpperCaseO •*■ws-5 tolowerCaseO toStringO*4.,E4 toUpperCaseQ vaJueOfQ"4^4 | Regular Expressions'44,,e442| I global •gnoreCaseM5.W5 5 lastJndex munilne<1).W5.5 lastMatehO).W5 5 lastParenO).v«5 teftContexl(i).W5.5 prototype rigttfContoxtW source |$1...$9 conipiH wgeup) ехес(*5(лпу')(2) testfstrihg") sfr.tnatcrKreoexp) str. replace^ regexp, sfr) str.searcrK regexp) sfr.spW( гедвхр[,Ш1\) |<l)Propa(ly<rf tw аШ1с RagExp objad- \ Boolean"3* 28 constructor '**•IE4 prototype toStringO*4.»" valueOfON4-** MDaao^ (wwj^jjmiyB^Mn^HRiabtsR | Math(1) . й] |e LN2 LN10 LOG2E LOG10E PI SQRT1 2 SORT2 IgyWpMpwiM abs(va/) I acos(va/) asto(va/) atan(va/) atan2tva/r, vatf) ceiKva/) cos(va/) exp(va/) flcor(va0 tog(va/) max(va/r. va/2) min(va/r, vaC) pow{va/f, power) randomO round(va/) skKva/) sqrt(va/) tan(var) I fc»wtnb»»c«t»«4lclimi<*i»ct ] Number** 28 konstructor ***';K4 toExporertiaK n/*- *** lMAX_VALUE«4 toFKed(ny^W.5 MIN.VALUE^4 toLocateStringO Ne-W55-M5l NaN*4 toStRnga/adbriy*4.C4 |NEQATIVejt«NITY»loplediionj Jfe. W5.5 |POSmVE_INRNrrYIE4 vaJueOf0N4-'" Function** 33 appry( the. argsAmiyjNe. W" ca«( iMi[.aiy1t. .arartD)N6. «5.5 cater toStringO constructor'*».IE4 vatoeOrO length Globals decodeURK'erwodeoVfl/'f*6. *»5 dвcaleURICornponerrt(■ encComp'f*-«» ericodeURH'O'WSlrtrio'f». *" encoleUrKk)mponeritr compSfring "f». VW.5 escapef sWrrg't-ll) evalCsWing') isBnttef nurnber/*». «4 isNar^ expression) Nurnber(stnno)N4.|E4 parseFtoaU'stTng') parsetnlfsTflbg' [.radbr]) toStringXI/aobrp unescapeTstnno*) unwatoh( propr* wateh(prpp, пвгквегУ*4 // Г...7 const N* ^sk Control Statements 31 if ((Х¥ю¥Моп) { statementstfTrve ) *{condtoon) { statementstfTrve }else{ statementstfFalse ) result = condition ? exprf : елр/2 for QOTrf expr]; [conoVrjon ]; [update e*pr}) { statements for(varino6/ecf){ statements I with (object) { statements I ) I do{ x statements | }whHe(conc5rion)N4.,E4 switch (expression) { case tabeflV: (break] [default: label: M'IE4 continue [label]**4** break [tobe/lN4^4 try{ ) [catch {ermrinfo) { statements if exception occurs in try block )) [finely { statements to run, exception or not tf*.W5 throw va<ueNew5 Error* toStringO fiteName"6 RneNumberNe message N6-1E5-5 narneTSjES.s number'*5
О20О*РвюСпвЬш\(**т4ммшсат).АПК&жЛсж*к4. 1 Operators 32I I Corapsfteon | 1 ^ Equate 1 = m. «stpcgy едиаь | h= U= N4. JE4 1 > 1 >= 1 < <= Does not equeJ 1 Stricty does not equal 1 rs greater than 1 Is greater tan or equal to 1 Is less than 1 Is less than or equal to 1 Arithmetic | 1 + 1. 1* / % 1 ++ 1 - l-va/ Plus (and string concat) 1 Mams 1 Mufcjply 1 Divide 1 Modulo I Increment 1 Decrement 1 Negation 1 Assignment 1 Is 1 += l-= 1 *e \/= %= 1 «= 1 »= 1 >»= l&= h* 1*= 1 Doolosn && H It Bltwtoe & 1 1 - |« 1» |»> Equals 1 Add by value 1 Subtract by value 1 Muttpry by value 1 DividebyvaJue 1 ModutobyvaJue 1 Left shift by value 1 Right shift by value 1 Zero «by value 1 Bitwise AND by vahie 1 Bitwise OR by value 1 Bitwise XOR by value 1 AND 1 OR 1 NOT 1 Bitwise AND 1 Bitwise OR 1 Bitwise XOR 1 Bitwise NOT 1 Left shift 1 Right shift 1 Zero « right shift 1 1 WsceMsnsous 1 Series delimiter 1 1 delete'*4. "E4 Property destroyer | 1 jnNe.W5.5 Hem in object 1 1 instanceof N6.W5 instance of | Inew Ithis h**^ Object creator 1 Object sel-reference 1 *a Value type 1 |voidN3'IE3 Return no value 1 JavaScript and Browser Objects Quick Reference Appendix A JavaScript Bible, 5th Edition by Danny Goodman How to Use This Quick Reference This guide contains quick reference info for the core JavaScript language, die original document object model (2 pp), the IE4+DHTML object model (4 pp), and the W3C DOM object model(4 pp) as implemented in Ш5+, NN6, MoziUa, and Safari browsers. All- uppercase object names refer to HTML elements (IE4+ and W3C DOMs). The three columns in each box list the object's propertjes^netnods, and event handlers in tfiat order. Read the compatibility guides for each section. Numbers in the upper right comers of object squares are chapter numbers in which die object is covered in detail. Bask browser and operating system notation codes are as follows: N — Netscape Navigator (including Mozilla when N6 or higher) IE — MS Internet Explorer W — Windows MSIE M — Macintosh MSIE See die accompanying file for printing and collating instructions in booklet or broadside configurations. Свойства объекта стиля в 1Е4+, NN6+ Text A Font» cctor*4, N6 «om*«.r* fontFarniy'E^Ne rontSize*<Ne fontSizeAdjus1M5>N6 foriiStretchM5,N6 fontStyle *«. Ne tonrVanant*4» fontwejght**.** letterSpacing'E*.Ne UneBreak ,e5 llneHelghtIE4.N6 quotesM5Ne rubyArignIE5 rubyOverhangJE5 rubyPositfon "Е5 textAttgn*4*'6 textAfignLaslIE5S 1 textAutospace т textDecoration «4. W textDecorationBhnk «-On* style «*■ Borders A Edges border*4, ** border8ottom»E4.»*e borderLefr^.Ne rjorder»gntIE4.N6 borderToptE4. N6 borderBottomColor*4, •* rjorderLeftCotor«4.N6 borderflightColor'E4. N6 borderTopColoi«4.N6 borderBottornStyjeIE4- N6 bonJerLeftStytefe4Ne borderRightStyte e4, ** borderTopStyle'E4.» borderBottomWidth *< N6 bc*derLefrWldlh>E4.'« bonJerRighrWidm ■«. »* borderTopWidlh"E4.Ne borderColoHE4.Ne borderStyle'E^Ne borderWkfth'E^Ne margin^. N6 textDecoraiJonUr»Through «-О"* manjinBottomIE4-Ю textDecorabonNone IE-0«y textDecoreiionOverline *-°*f textDecoratJonUnderfne IE-OA texrJndentIE4,Ne texUustify IE5 texUustrfyTrim ^ textKashiaaSpece ^.5 1 textOverflowW8 texiShadowM5>Ne 1 textTransformIE4N6 1 textUnctertfnePosrtion (£5-5 1 unicodeBWi ,E5< ** 1 whiteSpace^.Ne [ wordBreakW5 1 wordSpaangM4,N6-we 1 wordwrap7**-5 writJngModeWSS 1 Positioning bonom»e.N6 height с*. Ne lenlfe4.N6 pixeBottom <E/W-Onry 1 pixettoight **<*** 1 pixelLeft ***** pixelRight'EW-Onry pixefTop'E-o^ pixefWidih IE-o* po8BottomIE/w<Wy posHeight,E-Onhr 1 posLeft'E"0^ posRigM,E'w-0n* 1 posTop'E-O^ 1 poaWid№ ■*<** 1 position «Е4,М8 right'E5.Ne 1 |optE4.Ne width'". N6 zlndex ■**■"« maraJnLen11*-*16 пгагдИгедгй«Е4,»« marginTop'E4' N* ouhTneM*'N6 outSneCotorM5-Ne outineStyle>«.N6 outfineWidthM5,Ne pad.ingC4.Ne paduliuButionig4, ** paddngLeft^.Ne paddingRightIE4, N6 padd«gTop,E4,Ne Tables borderColapse m-w borderSpecing *». ** captionSide *. N6 emptyCeNs **• N6 tableLayout'E5. N6 Usts feiStyta*4-*» istStyielmage ^,N6 fistStytePosition «4.N6 istStyteType IE4, N» Background background ,E4.N6 261 J^D^IL^ Cip«4,Ne cipeottomw5 dtoLeftWS cMpflkjhtW dpTopW5 1 contentMb*Ne 1 countertncrement **&- "* 1 oouraerResetMS«Ne 1 cssFloat **• ** 1 cursor^4- •* 1 dkectioniES.Ne ZsTm layoutGrtdWS layoutGridCharW5 layoutGridUneW5 layoutGridModeWS layoutGrioTypeW5 rrerkerOflset»*5. •« marks**5, ** maxHeight M5, we maxWidth ms. Ne minHeigntM5.N6.we mkiWidlh M5, w MozOpacrtvNe overflow ,E4> "6 J overflowXws overflowYWS styteFToat «-Only vemcaJAJign IE4, Ne vWb%».« width«E4,Ne zoom*55 orphansM5,Ne widow8M5N6 пшшМэ, No 1 pageBreakAner'E^Ne pageBreakBefore>E4.N6 pageBreaklnside M5' ^ see sMscettaneous 1 acceleratorW5 behaviorW5 cssText'E4,Ne vneMode*5 backgroundAttachment **■ Ne | backgroundCotor "E4-"" backgroundrmage C4,m gackgrouncPoertion »E4.Ne backToundPosrsonX ■«*»> backgroundPositionY IE-Only bacfcgroundRepeat **• ** ScroBbers scroJfcar3dUghtColor W5-5 scrotoarArrowColorv/ss scroabarBaseColor w5 5 ecroitoe^ajkSrtaoowCotor W5^ 1 асговЪагРасеСокмг W-5 scrofcarHighl^rtColor WS6 8CTOw)flfwn&OOWwOvOr 1 scrc*barTrackCok>r v*ss
Базовая DOM (NN2+, IE3+), аррСоге*6 dlpboardData W5 dosed"».*4 compooemsQ "• controHersQ "e crypto*6 defauftStatus dialogArguments ,E4 dlatogHeightW4 dtatogLettIE4 d»togTop,E4 diatogWIdth W4 directories N4.(8) document eventIE4 externa)W4 frameEtementW.S framesQ history innerHeightN4 innerWidthN4 length N6. IE4 loading N4-°"^ location tocationbar ^(S) | menubarN4-*8) me I navigator N6. IE4 offscreenBuffering ,E4 opener «ЕЗ, N3 outerHeight "* outerWkfth *" pageXOflset M pageYOffset M parent personaJbar N4,(S) pkcsn N« prompterN6 retumVakieW4M5 screen **•,E4 screenLeftW5 screenTopW5 screenXN6 screenY**6 scrollbars N4.(S) scroUXN6 scrolYN6 self sidebar N4.(S) status statusbarN4-^) tootoar N4.(8) top | window window atertfrneg") attechEventC evTJuncI*5 onabortN6 backON4 onbeforeprintW5 onbefofeuntoad *4 OnblurN3. IE4 onchangeNe oncSck'N6 ondoseN* onoYagdropN4-°rt>' orwrrc/o.^4 OntOCUS N3-IE4 captureEvents(type) N4-OUy deartntervaKID)N4-,E4 clearTlmeoutflD) ctoseO confirrrK'mso;*) createPopupO^5-5 detachEvent(* evf/imc)^ onrocus ■*• disableExternalCaptureO N4-°"* onhelp,E4 enabteExtemalCaptureO N4"°n,v onkeydownNe execScriptf exprs"[./ang,T),E4 onkeypress N6 find(rsfrTI.case. bkwd\f* onkeyup N6 fireEvert('evr[.evf06/l)W5 5 focusO*3-IE4 forwardON4 handteEvent( evefrt)*4-0"* home()N4 moveBy(Ax,Av)N4.iE4 rroveTo(x.y)N4,|Е4 navigateOIE3 onload onmoueesdown N6 onmousemove n6 onrnouseout ** onmouseover N* onmouseup N6 onmoveN4-0"^ navigateO,c'' onresetN6 ореп((УЯ£,"латеГврес8"JW-CS) onresizeN4.>E4 printON4. IE5 onsen,! IE4 prorr#(Vns9". "repry") onselect N6 reteaseEvents( •УРв/*4"ОЫу onsubmrt N6 resizeBy(A хЛуг4™1*-e4 ononload resizeTo( width, heightf/w-Only, IE4 routeEventfeverrf)N4-Onry scrorKx.yjN3*4 scronBy(A х.Ду)"4'C4 scroin'o(xIy>N4'IE4 setActrveO^5-5 setlnterval( /one, msec [.ergs])*41^2)* setTimeout( froc, msec [,args]/2) showHetoOW4 showModaJDiaJogO IE4 shrjwModetessDialogO ** sizeToContentON6 stop()N4 2-toefc(S). N6 +Includes toll, top. I <2)Орйопв агдв рагеп* 1из2 ^MDv^octamfww^ctojtcam^ljR^iR^vecL | document is] labtikCoJor anchorsQ apptetsO>«.'E4 bgColor cookie domain N3.^4 embedsQN3'» fgCotor formsfl height*4 imagesQ N3. IE4 llastModrfied tayersfl^-onty SnkCotor inksfl location <1) I referrer title URLN3. IE4 vKnkCotor width*4 captureEvents( typef**-**** (None) dearO 0,0880 getSetoctionO N4.(2) handleEvent( evenf )N40niy орепС/тнтегуре" [,replace]jf^ 1 reteaseEvente( typef*-°^f routeEvent( event f**<**f wrfteCstring') writemCstnVjg') |<1)R4>lMWlt>ytrwURLpiop«lylnNavigMor3. | |(2)M4hM«docunNn |(Э)т1т«ур«р«щ»» -jatecfton property to ratrtom «h* cunvrtfy Mtecfctd net 1 гп«»)пМ4.Ьи101<уТюИ<тГ type t^pofW 1 hash host hostname href pathname port protocol search target textN^Jmy xN4-Orty yN4-Only link (<a (None) href=. ..x/a>) oncfcck Ondbldick N4.<1).«E4 onmousedown N4. IE4 onrnouseout ***<tE4 onmouseover onmouseup ***•,E4 19J |(1)rWirnpiement*dlnNN4/Mac. | nameN4,iE4 textN4<Wy xN4-Only yN4-Onry anchor (<a name=...x/a> ) (None) (None) 19| above background below bgCotor | clip.bottom I cNp.height Icfcp.tetl 1 dp.right cSp.top cfip.width document left name pageX pageY parentLayer sblingAbove sfclingBelow src top Iveibirty | zlndex layer"44** loadffitename'.y) moveAbove( tayetObj) moveBetow( layetObj) moveBy(Ax, Ду) moveTofx, y) moveToAbsolute( x, y) resizeBy(A x, Ду) resizeTo( width, he&it) 39] onbkir onfocus onload onrnouseout onmouseover onmouseup location hash assignf UK*-') host retoadflwcorjowona/ ])N3.B4 hostname reptaceflff?/.")"3164 href port protocol search | imaged*4 1 border (None) onabort 1 complete onerror height onload hspace towsrc name src vspace 1 width xN4-Only yN40nly 20] |(1) Implemented л IE3.01/I*arin^ | I area'0-^4 hash (None) onolck N4 I host onrnouseout I hostname onmouseover href pathname port protocol I search | target 201 | history | current<S).(i) backO length forwardO next(S).(1> go(int\-URL') | previous ШЪ (None) ^1 |(1),«^liWiinW«4^Woz«>wttiwgn«d>ato>. 1
а ^«^Mn^JgodinMWww^anny^xom^l^jA^egrved Базовая DOM (NN2+, IE3+), страница 2 из 2 action elements!] encoding length method name [ target form handleEvent( evtf** reset()N3- IE4 submitO onreset*^IE4 onsubmit 21~| button, reset, submii form name type^.'i* value cHck<) handteEvent( evtf*3 onclick onmousedown ***•IE4 onmouseuD N*. Iе4 | select 1 length ЫигО***4 name focusON3-,E4 options(i] handteEvent( evt/44 optionsrj].defaultSelected opbons[i]»ndex opbons[ij.selected optionsfij.texl aptions[i].value setectedlndex 1 type^'E4 2A\ onblur onchange onfocus checkbox checked dk*() defaultChecked handleEvent( evtf3 form name typeN3.'E* onclick onmousedown ***■,E4 onmouseiio ***•,E4 1 checked defauttChecked fonn length ф name type**. IE4 | value radio dickfj handleEvent( evtf3 22~| onSck^^^^^^™ onmousedown NA-,E4 onmouseup ***•IE4 navn igator 38 appCodeName javaEnabtedO **. »*• appMinorVerston IE4 preference namef, ve/D^.(S) appName taint£nabled()N3. «4 appVersion browsertanguageIE4 cookieEnabled **• IE4 cpuClass^4 language*14 rrnneTypesTJ *°-ш onUne»» ОбСри** platform*". >E4 pluginsflN3.»*4 product**6 productSub**8 securityPottcy ж systemLanguageIE4 ч userAgent userLanguageIE4 userf>rofile,E4 vendor** vendorSub**8 text, textarea, password, hidden 23 defaultVahie M) form name type*». 'E4 ЫигО tocus{) handleEvent( evtf** select() value (3 onblur onchange onfocus onkeydown **••IE4 onkeypress N4-IE4 onkeyup ***•,E4 (1)N (2) P—«word value property returns empty string in NN2. mimeType"3"4 3s| description enabtedPkjgin type suffixes plugin"3"4 38| name filename description refresh<) file input control1*-* 24 form name type value ЫигО focusO handteEvent( evt f* setectO onfocus onootoct (1)AsoceJedlhefi»Uptoed object screen** 38 avai Height availLeft <1> availTopO) bufferDepth<2) cokxOepth foi^SnwothingEnabled <2> pixefOeplh updateintervaJ <2> (UN4+ar*y. (2)Wing4+only. Original DOM Compatibility Guide Baseline browsers for this section are NM2, Winl£3/J 1, and MacIE3.01. An item with do notation is compatible back to that level, and is found in all new scriptablc browsers since then. Notations indicate the browser and version in which the property, method, or event handler was introduced. Except for die window and navigator objects (whose listings cover all browsers and versions), new features listed in this section cover only through NN4 (and IE4 when they matched a new NN4 feature). Notations are as follows: N3—NewinNN3 N4 — New in NN4 J2 — New in IE3. JScripLdll ver.2 IE4 — New in 1E4, all OSes (S) — Requires signed scripts (NN) Additional window and navigator object W4 — IE4+/Windows only W5 — IE5+/Windows only IE5 — IE5+all OSes W5.5 — IE5.5+/Windows only W6 — IE6+/Wmdows only M4 — Г£4+/Масоо1у M5 — Г£5+/Мас only N6 — New in NN6 & Mozilla Except for items marked N4-Only (which are not carried over into NN6), an Hem listed for an early browser is also available in the IE4+ and/or W3C DOM object models. "(None)" means diat no methods or events exist for the current object uvough IE3 and NN4.
IE4+ DHTML DOM, страница 1 из 4 I f 8 i i Г f I n All HTML Elements is aeceeeKey"^^™ tehavtorUmsQ*5 canHaveChiWren *« canHaveHTML*55 1 children ctassName 1 cHentHoight cNentLeft cfentTop cfentWidth contentEditabte ** s currentStyle'E5 rtol.FH W4.M5 dataFofmatAsW4"5 dataSrcW4-M5 disabled document «tersQW4 hideFocueWS-S id innerText isContentEdnable ws isOtsabted ws.5 isMuttlJne ws.5 isTextEdrt *" lang language tengthO) oflsetHeight oflsetLeft offsetParent offsetTop 1 offsetWRtth outerHTML outerText parentElement parenfTextEdrt readyState recofdNumberW4 runtimeStyte ^ scopeNamews scroRHeight scroNLeft scrolFTop scrollWidth sourceindex style tablndex tagName tagUm*5 1 uniquelDW5 addBehavkxf URIS) W5 apptyEtomentf eiem[.type№ attachEventr evT.ft^c)*" ЫигО ctearAttributesO ** аккО oomponentFromPoint( x.y)*"5 contains( efem) detachEventC evT,func) ** fireEventC eWl.evfD*5 5 focusO getAo$acentText() ^ getAttrfDuteCaftrXcaseD geffloundingaientRectO w getdientRectsO ^ getExpressionO }NS insertAdjacentBementO W5 insertAdiacentHTMLO insertAdjacentTextO ilmtindexlsubindex ]p) mergeAttributesO ** releaseCaptureOW5 removeAttributef afrlcase]) 5 removeBehavk>r( IDp™ removeExpressionf" proiff* removeNode< chUdnn )Ws reptaceAdjacenfTextr toc',txr)W5 replaceNode( new)** scroMlntoViewf. top) setAcbveO W5-5 setAttribute<'anr",va/[.case]) setCaptureCcontatner^ onacttvate w5-5 oribefofecopy W5 onbeforecut*'5 onbeforedeactivate *" onbeforeedrttocus w5 onbeforepaste^5 onbhir onclick oncontextmenu W5 oncontroteelect w55 oncopy^5 oncut*5 ondblcsck ondeactivate W5-5 ondragW5 ondragendW5 ondragentei-w5 ondragleaveW5 ondragoverW5 ondragstart*5 ondrop*'5 onflterchange ш orrfocus ontocusin **<2) onfocusout**2) onhe^w^MS onkeydown onkeypress onkeyup onlosecapture *** onmousedown onmouseenterW5 5 setExpressionC prqff'oxpt*,4angm)v*i onmouseieave Vib-5 swapNodefnode)** tags<4Bo*)0) um^'URNf^W - onmousemove onmouseout onmoueeover onmouseup onmousewhee» ** onmoveW5-5<2) onmoveendW5-5(2) onmovestartws.^) onpasteW5 onpropertychange w5 onreadystatechange on resize onresizeend W5 5 onresizestart WS5 onsetectstart |(1)Property or method of a» object crttections. (2)rE content editing, mode only. S! popup*5: document isOpen nideO showf) jtlbno^ ■ (wj^^Moyjcoro^l^Jttb^aCTYed FRAMESET border borderColor cols frameSpaoing FRAME alowTransparency we borderCotor conterrtWindow w-5 frameBorder height, width marginHeight we."5 rnarginWidth **.M5 IFRAME align oontenWVindow * height, width hspace. vspace BASE 361 1 href 1 1 target | BASEFONT 36 color face | size | META 36 1 charset ~ 1 content httpEquiv name 1 """ 1 TITLE 36 | text 1 activeElement aflnkColor al anchorsO apptetsfl bgCokx body charset compatModeW6 cookie defauttCharset desjgnMode*5 doctype*15 domain embedsa expando fgCokx tleCreatedDate fMeModrfiedDate fJeSize tormsQ framesQ imagesQ tastModffled BnkCotor HnksQ location media*** mimeType^ namePropwe namespacesO W55 1 paientWinduw piuginsO protocol readyState reterrer scriptea . security W5 5 1 selection styteSheetsQ title uniquelD URL URLUnencoded*8 1 vKnkCokx document atlachEventC evTJuncf*5 dearO clearAttnbutesO^ ctoseO createElementTCao') createEventOtojectfJ evfl)*5-5 createStyleSheeta* URflJadexJi) detachEventC evTfimclF5 etementFromPoint( x,y) execCommandC спкГ[,иЦ,агдЦ) focusO meTgeAttributes( obff* operHTmkneType l^eptece]) o^teiyCommandEnabledC cmrf") quetvCommarK*ndtenn(* cmd") queryCommandState('crrxT) o^jervCommandSupporteoX'спкГ) queryCornmandTextC спкГ) o^jeryCommandVahje{* стГ) recatc(a*Fiag)*K releaseCapture<)IE5 setActiveO*55 write<'sfi') writeky'slO "• 5 is] onactivate w*-5 onbeforecut*5 onbeforedeactivate W5-s onbeforeeditfocus ws onbeforepasteW5 onclick onoontextmenu W5 oncontroteelect w5-5 oncut ondblclick ondeactivate w5 5 ondragW5 ondragendW5 ondragenterW5 ondragteaveW5 ondragoverW5 ondragstartW5 ondropw5 onhelpW4.M5 onkeydown onkeypress onkeyup onmousedown onmousemove onmouseout onmouseover onmouseup onpaste onpropertychange ™ onreadystatechange onresizeend W5-5 onresizestartш 5 onselectionchange W5-5 onstop1E5 1 alink background bgCotor bgProperties bottomMarajn BODY createControlRange() w5 createTextRangeO doScrolHl*scfo«4ctibn "Jf5 teftMargin, rightMargtn noWrap scroH scroNLeft, асгоГГор text topMargin | vLink 18 onAfterPrintw5 1 onBeforePrintW5 onScrdl
О 2004 Duny Goodme (www.dMny&oom). AD Rigbtt Rcaetved 0SB5 " 1 FORM 21 1 autocomptete w5 submitO onsubmit 1 enctype | target | LABEL 35 1 BUTTON 22 | (See original object model button, reset, submit radio, and checkbox object listings.) | INPUT (image) 22 1 form 1 name 1 src Itype | INPUT (text, password, hidden) 23 1 (See original object model text password.and hidden object Ratings.) 1 maxLength (Nor») onaftenjpdateW4 1 readonly onbetoreupdateW4 | size onerrorupdateW4 | TEXTAREA 23 1 (See original object model textarea object feting.) 1 cote createTextftange() onafterupdateW4 1 readonly onbeforoupdaleW4 1 rows onerTorupdateW4 1 wrap j SELECT 24 1 (See original object model select object listing.) 1 length tamiindexlsubindaxfE5 (None) 1 multiple namedRem("tf,)W6 1 size orjtions[i].add( ehml.index}) \ value optorttfrremoveO | OPTION 24 I defauttSeiected (None) (None) 1 selected 1 text | value A (anchor/link) i9| hash 1 hostname 1 href 1 Methods 1 mimeType 1 name 1 nameProp 1 pathname 1 port 1 protocol I protoooLong ] ral 1 rev 1 search 1 target 1 |um | IE4+ DHTML DOM Compatibility Guide The baseline browser for this section is compatible back to that level for all OS versions. Notations as follows: W4 — IE4+/Windows only W5 — IE5+/Windows only IE5 — IE5+ all OSes W5.5 — IE5.5+/ Windows only W6 — IE6+/Windows only M5 — IE5+/Mac All HTML element objects share items from "All HTML" box on Page 1. "(None)" means no special methods or events for the current object OL 37 compact start type UL 3? compact type LI 37 type value DL, DT, DD, DIR, MENU compact 1 IE4+DHTML DOM, align alt border dynsrc MeCreatedOale^ fiieModrfiedDate fieSizeW4,M5 fVeUpdaledDate rwef hapace isMap loop towsrc mimeType ** name namePropW5 protocol src start useMap vapace alt ; COOrdS hash 1 host hostname href noHref pathname port protocol search shape target areasfl name i behavior bgCotor hapace loop scrolAmount scroeDeJay trueSpeed vspace IMG (None) AW.M5 W4.M5 W5.5.MS AREA (None) map" (None] страница 2 onerror onload (None) опшаЯ MARQUEE startO stopO onstart из 4 201 201 *" 2oj 35 |
IE4+ DHTML DOM, страница З из 4 li f1 s 1 § о , г i f' ! l I1 1 oKgn background ЬдСокн border 1 borderColor 1 bordefCokxDark bonterColorUght caption celPadding ceHsO*5 ceHSpacing cotelj datePageSize 1 frame height 1 rowsQ rules tBodtesfJ tFoot HHead | width TABLE createCapbonO отстой createTFootO createTHeadO deteteCaptionO dek*teRow<i) deteteTFootO deleteTHeadO firstPageO»" msertflowrfrt lastPageO^5 _ mowRtrw(srcfndex .desUndoxy*5 nextPageOW4M5 prevkxjsPageO ^^,M5 refreshO 37 TBODY, TFOOT, THEAD 37 align ЬдСокн insertflowf) rows rrweRow(sn^ndex,destfndex) vAfign TR 37 bgCotor borderColor borderCokxDark borderCokxLight cetetP deleteCel</) •nsertCeIKO vAlkjn » TD,TH aKgn background bgCotor borderColor borderCokNDark borderColorUgnt colSpan height noWrap rowSpan vASgn | COL.COLGROUP 37 span vAKgn |width CAPTION 37 lafcgn |vAlign 4D№ *AM«XOTjUllRijteR H1...H6 35J | align | HR 351 «*Qn 1 1 noShade size | width | BR 351 | clear J FONT 35| face | size I boundngl kught boundingLeft boundingTop boundingWidth ntmfText offsetLeft offsetTop text TextRange*4 colapse<[ start]) (None) compareEndPointsC type'sange) dupiicateO execCommandC cmd"[,U4,va/J]) expand^ unit") firKTText("str*[,scope,/tegs]) geffiookmarkO getBoundingClientRectO getCtientRect8() inRange(ra/jpe) isEquaK range) move("unin^ounf]) moveEnoX" uniT[,count]) moveStartf un/f *[,соил fj) moveToBookmarkf bookmark*) moveToElementText( etom) moveToPoint( x,y) parentElementO pasteHTMLCW7Wirexf) queryComfnandEnabted{* cnxT) queryCommandlndeterrn(' cnxT) QuefyComrnandStatef and") queryComrnandSupported(* cmd") queryComrnandTextC «no") quefyCommandValuef and*) scrolllntoViewO setectO setEndPointC type'sange) 35~] IE4+ DHTML DOM Compatibility Guide The baseline browser for this section is MSIE 4. An item with no notation is compatible back to mat level for all OS versions. Notations as follows: W4 — IE4+/Windows only W5 — IE5+/Windows only IE5 — IE5+ all OSes W5.5 — IE5.5+/Windows only M5 — IE5+/Mac All HTML element objects share items from "All HTML" box on Page 1. "(None)" means no special methods or events for the current object This Quick Reference does not contain listings for Microsoft's separate XML DOM. length nextSibling nodeName nodeType nodeVaJue parentNode previousSibling type typeDetail W5-5 top TextNode"* 35 appendDataCfexnM5.*» <l deteteOata( start, count)M5,w6 insertData< start, •texTf*5-'*6 reptoceData( start, count, 'texTf*5™* splitText( offset}*5-*6 substringData( start, cotmf)M5'we selection"4 35 ctearO create! emptyO TextRectangle" 35
О 2004 Риту Goodman (www dMmyg.com). АД lUnbte Reserved IE4+ DHTML DOM, страница 4 из 4 STYLE 26 type styleSheet 26 cssText*5 disabled addlmpcHtrLWn>ndtaD i aoWulef setector\WvteS£ec Ijndex]) removeRule( index) owningElement pagegflW5-S parentStyleSheet reedOniy ruJesQ title type currentStyle^ runtimeStyle* 26 (Sm style obfect) rule 26 readonly selectorText style charset ojsabled href hreflang media rel rev styleSheet ws target |type (None) LINK onload Зб] event altKey altLeft*" behaviorCootoe ** 5 behavforpartwss bookmaiteW4 boundBements button cfientX cientY contentOverilow ctrlKey ctriLeft'ESi dataRdW4 dataTransferW5 fromElement keyCode nextPageW5-5 ofbetY propertyNamevw W4 __atW5 retumValue saveType *** 5 screenX screenY snJftKey shiftLeft»E55 srcElement srcRHerW4 srcUm*5 type wheelOataW8 h*gn aRHTML archive W6 code [ CodeBase 1 height hepace name object vspece | width (None) APPLET 40] onceOchange W5 ondataavailable W5 ondatasetchanged W5 ondatasetcomplete w5 onload onrowenterW5 onrowexitW5 onrowsdeieteW5 onrowsinserted W5 onscroll align aKHTML BaseHref classtd code CodeBase codeType data height nspace object type vspace 1 ***" OBJECT (None) 40] onceilchange W5 ondataavailable W5 ondatasetchanged ws ondatasetcomplete W5 onload onrowenterws onrowexitW5 onrowscteteteW5 onrowsinserted ws onscroll EMBED height hidden phiginspage XMLW XMLOocument defer event htmFor sre text |type (None) SCRIPT (None) Зб|
W3C DOM (IE5+, NN6+, Mozilla, Safari), страница 1 из 4 O2004P—iyGoodoMPfon y.dMftyg-сош). All Right» Rdcrvcd. anrtbutesrj chadNodesO ciassName I cioiiH kriyhi '*) dientLeftO) ctentTopO) c«entWidth 0) dfr firetChW id lastCMd tengthO) tocaJName namespaceUfll nextSttxing nodeName nodeTvpe nodeVaJue offsetHeigtrl П) offsetLeftd) oflsetParentn) oftsetTop<1> offsetWkJth 0) I ownerDocumerrt parentNode prefix prevnousSibling All HTML Elements addEvenuJBtonerrevf*^MC,capr)(2) appendChid( etorn) ЫигО cfckO doneNode( deep) dtepafchEventf evrfft focueO getAOribuH'a»-) getA№butoNode('effi'fw getAOributoNodeNST nsurT.Tbce/ "jP> getAttributeNS(ansuna.%)ce/')f2) getEtenientseyTacNamef taflf) nasAttribme('a«ri2) hasAttributoNST гжяГ.ТЬса/")!2) hasAttnbutesO*2) hasChidNodesO insertBefore( пвлЦ, гвф tsSuppoctedr/eeluny.Vw'^) item< index )w normaizeO^ removeAttributefatt") removeAiW*jteNode( nodefU removeChfld( node) removeEventjstener(' evCJunc.capt^ replaceChMd( new.otd) scroNlntoViewO(1> setAttrfeutefam-.vHi) setA«ributeNode( node)® scfoBHeight, scroHLeft, scrohTop, ucrolWidm m styto tabtndex lagName title ii] олЫиг 1 oncfeok orwontextmenu <*) ondbldick onfocus onkeydown onkeypress 1 onkeyup onmousedown onmousemove onmouseout onmouseover onmouseup onresize I (1)Non-W3C Item onX^natod in IE4 Object Modal, but imptemenled in NeWMoz/SaJ tor convenience.] |(2)NcKimptamentadinlE through 6. (3)Piuuerty or method of aB obfoct oowectiooa. | | HEAD 361 profited 1 1 (1)Nol implemented in IE trough 6. 1 BASE BASEFONT 36 face size Г МЕТА 1 charset 1 content htyEqutv name scheme ms.wb | uri Зб] TITLE 36 cols rows FRAMESET (None) - (None) 16 FRAME 16 conterrtDocumentW (None) corrtentWindow N7 frameBorder tongDesc ***** margnHetght, margxiWidth name noResize scrolling W3CDOM Compatibility Guide Baseline browsers for this section ae_ . 1Б5, NN6, Mozilla I, and Safari ). An item with no notation is compatible with these browsers (except occasionally Safari). Some items are new to Netscape 7 (N7) and Mozilla or WinJEo (W6). Observe footnotes for items missing from IE, and see the book's text for Safari details. All HTML element objects share items from "All HTML" box on Page I. "(None)" means no special methods or events for the current object. documenl attributes!] ЬдСокх body 0) compatModeWe-N? cookie defaultVlew (1> dodypeOb dccument£lement domain fgCokx formsfj height^ imagesfl implementation 0> lastChiU lastModified алкСоЮг finksQ ctearf) doeeO createAttribute(" name") crea1eComment(' texfJT* createf>xaxnerrtFragment() ** createBementC top*) createEverTrCM»'/1) createRangeO"> createTextNodeC nrf") createTrBeWakeftroof, what, marfunc, axpandfn-W focusO OetBementByWC IP) getEtements8yName(' name') getEiemeritsByTagNamef teg") openfnwmeType "[/eplace]} writeCstr*) writelnfsfr*) onbtur onclick onkeydown onkeypress onkeyup onmousedown onmouseout onmouseover onmouseup nextSMng nodeTvpe ownerOocument 0) parentNode pkjginsO previousSibling stytoSheetsTj title URL vlinkCokx widthO) (1)Not implemented in IE trough 6. IFRAME align contentOocument (1) longDescMS.we margin Height margin Width scroiing (1)Nol implemented in IE through 6. f BODY 1 alnk (None) background bgCokx link scrolLeft. scroirTop N7.(1) text | vLink (None) _ **1 | (1 )Onp)nated in IE Object Model, but implemented in N7/Moztta for convenience. | | version 0) (None) HTML (None) 36J |(1)Not hnptemented in IE through 6.
O20O^HDvGoateo(wvn^Mayfrcart^llRi^aRaaved acceptCharset И) reset() action submrt() elementsQ encocSng lencrype length method name target FORM onreset onsubmit "^l |(1)Not implemented in IE through 6. I align form FIELDSET, LEGEND (None) (None) 21 LABEL 35 accessKey tormM5.we htmJFor BUTTON 22 INPUT (button, reset, submit, radio, checkbox) (See original object model button, reset, submit, radk), and checkbox object listings.) INPUT (image) 22 INPUT (text, password, hidden) 23 (See original object model text, password, and hidden object listings.) (None) (None) maxLengm readonly TEXTAREA 23 cob dteabl readonly (See original object model textarea object feting.) W3C DOM (IE5+, NN6+, Mozilla, Safari), страница 2 из 4 disabled length multiple size | value SELECT (See original object model select object listing.) options! /l.removeO (None) 24] 1 defauttSelected disabled form label "S-W6 selected text I value OPTION (None) (None) 241 torrnW labelO) |(1)Nol implemented OPTGROUP (None) (None) in IE/Windows through 6, but is implemented in IE5/Mac. 241 1 align alt border complete height 1 href nspace «Map tongDesc^) (owsrc lowSrcd) name (None) naturalHelght, naturalWidth >* src uaoMap 1 vspace I width IMG onAbort onError onLoad 20| |(1)Not Implemented in IE through 6. J A (anchor/link) 19 charsetW coordsW hash host hostname href hreflang<1) name pathname port protocol rel rev search shaped) target typed) (1)Not implemented in IE through 5.5. AREA alt coords hash host hostname href noHref pathname port protocol search shape target MAP I OL 37] I compact start | type | |DL,DT,DD,DIR,MENU| [compact I UL 37] compact I typ8 I LI 371 I type I I value MARQUEE( behavior start() direction stopO scrolAmount scroKDelay
W3C DOM (IE5+, NN6+, Mozilla, Safari), страница З из 4 w£nyaxom)^]lRiAtsReKrved 1 f s i о , i f 1 1 0> ™ bgCotor 1 border caption 1 uBPPadukig cellspacing 1 frame 1 height rewsQ rules summarywe fflodtos tFoot tHeed I***" TABLE creatoCaptionO creefeTPootO creafeTHeadO deMeCapttonO dBMeRow(f) deieteTFootO deMeTHeadO insertRow(f) oracrofl 37] TBODY, TFOOT, THEAD bgCotor ch*» chOU** rows vAign insertRowf» | H1...H6 35] I align | | HR 351 align color noShade size | width | | BR 351 I dear | | FONT 351 I coi°f I face I s*26 I | BLOCKQUOTE, Q 351 I cite ^'^6 ] Rangi le™ 35 doneContentsQ1 comrnofiAraestorCoritaJner cloneRangeO™' сойарэеа star® endOftset startContainer startOffet oonic«reBoundaryPoints( type.srcf** compareNode( node) comparePoint( node, offset) createCcfltextueJFragment(* texf) deleteContentsO detachO extractContentsON7 insertNodetnode)^7 intersectsNode( node) isPointlnRange( node, offset) setectNode( node) setectNodeContents< node) setEnd< node.o/fcef) setEndAfter( node) setEndBefore( node) setStart(node.offiset) setStartAften; node) setStartBef ore( node) surroundContents( nodef17 toStringO (1)Not jmptenwnted in IE through 6, TR bgCotor ch^ chOft** deteteCe»(3 inaertCeHO 1 Text(1) I data appendData('fext') length deteteData(oflfeef,oounf) insertData( offset ,mtexT) I replaceOata( offset,count ,'texT) spKtText( offset) | substringData( offset.count) (None) 35J [(1)Not>TptomentedinlEthrough6 , | ei TD.TH 37 abbr*6.*» align a»MWwe hacfcgronid ch*« chOff"* headers»"* CAPTION 37 aign Node Types ELEMENT_NOOE ATTRIBUTE_NODE TEXT_NODE CDATA_SECTlON_NODE ENTTTY_REFERENCE_NODE ENTITY_NODE PROCESSING INSTRUCTJON_NODE COMMENT.NOOE DOCUMENT_NODE DOCUMENT_TYPE_NODE DOCUMENT FRAGMENT.NODE NOTATION.NODE anchorNode anchorOffset focusNode focusOffset isCoNapaed 1 rangeCount |(1)Not hnplwnt^d selection*1* addRange( range) ctearSetectionO ooftapse< node,offset) coUapseToEndO colapseToStartO containsNode( node.recurse) dctotoFrornOocurnent<) extend(ncde.orfeeO getRangeAtO remcveAURangesO removeRange< range) seiectANChildrerK node) toStringO f\ F£ thfOUffi 6. (None) ЗТ|
O200^m^3ootaan(w^^amy^(Mn^l^i£iiRcKrved W3C DOM (IE5+, NN6+, Mozilla, Safari), страница 4 из 4 STYLE 261 I media I type | stylesheet 1 cssRulesTJ ofeteteRutef index/1) disabled insertRuJefnA'.iodex/1) href media ownerblodeW ownerfluteO) parentStyteSheet title type (None) 2б] |(1)Not implemented in IE through 5.5. | | cssRule I cssText (2) (None) parentStyteSheet Ю setectorText style typed) (None) 2б| (1)Not implemented in tEftrough 6. 1 |(2)Not Implemented in IE through 6, but Implemented in r£&Mac. | 1 charset disabled href hreflang ПЭ1 rev sheetd) target type l(1)Not icnpteniented i (None) l IE through 6. LINK (None) Зб] W3CDOM Compatibility Guide Baseline browsers for this section arc ГЕ5, NN6, Mozilla I. and Safari I Ал item with no notation is compatible with these browsers (except occasionally Safari). Some items are new to Netscape 7 (N7) and Mozilla or WinIE6 (W6). Observe footnotes for items missing from IE, and see the book's text for Safari details. All HTML element objects share items from "All HTML" box on Page 1. "(None)" means no special methods or events for the current object. altKey bubbles button canceBubole cancelable charCode dientX cfentY ctriKey currentTarget detail eventPhase вСпаг keyCode tayerX layerY metaKey originaJTarget pageX pageY relatedTarget screenX screenY ehiftKey target timeStamp type 1 view eventm nt£venA(mtype'fiubble,cancelable) (None) initKeyEventC fype", evtArgs) initMouseEventC type', evtArgs) mrtMutabonEvenlC type', evtArgs) inrtUIEventC fype". evtArgs) preventDefauNO stopPropagationO 25] 1 (1)Not implemented in IE through 6. I defer event htmlFor sre text Irype (None) SCRIPT (None) Зб| align (None) height name | wtdrh 1 APPLET align aft™ archive V№ code CodeBase data height hspace name type useMap^6 vspace I width EMBED onload onscroll 40 OBJECT align alt™ baseURI*7 border** code CodeBase codeType contentDocument (') height hspace name object type vspace width 40| 401 (l)Not implemented Ы IE through 6. |
Зарезервированные слова JavaScript к аждыи язык программирования содержит встроенный словарь зарезервированных слов, которые нельзя использовать в качестве имен переменных. Поскольку функция JavaScript представляет собой объект и вызывается с помощью имени объекта, нельзя использовать зарезервированные слова в качестве имен функций. Словарь зарезервированных слов Netscape подобен используемому в языке Java, хотя многие приведенные в нем слова не используются в JavaScript. He забывайте о том, что зарезервированные слова JavaScript зависят от регистра символов. Вы можете использовать зарезервированные слова в качестве имен объектов или переменных в своих сценариях, однако если вы введете их в другом регистре, это запутает пользователей, которые попытаются разобраться в вашем сценарии (и даже вас самих). abstract case const delete enum final function import interface null public super throw try volatile boolean catch continue do export finally goto in long package return switch throws typeof while break char debugger double extends float if instanceof native private short synchronized transient var with byte class default else false for implements int new protected static this true void
Ответы к упражнениям этом приложении вы найдете ответы к упражнениям, которые приведены в конце глав 4-12 части П этой книги. Глава 4 1. Приложение музыкального проигрывателя и калькулятора температуры — это достойные использования JavaScript задачи. Несмотря на то, что приложение музыкального проигрывателя воспроизводит готовые файлы, которые уже сохранены на сервере, вам придется решить еще много серьезных задач. Необходимо создать пользовательский интерфейс, провести предварительную загрузку изображений, получить информацию об используемых надстройках — LiveAudio, Windows Media Player или QuickTime. С этой точки зрения, калькулятор температуры — более завершенное приложение, поскольку при его создании не используются данные с сервера. Количество посетителей Web-узла регистрируется и обновляется на сервере, поэтому обычно эта задача выполняется с помощью специального CGI-прило- жения. Чтобы получить лучшее клиентское приложение, подсчитывающее посетителей Web-узла, необходимо "научить" его отправлять конечному пользователю отчет о том, сколько раз он уже посетил текущий узел. Для решения этой задачи привлекаются данные cookie (глава 16). Приложение комнаты бесед требует специального места на сервере, откуда устанавливаются соединения с конечными пользователями, посещающими приложение. Поэтому исключительно клиентскими средствами создать комнату бесед практически невозможно.
а) Правильно, поскольку это одно слово. Слитный формат подходит как нельзя лучше. б) Правильно, поскольку символ подчеркивания допускается использовать между словами. в) Неправильно, поскольку идентификатор нельзя начинать с цифры. г) Неправильно, поскольку пробелы использовать нельзя. д) Неправильно, поскольку символы апострофа и многие другие символы пунктуации использовать нельзя. 3. Диаграмма приведена ниже. Ссылка на элемент абзаца имеет следующий вид. document.getElementByld("formPar") document html head body title* "Search Form" img form "Search For:" input input 4. Общие: • оба имеют тип узлов, полученных из базового узла DOM; • оба могут выступать дочерними для родительских узлов, представляющих собой контейнеры. • Разные: • узел элемента создается из дескриптора, а текстовый узел не имеет собственного дескриптора; • текстовый узел не может быть родительским ни для какого другого узла. 5. <input type="button" name="Hi" value="Howdy" onelick="alert (•Hello to you, too!')"> Глава 5 <script type="text/javascript"> document.write ("Hello, world."); Приложение В. Ответы к упражнениям 1137
// --> </script> <html> <body> <script type="text/javascript"> <!-- document.write("Hello, world."); // --> </script> </body> </html> <html> <body> <script type="text/javascript"> <!-- // вывод приветственного сообщения document.write("Hello, world.") // --> </script> </body> </html> 4. Решение заключается в том, что оба обработчика событий вызывают отдельные функции. Кроме того, вы можете сделать так, что обработчики будут вызывать метод alert О. <html> <head> <title>An onload script</title> <script type="text/javascript"> <!-- function done(). { alert("The page has finished loading."); function alertUserO { alert("Ouch!"); } // --> </script> </head> <body onload="done()"> Here is some body text. <form> <input type="button" name="oneButton" value="Press Me!" onclick="alertUser()"> </form> </body> </html> а) На странице отображается два текстовых поля. б) Пользователь вводит текст в первое поле и переходит к другому полю, чтобы вызвать обработчик события onchange. в) Функция отображает во втором поле значение первого поля, представленное в верхнем регистре. 1138 Часть V. Приложения
Глава б а) Правильно. б) Неправильно. Переменная должна быть представлена одним словом, например howMany или howjnany. в) Правильно. г) Неправильно. Имя переменной не может начинаться с цифры. Если необходимо различать подобные переменные по именам, то поместите числовое значение в конец имени: address 1. 2. а) 4 б) 40 в) "4020" г) "Robert" 3. Используются функции parselntO nparseFloatO. Преобразуемые строки подставляются в качестве параметров функций. parseInt(document.forms[0].entry.value) 4 Оба значения текстового поля строковые; их необходимо преобразовать в числа перед арифметическим сложением. Функцию parseFloat () можно использовать в выражении присвоения значения (например var valuel = parseFloat(document.adder . inputA. value)) или выражении суммирования (document. adder. output. value = parseFloat (valuel) + parseFloat (value2)). 5. Конкатенация означает объединение двух строк в одну. Глава 7 1. Поскольку в функции ссылка указывает на текстовое поле entry формы entryForm, то обязательно используйте эти имена в атрибутах name соответствующих дескрипторов HTML. <html> <head> <script type="text/javascript"> var USStates = new Array(51) USStatestO] = "Alabama" USStates [1] = "Alaska" USStates[2] = "Arizona" USStates [3] = "Arkansas" USStates[4] = "California" USStates [5] = "Colorado" USSt;ates[6] = "Connecticut" USStates [7] = "Delaware" USStates [8] = "District of Columbia" USStates [9] = "Florida" USStates [10] « "Georgia" USStates[11] = "Hawaii" Приложение В. Ответы к упражнениям 1139
USStates[12] USStates[13] USStates[14] USStates[15] USStates[16] USStates[17] USStates[18] USStates[19] USStates[20] USStates[21] USStates[22] USStates[23] USStates[24] USStates[25] USStates[26] USStates[27] USStates[28] USStates[29] USStates [30] USStates[31] USStates [32] USStates [33] USStates [34] USStates [35] USStates [36] USStates [37] USStates [38] USStates [39] USStates[40] USStates [41] USStates [42] USStates [43] USStates [44] USStates [45] USStates [46] USStates [47] USStates [48] USStates [49] USStates [50] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = as = = = "Idaho" "Illinois" "Indiana" "Iowa" "Kansas" "Kentucky" "Louisiana" "Maine" "Maryland" "Massachusetts" "Michigan" "Minnesota" "Mississippi" "Missouri" "Montana" "Nebraska" "Nevada" "New Hampshire" "New Jersey" "New Mexico" "New York" "North Carolina" "North Dakota" "Ohio" "Oklahoma" "Oregon" "Pennsylvania" "Rhode Island" "South Carolina" "South Dakota" "Tennessee" "Texas" "Utah" "Vermont" "Virginia" "Washington" "West Virginia" "Wisconsin" "Wyoming" var stateEntered = new Array(51) stateEntered[0] stateEntered[1] stateEntered[2] stateEntered[3] stateEntered[4] stateEntered[5] stateEntered[6] stateEntered[7] stateEntered[8] stateEntered[9] - 1819 = 1959 « 1912 * 1836 « 1850 - 1876 ■ 1788 « 1787 ■ 0000 * 1845 stateEntered[10] » 1788 stateEntered[11] - 1959 stateEntered[12] * 1890 stateEntered[13] = 1818 stateEntered[14] = 1816 stateEntered[15] = 1846 stateEntered[16] = 1861 1140 Часть V. Приложения
stateEntered[17] = 1792 stateEntered[18] = 1812 stateEntered[19] = 1820 stateEntered[20] = 1788 s stateEntered[21] = 1788 stateEntered[22] = 1837 stateEntered[23] = 1858 stateEntered[24] = 1817 stateEntered[25] = 1821 stateEntered[26] = 1889 stateEntered[27] = 1867 stateEntered[28] = 1864 stateEntered[29] = 1788 stateEntered[30] = 1787 stateEntered[31] = 1912 stateEntered[32] = 1788 stateEntered[33] = 1789 stateEntered[34] = 1889 stateEntered[35] = 1803 stateEntered[36] = 1907 stateEntered[37] = 1859 stateEntered[38] = 1787 stateEntered[39] = 1790 stateEntered[40] = 1788 stateEntered[41] = 1889 stateEntered[42] = 1796 stateEntered[43] = 1845 stateEntered[44] = 1896 stateEntered[45] = 1791 stateEntered[46] = 1788 stateEntered[47] = 1889 stateEntered[48] = 1863 stateEntered[49] = 1848 stateEntered[50] = 1890 function getStateDate() { var selectedState = document.entryForm.entry.value; for ( var i = 0; i < USStates.length; i++) { if (USStates[i] == selectedState) { break; } } alert("That state entered the Union in " + stateEntered[i] + ".") ; } </script> </head> <body> <form name="entryForm"> Enter the name of a state: <input type="text" name="entry" /> <input type="button" value="Look Up Entry Date" onclick="getStateDate()" /> </body> </html> В определении этой функции существует несколько недостатков. В первом условном выражении if пропущены скобки. Фигурные скобки также пропущены во втором вложенном выражении if. . .else. Более того, фигурные скобки не заданы для всей Приложение Б. Ответы к упражнениям 1141
условной конструкции. Ниже приведен правильный вариант кода. Изменения введены полужирным начертанием. function format(ohmage) { var result » if (ohmage >= 10e6) { ohmage = ohmage / 10e5; result = ohmage + '■ Mohms"; } else { if (ohmage >= 10e3) { ohmage = ohmage / 10e2; result = ohmage + " Kohms"; } else { result = ohmage + " ohms"; alert(result); } 3. Представим один из вариантов. for (var i = 1; i < tomatoes.length; i++) { if (tomatoes[i].looks == "mighty tasty") { break var myTomato = tomatoes[i] 4. Новый вариант определяет другую локальную переменную для имени собаки. <html> <head> <script type="text/javascript"> var aBoy = "Charlie Brown" // глобальная var hisDog = "Snoopy" // глобальная function sampleFunction() { // использование неточного варианта var WallacesDog = "Gromit" // local version of hisDog var output = WallacesDog + " does not belong to " + aBoy + ".<br>" document.write(output) } </script> <body> <script type=Htext/javascript"> demo() // выполняется при загрузке документа document.write(hisDog + " belongs to " + aBoy + ".") </script> </body> </html> 5. В приложении используется три параллельных массива. Само оно структурировано подобно решению, предложенному в первом упражнении. Постарайтесь разобраться в приведенном ниже коде. <html> <head> ocript type="text/javascriptM> var planets = new Array(4) planets[0] = "Mercury" planets[1] = "Venus" 1142 Часть V. Приложения
planets[2] = "Earth" planets[3] = "Mars" var distance = new Array(4) distance[0] = "36 million miles" distance[1] = "67 million miles" distance[2] = "93 million miles" distance[3] = "141 million miles" var diameter = new Array(4) diameter[0] = "3100 miles" diameter[1] = "7700 miles" diameter[2] .= "7920 miles" diameter[3] = "4200 miles" function getPlanetDataO { var selectedPlanet = document.entryForm.entry.value; for ( var i = 0; i < planets.length; i++) { if (planets[i] == selectedPlanet) { break; } } var msg = planets[i] + " is " + distance[i] +. " from the Sun and " msg += diameter[i] + " in diameter. "; document.entryForm.output.value = msg; } </script> </head> <body> <form name="entryForm"> Enter the name of a planet: <input type="text" name="entry" /> <input type="button" value="Look Up a Planet" onclick= "getPlanetDataO " /> <br /> l <input type="text" size=70 name="output" /> </body> </html> Глава 8 l. а) Близко, но неточно. Ссылки на массив задаются в множественном числе. window.document.forms[0). б) Неправильно. Объект self соответствует окну, a en try Form должна соответствовать форме. Где же документ? Он должен задаваться ссылкой self.document.entryForm.entryField.value. в) Правильно. г) Неправильно. Пропущена ссылка на document. д) Правильно, если newWindow — это переменная, содержащая ссылку на вложенное окно. 2. window.status = "Welcome to my Web page." 3. document.write("<hl>We1come to my Web page.</hl>") Приложение Б. Ответы к упражнениям 1143
4. Сценарий в разделе body вызывает функцию, которая возвращает текст, введенный в диалоговом окне prompt (). <html> <head> <script type="text/javascript"> function askNameO { var name = prompt("What is your name, please?","") return name } </script> </head> <body> <script type="text/javascript">, document.write("Welcome to my web page, " + askNameO + ".") </script> </body> </html> 5. Адрес URL получен из свойства href объекта location. <html> <head> <script type="text/javascript"> function showLocationO { alert("This page is at: " + location.href); </script> </head> <body onload="showLocation()"> Blah, blah, blah. </body> </html> Глава 9 1, В листинге 9.1 используйте текстовый объект, поскольку только он принимает участие во всем преобразовании. <html> <head> <title>Text Object value Property</title> <script type="text/javascript"> function upperMe(field) { field.value = field.value.toUpperCase0; } </script> </head> <body> <form onsubmit="return false"> <input type="text" name="convertor" value="sample" onchange="upperMe(this)"> </form> </body> </html> В листинге 9.2 кнопка вызывает функцию, управляющую другим элементом формы. Используйте объект формы. <html> <head> 1144 Часть V. Приложения
<title>Checkbox Inspector</title> <script type**" text/javascript"> function inspectBox(form) { if (form.checkThis.checked) { alert("The box is checked."); } else { alert("The box is not checked at the moment."); </script> </head> <body> <form> <input type="checkbox" name="checkThis">Check here<br> <input type="button" value="Inspect Box" onclick="inspectBox(this.form)"> </form> </body> </html> В листинге 9.3 кнопка вновь вызывает функцию, которая управляет другими элементами формы. Используйте объект формы. <html> <head> <title>Extracting Highlighted Radio Button</title> <script type="text/javascript"> function fullName(form) { for (var i a 0; i < form.stooges.length; i++) { if (form.stooges[i].checked) { break; alert("You chose " + form.stooges[i].value + "."); } </script> </head> <body> <form> <b>Select your favorite Stooge:</b> <input type="radio" name»"stooges" value="Moe Howard" checked>Moe <input type="radio" name="stooges" value*="Larry Fine" >Larry <input type="radio" name="stooges" value="Curly Howard" >Curly<br> <input type="button" name="Viewer" value="View Full Name..." onclick="fullName(thie.form)"> </form> </body> </html> В листинге 9.4 все действия вызываются объектом select. В функции используйте только этот объект. <html> <head> <title>Select Navigation</title> <script type="text/javascript"> function goThere(liet) { location = list.options[list.selectedlndex].value; } Приложение В. Ответы к упражнениям 1145
</script> </head> <body> <form> Choose a place to go: <select name="urlList" onchange=MgoThere(this)M> <option selected value="index.html">Home Page <option value="store.html">Shop Our Store <option value="policies">Shipping Policies <option value="http://www.google.com">Search the Web </select> </form> </body> </html> 2. Ниже приведено несколько способов ссылки на объект текстового поля. document.getElementByld("email") document.forms[0].elements[0] document.forms["subscription"].elements[0] document.subscription.elements[0] document.forms[0].elements["email"] document.forms["subscription"].elements["email"] document.subscription.elements["email"] document.forms[0].email document.forms["subscription"].email document.subscription.email Ссылка document .all. email (любые ссылки, начинающиеся с document .all) поддерживается только в IE. В Mozilla и Safari она не обрабатывается. В W3C DOM используются ссылки, в которых задействован метод getElementByTagName (). Поскольку текстовое поле располагается на единственной форме страницы, то оно является первым элементом input страницы. Таким образом, в качестве ссылки можно использовать выражение document. body. getElementsByTagName (" input") [0]. 3. Ключевое слово this соответствует объекту текстового поля, поэтому this .value соответствует свойству value этого объекта. function showText(txt) { alert(txt); } 4. document.accessories.accl.value = "Leather Carrying Case"; document.forms[1].ace.value = "Leather Carrying Case"; 5. Объект select вызывает функцию, выполняющую необходимые операции. <html> <head> <title>Color Changer</title> <script type="text/javascript"> function setColor(list) { var newColor = list.options[list.selectedlndex].value; document.bgColor = newColor; } </script> </head> <body> <form> Select a background color: 1146 Часть V. Приложения
<select onchange="setColor(this)"> <option value="redl!>Stop <option value="yellow">Caution <option value="green">Go </select> </form> </body> </html> Глава 10 1. Используйте метод строка. indexOf () для поиска символа @ в значении поля. <html> <head> <title>E-mail Validator</title> ocript type="text/javascript"> function checkAddress(form) { if (form.email.value.indexOf("О") == -1) { alert("Check the e-mail address for accuracy."); return false; } return true; } </script> </head> <body> <form onsubmit="return checkAddress(this)"> Enter your e-mail address: <input type="text" name-nemail" size=30xbr> <input type="submit"> </form> </body> </html> 2. Помните, что подстрока вычисляет, но не включает второй параметр функции. Пробелы рассматриваются как символы. myString.substring(0,3) // результат = "Net" myString.substring(13,18) // результат = "gator" myString.substring(4,12) // результат = "cape Nav" 3. Пропущенный цикл отображен полужирным начертанием. Вы также можете использовать оператор приращения в переменной count для добавления 1 к каждой букве "е". function countE(form) { var count = 0; var inputString = form.mainstring.value.toUpperCase(); for (var i ■ 0; i < inputString.length; i++) { if (inputstr.charAt(i) » "e") { count +■ 1; } } var msg = "The string has " + count; msg += " instances of the letter е."; alert(msg); } Приложение В. Ответы к упражнениям 1147
4. Формула произвольного значения одной кости приведена в главе. <html> <head> <title>E-mail Validator</title> <script type="text/javascript"> function roll(form) { form.diel.value = Math.round(Math.random() * 5) + 1; form.die2.value = Math.round(Math.random() * 5) + 1; } </script> </head> <body> <form> <input type="text" name="diel" size=2> <input type="textn name="die2" size=2xbr> <input type="button" value="Roll the Dice" onclick="roll(this.form)"> </form> </body> </html> 5. Если в вычислениях вы используете метод Math. round (), то не забывайте, что он вызывается для экземпляра объекта Math. Другой метод Math. ceil () также может пригодиться, поскольку он округляет дробные значения. <html> <head> <title>Waiting for Santa</title> <script type="text/javascript"> function daysToXMASO { var oneDay = 1000 * 60 * 60 * 24; var today = new Date(); var XMAS = new Date("December 25, 1998"); var diff = XMAS.getTime() - today.getTime(); return Math.ceil(diff/oneDay); } </script> </head> <body> <script type="text/javascript"> document.write(daysToXMASO + " days until next Christmas.") </script> </body> </html> Глава 11 1. onload="parent.currCourse = 'historylOl'" 2. <Framesets> <Frame> mechanics Top Parent <Frame>| description <Frame> navigation 1148 Часть V. Приложения
3. Все три фрейма — "сестры" по отношению друг к другу; они имеют один родительский фрейм. parent.mechanics.location.href = иfrench201M.html" parent.description.location.href = "french201D.html" 4. Сценарий в одном из документов пытается сослаться на объект selector в одном из фреймов, но документ еще полностью не загружен, поэтому объект не представлен в модели браузера. 5. Из вложенного окна свойство opener ссылается на фрейм, вызывающий метод window. open (). При расширении ссылки на родительский фрейм она включает оба объекта: opener .parent. location. Глава 12 1. При загрузке документа дескриптор <img> создает объект изображения документа. Объект в памяти, выделенной браузеру, создается с помощью конструктора Image (). Оба объекта имеют одинаковые свойства. При указании в качестве src адреса URL объект из памяти загружается в кэш браузера (изображение кэшируется). 2. var janelmg = new Image(100,120); janelmg.src = "jane.jpg"; 3. document.images["people"].src = janelmg.src; 4. Следующие выражения выполняются во всех W3C DOM-совместимых браузерах. var newElem = document.createElement("a"); var newText = document.сreateTextNode("Next Page"); newElem.href = "page4.html"; newElem.appendChild(newText); document.getElementByld("forwardLink").appendChild(newElem); Приложение В. Ответы к упражнениям 1149
Internet-ресурсы, посвященные JavaScript и DOM оздание сценариев на языке JavaScript вызвало бурный интерес в Internet-сообществе. Рекомендуемые для посещения ресурсы, упомянутые в данном приложении, были актуальны на начало 2003 года. Но с тех пор прошло несколько лет. Web-узлы быстро устаревают, а в отдельных случаях даже перестают существовать. Очень часто они также изменяют свои URL-адреса. Приготовьтесь к тому, что вам придется изрядно постараться, чтобы найти свежую информацию по интересующему вопросу. Узел поддержки и обновлений для книги Самый свежий список исправлений и замечаний к англоязычному изданию этой книги вы найдете на Web-узле автора. http://www.dannyg.com/support/index.html Если в процессе изучения листингов этой книги у вас возникло много вопросов, то сначала поищите ответы на них в разделе Support Center указанного узла. Как уже рассказывалось ранее, вам совсем не обязательно вводить код листингов (JavaScript и HTML). Если после копирования кода примеров второй части вы так и не смогли добиться ожидаемого результата (и решение проблемы не изложено в разделе Support Center), то отправьте полученный проект, а также краткое описание проблемы (не забудьте указать версию используемого браузера и операционной системы) по адресу dannyg@dannyg. com (предположительно на английском языке). К сожалению, я не имею возможности отвечать на общие вопросы по JavaScript, а также не могу советовать, как лучше применить приведенные в книге примеры в реальной жизни. с
Группы новостей Самый быстрый способ получения ответа на интересующий вас вопрос — это задать его в группе новостей. Ниже приведен список известных мне популярных групп новостей, посвященных в том числе и JavaScript. comp.lang.j avascript microsoft.public.scripting.j script microsoft.public.windows.inetexplorer.ie5.programming.dhtml microsoft .public .windows. inetexplorer. ie5 .programming.dhtml. scripting microsoft.public.inetsdk.programming.scripting.j script netscape.public.mozilla.dom netscape.public.mozilla.j seng Перед тем, как задать свой вопрос, обязательно ознакомьтесь со списком наиболее часто задаваемых вопросов (FAQs), приведенных в следующем разделе. В архивом всевозможных групп новостей вы сможете ознакомиться, задав поиск в таком популярном диалоговом средстве, как Google Groups. Страница поиска Google Groups расположена по следующему адресу. http://groups.google.com/ Введите в верхнее поле ключевое слово или фразу, но постарайтесь ограничить список групп новостей несколькими элементами. Например, если поведение свойства стиля borderCollapse в Ш вам кажется странным, то введите в строку поиска borderCoUapse, а затем укажите выполнить операцию только в одной из групп новостей (форуме) — скажем, comp. lang. j avascript. Если вы отправили свой вопрос в группу новостей, то можете рассчитывать на быстрый и квалифицированный ответ, сопровождаемый разъяснениями в коде, (если, конечно, таковой содержался в вопросе). Самым важным аспектом является правильное толкование возникшей проблемы другим пользователям. Постарайтесь максимально детально изложить возникшие трудности, не забыв указать браузер, который вы использовали для выполнения сценариев. Наиболее часто задаваемые вопросы (FAQs) Каждая новая технология требует времени на изучение широким кругом разработчиков и пользователей. Как и любым другом случае изучение JavaScript и DHTML сопровождается непрерывным потоком одних и тех же вопросов, задаваемых разными пользователями. Их количество только увеличивается и разработчикам Web-узлов приходится уделять немало времени на ответы постоянно задаваемых вопросов. Перед тем, как отправить свой вопрос в форум или конференцию, внимательно изучите раздел FAQ (часто задаваемые вопросы), вполне возможно он уже содержит ответ на. Ниже приведено две ссылки на узлы, содержащие разделы с наиболее часто задаваемыми вопросами по JavaScript. j avascript.faqts.com developer.irt.org/script/script.htm Ответы на менее часто задаваемые вопросы — задаваемые ранее или рассматриваемые в других разделах — вы найдете с помощью современных поисковых средств. Документация Web-узлы, на которых приведена официальная документация по браузерам разных версий, разбросаны по всей Всемирной паутине. Поэтому, в приведенных ниже ресурсах вы найдете ссылки только на самые известные Web-узлы, посвященные указанной тематике. Приложение Г. Internet-ресурсы, посвященные JavaScript и DOM 1151
Microsoft содержит документацию, предназначенную для разработчиков в огромной базе данных, именуемой MSDN (Microsoft Developer Network). Начните поиск необходимой информации со следующего узла. http://msdn.microsoft.com/workshop/ Эта страница представляет собой портал на Internet-ресурсы, содержащие описание JavaScript и методов разработки клиентских сценариев, в общем случае озаглавливаемый названием "Web-разработка". Уделите особое внимание разделу Scripting (Разработка сценариев). В нем приведено много технических статей и рекомендаций разработчиков Microsoft, в том числе и относительно применения JScript (воплощение JavaScript в представлении Microsoft). Ссылки на ресурсы, описывающие технологии, которые используются для разработки сценариев в браузере Netscape, приведены на следующем портале. http://developer.netscape.com/docs/ Весьма интересная документация по написанию сценариев, а также описание будущих технологий содержатся на таком Web-узле. http://www.mozilla.org/docs Наконец, с промышленными стандартами технологий HTML, CSS и ECMAScript вы также можете познакомиться, не отходя от экрана своего компьютера. Примите к сведению, что приведенные на указанных ниже узлах документы рассчитаны в первую очередь на разработчиком серьезного программного обеспечения, как браузеры, редакторы WYSIWYG и т.д. Поэтому, изучая приведенные на Web-узлах, постарайтесь соблюдать душевное спокойствие и не расстраивайтесь, если многое так и останется для вас загадкой. http://www.ecma-international.org/publications/standards/ECMA-262.НТМ http://www.w3.org/TR/html4 http://www.w3.org/Markup http://www.w3.org/TR/REC-CSS2 http://www.w3.org/DOM/ Учтите, что описание элемента в технологии промышленного масштаба не указывает на его поддержку во всех современных браузерах. В реальной жизни сначала нужно добиться признания промышленных технологий и только после этого рассчитывать на их поддержку браузерами. World Wide Web Количество независимых Web-узлов, посвященных JavaScript, может удивить даже опытного посетителя Всемирной паутины. Многие узлы нормально функционируют только в ночное время, а потому оставляют мало надежд тем, кто привык работать в дневное время. Если вы хотите познакомиться с реальными примерами использования сценариев, которые не вошли в настоящую книгу, то обратитесь к традиционным поисковым средствам. Чтобы сузить область поиска, указывайте критерии максимально детально. В дополнение к узлам Netscape и Microsoft (а также многочисленным статьям, приведенным на узле ht tp: / /www. dannyg, com/ pubs/index. html), обратите свой взор на следующие ресурсы. http://builder.com http://www.webreference.com Эти узлы нельзя считать достаточными для всестороннего изучения JavaScript и DHTML, применяемых в Web-разработке. Не стоит полагаться в программировании на мнение одного или нескольких изданий. Сначала изучите все основные точки зрения и только после этого приступайте к собственным изысканием. В этом вам помогут ссылки на Web-узлы и группы новостей, приведенные выше. 1152 Часть V. Приложения
Дополнительные главы на компакт-диске
Предметный указатель Acrobat Reader, 40 ADO-свойства, 775 BBEdit, 53 В н HTML, 38 динамический, 50; 67 HTML-код вставка, 331 HTTP, 522 CGI, 63; 68; 652; 925 CGI-программа, 652 CGI-сценарий, 69 cookie, 546 доступ, 548 получение, 550 сохранение, 548 функции, 551 CSS,49;209;811 класс, 173 D Decision Helper, 67; 160 DHTML, 50; 67; 211 DOM, 48; 70; 196 Dreamweaver, 52 E ECMA, 48; 94 ECMA-262, 94 ECMAScript,48;177 JavaScript, 40 версии, 176 история, 41 назначение, 42; 68 особенности, 192 JScript, 41 LiveScript, 40 MacOS X, 55 Macromedia Flash, 40 RGB, 830 SGML, 38 M R FrontPage, 52 FTP, 522 GMT, 150; 549; 908 TheEvaluatorJr.,99; 191 и Unicode, 784 URI, 323; 568; 832; 1026 URL-адрес, 512; 767 URN, 356 UTC, 908
V VBScript, 41 w W3C, 49; 196 W3C DOM, 212; 538 Web-технологии, 37 тенденции развития, 46 Windows, 54 WWW, 522 WYSIWYG, 52 X XHTML, 38 A Авторизация, 311 Адрес, 512 Активизация объекта, 306; 349; 375 поля, 694 Активная область, 415 Альтернативное содержимое, 627 Анимация, 39 Анкер, 516; 542; 613 Аргумент, 79; 110 Арифметические операторы, 979 Атрибут, 119 action, 660; 673 enctype, 657 ГО, 264; 585 language, 84; 178; 269 method, 657; 658; 673 name, 76; 135; 664 size, 699; 715 src,84; 181 title, 821 type, 84; 178 value, 135; 674; 680; 715; 726 свойства, 322 создание, 579 удаление, 341; 342 Б Базовая объектная модель, 203 Базовый язык, 146 Бегущая строка, 433 Безопасный массив, 1037 Бессерверный сценарий, 42 Бета-версия браузера, 190 Библиотека объектов, 207 сценариев, 181; 232 функций, 1008 Бинарный оператор, 975 Браузер, 38; 53 определение версии, 182 совместимость, 46 Буквенное обозначение, 926 Булево значение, 907 Булевы операторы, 983; 984 Буфер обмена, 402 Буферизация страницы, 418 в Ввод кода документа, 598 Версия JavaScript, 176 браузера, 182 Ветвление, 185 сценария, 229 Видеоклип, 39 циклическое воспроизведение, 633 Вложенная строка, 109 функция, 998 Вложенный метод, 893 слой, 567 Внешний интерфейс, 64 Возврат каретки, 711 Возвращаемое значение, 120 Восьмеричные числа, 897 Временная зона, 908 Всплывание события, 749 Всплывающее меню, 511 Вставка, 365 HTML-кода, 331 элемента, 329 Встроенные объекты, 193 Выделение, 574; 694 анкерное, 1079 Вызов метода, 79 функции, 1004 Выполнение сценария прекращение, 600 Выравнивание, 626 Выражение, 97; 1032 1160 Предметный указатель
вложенное, 948 регулярное, 880 обновления, 951 Вырезание, 365 Выход из цикла, 954 Выходной поток, 127 Вычисление выражения, 97 даты, 152 проверка, 99 Вычисляемый стиль, 813 г Генерирование случайных чисел, 902 Гиперссылка, 613 Глобальная переменная, ПО; 1005 функция, 1024 Граница, 847 изображения, 628 Группа переключателей, 138 элементов, 734 Д Данные, 95 безусловное получение, 527 интерактивные, 65 отображение, 256 отправка на сервер, 681 передача, 140 перенаправление, 658 преобразование типов, 100 проверка, 65; 143; 707 связывание, 285 сортировка, 258 тип, 95 Данные диалогового окна, 474 Дата добавление, 565 преобразование, 916 проверка, 920 строковая, 914 формат, 915 Двунаправленная модель событий, 225 Деактивизация, 694 Действие по умолчанию, 751 Декодирование, 894 Дерево узлов, 76 Дескриптор, 575 <а>, 183 <агеа>, 622 <form>, 560; 657 <frame>, 491 <img>, 166; 622 <input>, 659 <1ауег>, 566 <link>,811 <noscript>, 182 <object>, 254 <script>, 58; 83; 178 <scriptfor>, 179 <style>, 811 комментария, 58 размещение, 84 Детектирование объектов, 187 Диалоговое окно данные, 474 свойства, 474 Динамический HTML, 67 стиль, 228 Динамическое содержимое, 230 Длина, 829 Длинные строки, 869 Добавление прототипа, 1019 Документ, 538 заголовок, 575 загрузка, 72; 88 иерархическая структура, 70; 119 многофреймовый, 156; 426 навигация, 532 настройка цветов, 540 объектная модель, 48; 69 открытие, 592 перезагрузка, 527 прокрутка, 463 с анкерами, 516 сведения, 569 тип данных, 556 Домен, 549 Доступ к cookie, 548 к свойствам формы, 132 Дочерний узел, 76; 247; 261 фрейм, 156 элемент, 248 Единицы измерения, 829 Предметный указатель 1161
ж Журнал, 531 3 Заголовок документа, 575 Загрузка фреймов, 396 Задержка, 439; 471 Закрытие окна проверка, 404 Запись, 531 cookie, 547 Заполнение массива данными, 925 Заполнитель, 570 Запрос данных, 459 команды, 593 Захват события, 337; 437; 576; 740 отключение, 740 Защищенный сценарий, 452 Значение, 95 булево, 907 возвращение, 120 комбинированное, 832 по умолчанию, 697 сравнение, 978 и Идентификатор, 75; 588 id, 76 Иерархическая структура, 70; 155; 119; 197 Иерархия наследования, 200 узлов, 215 Извлечение подстрок, 148 числа, 898 Изменение регистра, 147 Изображение, 165; 563; 622; 690 выравнивание, 626 граница, 628 динамическое, 630 загрузка, 629 имя, 634 исходный размер, 635 кэширование, 636 низкого разрешения, 633 предварительная загрузка, 166 Импорт таблицы стилей, 812 Имя каталога класса, 249 объекта, 75 окна, 417; 454 переменной, 97 события, 771 Индекс, 113 Индекс опции списка, 723 Индексная страница ветвления, 185 Инициализация переменной, 96 Интерактивные данные, 65 Интерфейс внешний, 64 интерактивный, 63 Исключение, 963 Исключительная ситуация, 945; 963 механизм обработки, 964 переход, 968 Исходный код, 57 размер изображения, 635 к Карта изображения, 640; 644; 646 именованных узлов, 322 Каскадная таблица стилей, 49; 209 Категории операторов, 976 Клавиша-модификатор, 761; 770; 773; 792 Класс, 197 имя, 249 Кнопка, 671; 689; 775 Reset, 673 Submit, 673 на форме, 658 определение, 775 Код клавиши, 784 документа, 598 Кодированный URL, 1026 Кодировка, 545 Коллекция frames, 159 Команды запросов, 593 Комбинированные значения, 832 Комментарий, 87; 180; 1032 Компактный массив, 926 Комплексные операторы, 990 Комплексные решения, 947 Конкатенация, 59; 102; 146; 869 Консоль JavaScript, 91 Конструктор, 925 Конструкция if...else, 946 ror-in, 957 try-catch-finaly, 965 1162 Предметный указатель
Координаты события, 768; 776; 798 формат, 645 Короткая обработка, 994 Кэширование, 166 изображений, 636 л Локальная переменная, ПО; 1005 м Маркер, 959 Маркированные операторы, 958 Массив, 113; 924 areas, 647 childNodes, 246 elements, 661 stylesheets, 811 взаимосвязанный, 927 заполнение данными, 925 извлечение элементов, 114 компактный, 926 многомерный, 930 объединение, 934 параллельный, 114; 927 создание, 113; 925 сортировка, 940 элементов формы, 659 объектов, 334 Межбраузерный сценарий, 58; 184 Метод, 78; 200; 219 addBehavior(), 295 addEventListener(), 298 alertO, 146 appendChild(), 301 applyElementO, 303 arrayxoncat(), 933 array join(), 936 array.sliceO, 939 array.sortO, 939 array.toStringO, 944 attachEvent(), 305 blurO, 306 charAt(), 875 charCodeAtO, 875 clear(), 577 clearAttributesO, 309 createPopupO, 444 click(),310 cloneNodeQ, 310 componentFromPointO, 311 contains(), 313 deleteRule(), 823 detachEvent(), 305; 314 dispatchEvent(), 314 escape(), 1026 eval(), 1027 execCommandO fireEvent(), 316 focus(), 306; 319 fromCharCodeO, 876 getAdjacentText(),319 getAttribute(), 320 getAttributeNode(), 321 getAttributeNodeNSO, 323 getAttributeNSO, 323 getBoundingClientRectO, 323 getClientRects(), 326 getElementsByTagName(), 326 getElementsByTagNameNS(), 327 getExpression(), 327 hasAttributeO, 328 hasAttributeNSO, 328 hasAttributes(), 328 hasChildNodes(), 328 hasOwnPropertyO, 1023 insertAdjacentElementO, 329 insertAdjacentHTMLO, 331 insertAdjacentText(), 331 insertBeforeO, 332 isPrototypeOfO, 1023 isSupported(), 333 item(), 334 lastlndex0f(), 879 localeCompareO, 879 mergeAttributes(), 335 normalize(), 336 match(), 879 open(), 592 releaseCapture(), 337 removeAttributeO, 341 removeAttributeNodeO, 341 removeAttributeNS(), 342 removeBehavior(), 342 removeChild(), 343 removeEventListener(), 298; 343 removeExpression(), 343 removeNode(), 344 removeRuleO, 822 replaceAdjacentText(), 345 replaceChild(), 346 replaceNode(), 346 scrollIntoView(), 349 Предметный указатель 1163
searchO, 884 setActiveO, 349 setAttribute(), 350 setAttributeNodeO, 341; 351 setAttributeNodeNSO, 351 setAttributeNSO, 352 setCapture(), 337 setExpression(), 352 slice(), 884 submit(), 666 substr(), 887 substringO, 888 swapNode(), 355 tags(), 355 toLoweiCaseO, 890 toStringO, 890 toUppeiCaseO» 890 unescape(), 1027 urns(), 356 watch(), 1032 window.open() writeO, 59 аргумент, 79 вложенный, 893 вызов, 79 параметр, 79 форматирования, 892 Многократно вложенные конструкции if...else, 949 Многомерные массивы, 930 Многофреймовый документ, 66; 156; 426 Модальное окно, 477 Модель объектов, 198 событий, 761 перехвата событий, 205 н Набор данных, 926 символов, 545 фреймов, 413; 498; 517 Навигационная панель, 160 Навигация по документу, 532 Надстройка, 39; 572 Названия фильтров, 863 Наследование, 197; 200; 396 объектов, 194 прототипа, 1020 Начальное выражение, 951 Нежелательная прокрутка, 465 Немодальное окно, 481 Несоизмеримые типы данных, 977 Новые концепции DOM, 215 о Область граница, 1090 действия, 111 изображения, 643 объекта, 323 Обмен данными, 523 Обозначение буквенное, 926 Обработка исключительных ситуаций, 945; 963 событий, 233 Обработчик события, 78; 201 onactivate, 357 onbeforecopy, 357 onbeforecut, 358 onbeforedeactivate, 357; 359 onbeforeeditfocus, 359 onbeforepaste, 359 onblur, 360 onchange, 139; 140 onclick, 138; 187; 361 oncontextmenu, 364 oncontrolselect, 364 oncopy, 364 oncut, 364 ondblclick, 366 ondeactivate, 357 ondrag, 367 ondragenter, 372 ondragleave, 372 ondragover, 372 ondragstart, 373 ondrop, 373 onerror, 419 onfilterchange, 374 onfocus, 375 onhelp, 376 onkeydown, 377 onkeypress, 377 onkeyup, 377 onload, 124 onlosecapture, 382 onmousedown, 383 onmouseenter, 384 onmouseleave, 384 onmousemove, 385 onmouseout, 385 onmouseover, 385 onmouseup, 383 onpaste, 386 onpropertychange, 388 onreadystatechange, 390 1164 Предметный указатель
onresize, 390 onresizeend, 390 onresizestart, 390 onselectstart, 391 onsubmit, 142 Обратный отсчет, 440 Обтекание текста, 604 Общие объекты, 236 Объединение, 102; 146 массивов, 934 строк, 869 Объект, 77 area свойство alt, 645 свойство areas[], 647 свойство coords, 645 свойство hash, 646 свойство host, 646 свойство hostname, 646 свойство href, 646 свойство pathname, 646 свойство port, 646 х свойство protocol, 646 свойство search, 646 свойство shape, 645 свойство target, 646 Array, 931 методы, 932 свойство length, 931 свойство prototype, 931 Attribute, 242 body, 601 метод createControlRangeO, 607 метод createTextRange(), 607 метод doScroll(), 607 обработчик события onafterprint, 608 обработчик события onbeforeprint, 608 обработчик события onscroll, 608 свойство aLink, 602 свойство background, 602 свойство bgColor, 602; 603 свойство bgProperties, 603 свойство bottomMargin, 603 свойство leftMargin, 603; 604 свойство link, 602; 604 свойство no Wrap, 604 свойство rightMargin, 603; 605 свойство scroll, 605 свойство scrollLeft, 605 свойство scrollTop, 605 свойство text, 602; 606 свойство topMargin, 603; 606 свойство vLink, 602; 606 Boolean, 907 button метод click(), 675 обработчик события onclick, 675 обработчик события onmousedown, 676 обработчик события onmouseup, 676 свойство form, 674 свойство name, 674 свойство type, 674 свойство value, 674 Checkbox, 677 метод click(), 681 обработчик события onclick, 681 свойство checked, 678 свойство defaultChecked, 679 свойство type, 680 свойство value, 680 cssRule, 811; 824 currentStyle, 827 dataTransfer,781 Date методы, 151 document метод clear(), 577 метод close(), 578 метод createAttribute(), 579 метод createCommentO, 579 метод createDocumentFragmentO, 579 метод createElement(), 129; 580 метод createEvent(), 581 метод createEventObjectO, 581 метод createRange(), 581 метод createStyleSheetO, 582 метод createTextNode(), 583 метод createTreeWalkerO, 584 метод elementFromPointO, 585 метод execCommandO, 586 метод getElementByldO, 129; 588 метод getElementsByNameO, 589 метод getSelectionO, 590 метод handleEvent(), 591 метод орепО, 592 метод quei7CormnandComnlandState(), 593 метод queryCommandEnabledO, 593 метод queryCommandlndtermO, 593 метод queryCornmandSupportedO, 593 метод queryCommandTextO, 593 метод queryCommandValueO, 593 метод recalc(), 594 метод releaseEvents(), 594 метод routeEvent(), 595 метод write(), 129; 595 метод writelnO, 595 метод captureEventsO, 576 Предмвтный указатель 1185
метод write(), 127 обработчик события onselectionchange, 599 обработчик события onstop, 599 свойство activeElement, 539 ! свойство anchors [], 542 свойство applets, 544 свойство bgColor, 540; 544 свойство body, 544 свойство characterSet, 545 свойство charset, 545 свойство compatMode, 546 свойство cookie, 546 свойство defaultCharset, 555 свойство default View, 556 свойство designMode, 556 свойство doctype, 556 свойство documentElement, 557 свойство domain, 557 свойство embeds, 557 свойство expando, 558 свойство fgColor, 540; 558 свойство fileCreatedDate, 558 свойство fileModifiedDate, 558 свойство fileSize, 558 свойство forms[], 126; 560 свойство frames[], 562 свойство height, 562 свойство ids[], 563 свойство images[], 126; 563 свойство implementation, 564 свойство lastModified, 565 свойство layers[], 566 свойство linkColor, 540; 567 свойство links[], 568 свойство location, 568 свойство media, 570 свойство mimeType, 571 свойство nameProp, 571 свойство namespaces[], 571 свойство parent Window, 571 свойство plugins[J, 572 свойство protocol, 572 свойство referrer, 572 свойство scripts!], 573 свойство security, 574 свойство selection, 574 свойство styleSheets[], 575 свойство tags[], 575 свойство title, 575 свойство URL, 568; 575 свойство URLUnencoded, 575 свойство vlinkColor, 540; 576 свойство width, 562; 576 свойство alinkColor, 540 1166 DocumentType, 556 error метод toStringO, 974 свойство constructor, 973 свойство description, 973 свойство filename, 973 свойство lineNumber, 973 свойство message, 973 свойство name, 974 свойство number, 974 event свойство altKey, 773 свойство altLeft, 774 свойство behaviorCookie, 774 свойство behaviorPart, 774 свойство bookmarks, 774 свойство boundElements, 774 свойство button, 774 свойство cancelBubble, 776 свойство clientX, 776 свойство clientY, 776 свойство ctrlKey, 773 свойство ctrlLeft, 774 свойство dataField, 774 свойство dataTransfer, 781 свойство fromElement, 783 свойство keyCode, 784 свойство nextPage, 786 свойство offsetX, 776 свойство offsetY, 776 свойство propertyName, 786 свойство qualifier, 774 свойство reason, 774 свойство recordset, 774 свойство repeat, 787 свойство return Value, 787 свойство saveType, 788 свойство screenX, 776 свойство screenY, 776 свойство shiftKey, 773 свойство shiftLeft, 774 свойство srcElement, 788 свойство srcFiiter, 789 свойство srcUrn, 790 свойство toElement, 783; 790 свойство type, 790 свойство x, 776 свойство у, 776 совместимость, 759 filter, 261; 856 form метод handleEvent(), 664 метод reset(), 665 Предметный указатель
метод submit(), 665 обработчик события onreset, 666 обработчик события onsubmit, 667 свойство acceptCharset, 660 свойство action, 660 свойство autocomplete, 660 свойство checked, 136 свойство elements[], 133; 660 свойство encoding, 663 свойство enctype, 663 свойство length, 663 свойство method, 663 свойство name, 664 свойство target, 664 frame свойство allowTransparency, 492 свойство borderColor, 492 свойство contentDocument, 492 свойство contentWindow, 493 свойство frameBorder, 493 свойство height, 494 свойство longDesc, 494 свойство marginHeight, 494 свойство margin Width, 494 свойство name, 495 свойство noResize, 495 свойство scrolling, 495 свойство src, 497 свойство width, 494 frameset свойство border, 499 свойство borderColor, 499 свойство cols, 499 свойство frameBorder, 502 свойство frameSpacing, 502 свойство rows, 499 history метод back(), 531 метод forward(), 531 метод go(), 533 свойство current, 530 свойство length, 530 свойство next, 530 свойство previous, 530 iframe свойство align, 504 свойство allowTransparency, 505 свойство contentDocument, 505 свойство contentWindow, 505 свойство height, 506 свойство hspace, 506 свойство longDesc, 506 свойство marginHeight, 506 свойство marginWidth, 506 свойство name, 507 свойство scrolling, 507 свойство src, 507 свойство vspace, 506 свойство width, 506 Image обработчик события onload, 641 обработчик события у, 641 свойство align, 626 свойство alt, 627 свойство border, 627 свойство complete, 691 свойство dynsrc, 629 свойство fileCreatedDate, 631 свойство fileModifiedDate, 631 свойство fileSize, 631 свойство fileUpdateDate, 631 свойство height, 631 свойство href, 632 свойство hspace, 632 свойство isMap, 632 свойство longDesc, 633 свойство loop, 633 свойство lowsrc, 633 свойство mimeType, 634 свойство name, 634 свойство nameProp, 634 свойство naturalHeight, 635 свойство naturalWidth, 635 свойство protocol, 635 свойство src, 636; 691 свойство start, 639 свойство type, 691 свойство useMap, 640 свойство vspace, 632; 640 свойство width, 631; 640 свойство х, 640 свойство complete, 628 свойство у, 640 input, 709; 735 Layer, 206; 566 label свойство htmlFor, 670 location, 124 метод assign(), 526 метод reload(), 526 метод replace(), 528 свойство hash, 515 свойство host, 516 свойство hostname, 520 свойство href, 520 свойство pathname, 521 Предметный указатель 1167
свойство port, 522 свойство protocol, 522 свойство search, 522 Math метод floor(), 150 метод random(), 150 свойства, 901 namespace, 571 navigator, 71; 125 Node, 321 number методы,' свойство свойство свойство свойство свойство свойство свойство Object, 1022 optgroup свойство 905 constructor, 904 MAX_VALUE, 904 MIN_VALUE, 904 NaN, 905 NEGATIVEJNFINITY, 904 POSmVEJNFINITY, 904 prototype, 905 label, 733 свойство label, 732 password, 708 popup метод hide(), 510 метод show(), 510 свойство document, 509 свойство isOpen, 509 radio методы click(), 688 обработчик события onclick, 689 свойство checked, 685 свойство defaultChecked, 687 свойство length, 687 свойство name, 688 свойство type, 688 свойство value, 688 Range, 1057 метод cloneContentsO, 1062 метод cloneRange(), 1062 метод collapse(), 1063 метод compareNode(), 1067 метод comparePointO, 1067 метод createContextualFragmentO, 1068 метод deleteContentsO, 1069 метод detach(), 1070 метод extractContents(), 1070 метод insertNode(), 1071 метод intersectsNodeO, 1072 метод isPointInRange(), 1073 метод selectNodeQ, 1073 метод selectNodeContents(), 1073 метод setEnd(), 1074 метод setEndAfter(), 1075 метод setEndBeforeO, 1075 метод setStart(), 1074 метод setStartAfterO, 1075 метод setStartBeforeO, 1075 метод surroundContentsO, 1076 метод toStringO, 1077 метод compareBoundaryPointsO, 1064 свойство collapsed, 1059 свойство common AncestoiContainer, 1060 свойство endContainer, 1060 свойство endOffset, 1061 свойство startOffset, 1061 rule, 824 runtimeStyle, 827 screen, 429 selection метод addRange(), 1081 метод clear(), 1081 метод collapseO, 1081 метод collapseToEnd(), 1082 метод collapseToStartO, 1082 метод containsNodeO, 1082 метод createRange(), 1082 метод deleteFromDocumentO, 1082 метод empty(), 1082 метод extend(), 1083 метод getRangeAt(), 1083 метод removeAllRangesO, 1083 метод removeRangesO, 1083 метод selectAllChildren(), 1083 метод toStringO, 1084 свойство anchorNode, 1079 свойство appendData, 1085 свойство data, 1085 свойство deleteData, 1085 свойство focusNode, 1079 свойство insertData, 1085 свойство isCollapsed, 1079 свойство rangeCount, 1079 свойство replaceData, 1085 свойство splitText, 1088 свойство substringData, 1085 свойство type, 1080 свойство typeDetail, 1081 select метод add(), 729 метод item(), 729 метод namedltemO, 729 метод options[HHfleKc].add(), 729 метод options [индекс] .remove(), 729 1168 Предметный указатель
метод remove(), 729 обработчик события onchange, 730 свойство length, 722 свойство multiple, 722 свойство options[], 722 свойство options[HHfleKcJ.defaultSelected, 723 свойство ориош[индекс].index, 723 свойство options [индекс].selected, 724 свойство options[HHfleKc].text, 725 свойство орйоп8[индекс]. value, 726 свойство selectedlndex, 727 свойство size, 728 свойство type, 728 свойство value, 728 String метод alertO, 146 метод chartAtO, 148 метод index0f(), 147 метод substringO, 148 свойство constructor, 873 свойство length, 873 свойство prototype, 874 style свойство media, 814 свойство type, 815 stylesheet метод addlmportO, 822 метод addRule(), 822 метод deleteRule(), 823 метод insertRuleO, 823 метод removeRule(), 822 свойство cssRules, 816 свойство cssText, 816 свойство disabled, 817 свойство href, 818 свойство id, 818 свойство imports, 818 свойство media, 818 свойство ownerNode, 819 свойство ownerRule, 819 свойство owningElement, 819 свойство pages, 820 свойство parentStyleSheet, 820 свойство readonly, 820 свойство rules, 821 свойство title, 821 свойство type, 822 Tabular Data Control, 254 text метод blur(), 702 метод focusO, 703 метод select(), 703 обработчик события onafterupdate, 705 обработчик события onbeforeupdate, 705 обработчик события onblur, 705 обработчик события onchange, 707 обработчик события onerrorupdate, 705 обработчик события onfocus, 705 обработчик события onselect, 705 свойство default Value, 696 свойство form, 697 свойство maxLength, 698 свойство name, 698 свойство readonly, 699 свойство size, 699 свойство type, 700 свойство value, 700 textarea метод createTextRange(), 712 свойство cols, 712 свойство rows, 712 свойство wrap, 712 TextNode, 1084 * TextRange, 1090 TreeWalker метод firstChildO, 611 метод lastChildO, 611 метод nextNode(), 612 метод nextSiblingO, 611 метод parentNode(), 611 метод previousNodeO, 612 метод previousSiblingO, 611 свойство currentNode, 611 свойство expandEntityReference, 611 свойство filter, 611 свойство root, 611 свойство whatToShow, 611 VBArray, 1037 window, 118 имя, 417 метод alert(), 122; 435 метод back(), 436 метод captureEventsO, 437 метод clearlnterval(), 439 метод clearTimeoutO, 439 метод close(), 441 метод confirmO, 123; 442 метод execScriptO, 444 метод find(), 445 метод forwardO, 436; 445 метод handleEvent(), 445 метод home(), 446 метод moveByO, 446 метод moveTo(), 446 метод navigateO, 449 метод open(), 450 Предметный указатель 1169
метод print(), 456 метод prompt(), 123; 458 метод releaseEvents(), 460 метод resizeBy(), 460 метод resizeTo(), 460 метод routeEvent(), 462 метод scroll(), 463 метод scrollBy(), 465 метод scrollTo(), 465 метод setlntervalO, 467 метод setTimeout(), 471 метод showModaЮialog(), 473 метод showModelessDialogO, 473 метод sizeToContent(), 484 метод stop(), 484 window.clipboardData методы, 403 window.extemal методы, 411 window, location, 514 активизация, 349; 375 анкера, 613 даты, 150; 909 документа, 47; 71; 116; 125; 535 изображения, 165; 622 кнопки, 136; 671 набора фреймов, 497 окна, 71; 400 окна документа, 118 определение, 187 ошибки, 972 переключателя, 137 пользовательский, 1009 правила свойство cssText, 825 свойство parentstyleSheet, 825 свойство readonly, 825 свойство selectorText, 825 свойство style, 826 свойство type, 826 связывание, 74 скрытого поля, 709 слоя, 206 события метод initEvent(), 807 метод initKeyEventO, 807 метод initMouseEvent(), 807 метод initMutationEvent(), 807 метод initUIEvent(), 807 метод preventDefault(), 808 метод stopPropagation(), 809 методы, 760 свойство bubbles, 793 свойство button, 793 свойство cancelBubble, 794 свойство clientX, 797 свойство clientY, 797 свойство currentTarget, 800 свойство data, 766 свойство detail, 802 свойство isChar, 802 свойство keyCode, 794 свойство layerX, 767; 797 свойство layerY, 767; 797 свойство metaKey, 792 . свойство modifiers, 770 свойство originalTarget, 802 свойство pageX, 767; 797 свойство pageY, 767; 797 свойство relatedTarget, 802 свойство screenX, 767; 797 свойство screenY, 767; 797 свойство shiftKey, 792 свойство target, 770; 804 свойство timeStamp, 805 свойство type, 771; 806 свойство view, 807 свойство which, 771 свойство altKey, 792 свойство eventPhase, 802 свойство cancelable, 794 свойство charCode, 794 свойство ctrlKey, 792 создание, 199 списка, 139; 713 ссылки свойство charset, 617 свойство coords, 617 свойство hash, 617 свойство host, 617 свойство hostname, 617 свойство href, 618 свойство hrefLang, 618 свойство Methods, 618 свойство mimeType, 618 свойство name, 619 свойство nameProp, 619 свойство pathname, 617 свойство port, 617 свойство protocol, 617 свойство protocolLong, 619 свойство rel, 619 свойство rev, 619 свойство search, 617 свойство shape, 617 свойство target, 620 1170 Предметный указатель
свойство text, 620 свойство type, 620 свойство urn, 620 свойство х, 621 свойство у, 621 статичный, 149; 224 стиля, 810 строки, 146 фильтра, 856 флажка, 136 формы, 131; 650 функции метод apply(), 1002 метод call(), 1002 метод toStringO, 1003 метод valueOf(), 1003 свойство arguments, 999 свойство arity, 1000 свойство caller, 1000 свойство lengtt, 1002 целевой, 744 экрана, 71 объект элемента списка, 731 обработчик события onbeforeprint, 485 onbeforeunload, 485 ondragdrop, 486 опеггог, 487 onhelp, 487 onload, 488 onmove, 489 onresize, 489 onunload, 490 свойство appCore, 402 clientlnformation, 402 clipboardData, 402 closed, 403 components, 405 Components [], 402 controllers, 405 controllers!], 402 crypto, 405 defaultStatus, 405 dialogArguments, 406 dialogHeight, 406 dialogLeft, 407 dialogTop, 407 dialogWidth, 406 directories, 408 document, 410 event, 410 external, 410 frameElement, 411 frames, 412 history, 414 innerHeight, 415 innerWidth, 415 loading, 416 location, 417 locationbar,408;417 menubar, 408 name, 417 navigator, 417 offscreenBuffering, 418 onerror, 418 opener, 162; 421 outerHeight, 415; 423 outerWidth,415;423 pageXOffset, 423 pageYOffset, 423 parent, 426 personalbar, 408; 428 pkcsl 1,405 prompter, 402 returnValue, 428 screen, 428 screenLeft, 429 screenTop, 429 screenX, 429 screenY, 429 scrollbars, 408; 430 scrollMaxX, 430 scrollMaxY, 430 scrollX, 430 scrollY, 430 self, 431 sidebar, 402; 432 status, 122; 432 statusbar, 408; 434 toolbar, 408; 434 top, 434 window, 435 Объектная модель, 48; 69; 196 комбинирование, 227 поколение, 213 типы, 204 Объектно-ориентированная модель, 220 Объектные операторы, 987 Объекты базового языка, 146 встроенные, 193 Оглавление, 64; 525 Ограничивающий прямоугольник, 323 Окно активная область, 415 Предметный указатель 1171
ввода данных, 459 загрузка данных, 454 запроса, 123 изменение размера, 461; 489 имя, 417; 454 методы, 119 модальное, 407 открытие, 450 перемещение, 447 подтверждения, 123; 443 предупреждения, 122 родительское, 156; 394 свойства, 119; 413 создание, 120; 452 ширина и высота, 415 элементы управления, 409 Операнд, 102 Оператор, 87; 102; 975 const, 1033 continue, 954 delete, 987 if, 106 if...else, 107 in, 988 instanceof, 989 mailto:, 660 new, 989 parent, 395 self, 431 switch, 960 this, 990 top, 395 try-catch-finally, 965 typeof, 991 var, 96; 1034 void, 992 with, 958 арифметический, 102; 979 булев, 983 выполнение, 87 дополнения, 147 категории, 975 комплексный, 990 маркированный, 95^ немедленного выполнения, 88 объектный, 987 побитовый, 986 приращения, 982 присвоения, 96; 981 сравнения, 102; 976 условный, 106 Описание типов документов, 212 Определение даты, 152 кнопки, 775 свойств, 1017 Опции списка, 716 изменение, 719 удаление, 729 Отключение захвата события, 740 фрейма, 396 Открытие документа, 592 окна, 450 Отмена всплывания, 751 Отображение данных, 256 Отправка формы, 142: 656 Отпускание кнопки, 373 Отслеживание события, 746 Отступ, 632; 847 Ошибка сценария, 90; 419 просмотр, 90 п Панель каталогов, 408 управления, 469; 532 Параллельный массив, 927 Параметр, 79 метода, 59 передача, 468 страницы, 854 фона, 603 функции, 109; 999 Пароль, 708 Первый сценарий, 56 Переадресация события, 747; 751 Передача объекта, 141 данных, 140 событий, 739 форм и элементов в функции, 653 Перезагрузка документа, 527 страницы, 55 формы, 665 Переключатель, 684 выбор, 718 длина, 687 установка, 686 Переменная, 95 глобальная, ПО; 1005 1172 Предметный указатель
значение, 96 имя, 97 инициализация, 96 локальная, ПО область действия, 111 параметров, 1007 создание, 96 строковая, 869 Перемещение окна, 447 Перенаправление данных, 658 Перетаскивание, 367; 767 Перехват события, 206; 577 Переход к исключительным ситуациям, 968 Печать, 457; 854 Побитовые операторы, 986 Поведение, 211; 295; 774 отключение, 342 текстовых объектов, 134 Поддержка JavaScript, 182 Подокно создание, 422 Подпись, 734 Подсчет дней, 917 Подтверждение, 442 Позиционирование, 844 Поиск в параллельном массиве, 928 данных, 64 строк, 147 циклический, 929 Поколения DOM, 213 Поле, 847 ввода пароля, 708 ввода файла, 735 Полоса прокрутки, 607; 852 Получатель свойств, 1017 Получение свойств стиля, 813 Пользовательская функция, 997 Пользовательский метод добавление, 1015 Пользовательский объект, 1009 Поток выходной, 127 Правило, 824 типы, 827 Предварительная загрузка изображений, 166 Предотвращение всплывания события, 750 Предупреждение, 122; 436; 475 Прекращение выполнения сценария, 600 Преобразование даты, 916 одного изображения в другое, 860 символов, 876 строк в числа, 101; 898 типов данных, 100 чисел в строки, 101; 899 Приемник событя, 225; 298 Приложение Decision Helper, 67; 160 The Evaluator, 191 Принципы совместимости, 192 Принятие решений, 67; 160; 946 Приоритет, 184 операторов, 992 Проверка вычислений, 99 данных, 707 дат, 920 загрузки фреймов, 396 закрытия окна, 404 правильности данных, 143 Программное обеспечение, 52 Прокрутка, 463 изображения, 463 нежелательная, 465 предотвращение, 609 расстояние, 606 страницы, 349; 605 фрейма, 496 Просмотр свойств, 957 Простой документ, 72 Простые решения, 946 Протокол, 522; 572 mailto:, 656 Прототип, 194; 874; 932 Пустой фрейм, 397 Путь, 549 Р Равенство несоизмеримых типов данных, 977 Раздел документа, 85 заголовка, 85 тела, 85 Разделение строки, 884 Размещение сценариев, 83 события, 771 текста, 345 Расширение, 210 Расширенная модель, 205 Расширяемое свойство, 558 Регистр, 147 Регулярное выражение, 880 Рекурсия, 1008 Родительский узел, 77 Предметный указатель 1173
Родительское окно, 156; 394; 571 Ролловер, 166; 168 Сведения о документе, 569 о файле, 559; 631 Свободное определение типов, 193 Свойства акустические, 855 атрибута, 322 вида и макета документа, 839 границ и полей, 847 диалогового окна, 474 дополнительные, 855 макета документа, 839 позиционирования, 844 полосы прокрутки, 852 события, 738 списков, 851 стиля, 828 страницы и печати, 854 таблиц, 853 текста и шрифта, 832 фона, 846 формы, 132 Свойство, 78; 199; 217 accessKey, 239 all, 241 anchors, 542 attributes, 242 behaviorUrns, 243 canHaveChildren, 244 canHaveHTML, 245 childNodes, 246 children, 248 className, 249 clientHeight, 250 clientLeft,251 clientTop, 251 clientWidth, 250 complete, 628 contentEditable, 252 cookie, 546 currentStyle, 253 dataFld, 253 dataFormatAs, 253 dataSrc, 253 defaulChecked, 679 dir, 259 disabled, 259 document, 260 filters[], 261 firstChild, 261 height, 263 hideFocus, 264 id, 264 innerHTML, 223; 265 innerText, 265 isContentEditable, 267 isDisabled, 267 isMultiLine, 268 isTextfcdit, 269 lang, 269 language, 269 lastChild, 261 length, 270 localName, 270 namespaceURI, 270 nextSibling, 271 nodeName, 272 nodeType, 272 node Value, 274 offsetHeight, 274 offsetLeft, 275 offsetParent, 276 offsetTop, 275 offsetWidth, 274 outerHTML, 278 outerText, 278 ownerDocument, 280 nodeValue, 274 parentElement, 280 parentNode, 281 parentTextEdit, 282 prefix, 270 previousSibling, 271 readyState, 283 значения, 283 recordNumber, 284 runtimeStyle, 286 scopeName, 286 scrollHeight, 287 scrollLeft, 288 scrollTop, 288 scrollWidth, 287 sourcelndex, 288 style, 289 tablndex, 289 tagName, 291 tagUrn, 292 title, 292 type, 661 uniquelD, 293 width, 263 изменение, 354; 388 расширяемое, 558 1174 Предметный указатель
Связывание данных, 285 объектов, 74 Серверный сценарий, 38 Символ преобразование, 876 специальный, 870 Синтаксический анализ, 898 Синхронизация фреймов, 397 Система исчисления, 899 Системные цвета, 831 Скрытие сценария, 180 Скрытое поле, 709 Слой, 206; 566 вложенный, 567 Случайное число, 902 Смещение, 1088 страницы, 424 Событие, 210; 368; 694; 737 всплывание, 749 двунаправленная модель, 225 захват, 337; 437; 576; 740 изменение, 761 клавиатуры, 379; 762 координаты, 768; 776; 798 обработка, 233; 300 обработчик, 80 освобождение, 741 отключение захвата, 740 отмена всплывания, 751 отмена захвата, 382 отслеживание, 746 переадресация, 746 передача, 739 перехват, 577 предотвращение всплывания, 750 приемник, 225; 298 расположение, 771 свойства, 738 создание, 581 типы, 576; 763 Совместимость, 189; 1092 принципы, 192 объектов event, 759 стандартов, 233 Содержимое узла, 221 элемента, 208 Создание атрибута, 579 окна, 120 фрейма, 393 элемента, 580 Сообщение в строке состояния, 406; 432 об ошибке, 91 Сортировка внешних данных, 258 массивов, 940 Составные решения, 947 Специальные символы, 870 Список, 713; 851 именованных узлов, 334 Справочная система, 376; 488 Сравнение значений, 978 моделей событий, 761 Среда разработки, 53 Срок службы, 549 Ссылка, 568; 573; 613 на объект, 75; 121; 157 на событие, 758 на фрейм, 394 на элемент, 215 на элементы управления формы, 652 Старые браузеры, 86; 179; 764 Статичный объект, 149; 224 Стиль, 575 вычисляемый, 813 динамический, 228 категории, 829 получение свойств, 813 свойство, 828 accelerator, 855 background, 846 backgroundAttachment, 846 backgroundColor, 846 backgroundlmage, 847 backgroundPosition, 847 backgroundPositionX, 847 backgroundPositionY, 847 backgroundRepeat, 847 behavior, 855 border, 847 borderBottom, 848 borderBottomColor, 848 borderBottomStyle, 848 borderBottomWidth, 849 borderCollapse, 853 borderColor, 849 borderLeft, 848 borderLeftColor, 848 borderLeftStyle, 848 borderLeftWidth, 849 borderRight, 848 borderRightColor, 848 borderRightStyle, 848 Предметный указатель 1175
borderRightWidth, 849 borderSpacing, 853 borderStyle, 849 borderTop, 848 borderTopColor, 848 borderTopStyle, 848 borderTopWidth, 849 borderWidth, 849 bottom, 844 captionSide, 853 clear, 839 clip, 839 clipBottom, 839 clipLeft, 839 clipRight, 839. clipTop, 839 color, 832 content, 839 counterlncrement, 839 counterReset, 840 cssFloat, 840 cssText, 855 cursor, 840 direction, 840 display, 840 emptyCells, 853 filter, 841 font, 833 fontFamily, 833 fontSize, 833 fontSizeAdjust, 833 fontStretch, 833 fontStyle, 834 fontVariant, 834 fontWeight, 834 height, 845 imeMode, 855 layoutGrid, 841 layoutGridChar, 841 layoutGridLine, 841 layoutGridMode, 841 layoutGridType, 842 left, 844 letterSpacing, 834 lineBreak, 834 lineHeight, 834 listStyle, 851 listStylelmage, 852 HstStylePosition, 852 listStyleType, 852 margin, 849 marginBottom, 850 marginLeft, 850 marginRight, 850 marginTop, 850 markerOffset, 842 marks, 842 maxHeight, 842 maxWidth, 842 minHeight, 842 minWidth, 842 mozBorderRadius, 850 mozBorderRadiusBottomLeft, 850 mozBorderRadiusBottomRight, 850 mozBorderRadiusTopLeft, 850 mozBorderRadiusTopRight, 850 mozOpacity, 850 orphans, 854 outline, 850 outlineColor, 850 outlineStyle, 851 outlineWidth, 851 overflow, 842 overflowX, 843 overflowY, 843 padding, 851 paddingBottom, 851 paddingLeft, 851 paddingRight, 851 paddingTop, 851 page, 854 f pageBreakAfter, 854 pageBreakBefore, 854 pageBreaklnside, 854 pixelBottom, 845 pixelHeight, 845 pixelLeft, 845 pixelRight, 845 pixelTop, 845 pixelWidth, 845 posBottom, 845 posHeight, 845 position, 846 ^ posLeft, 845 posRight, 845 posTop, 845 posWidth, 845 quotes, 835 right, 844 ruby Align, 835 rubyOverhang, 835 rubyPosition, 835 scrollbar3dLightColor, 852 scrollbarArrowColor, 852 scrollbarBaseColor, 852 scrollbarDarkShadowColor, 852 scrollbarFaceColor, 852 scrollbarffighlightColor, 852 1176 Предметный указатель
scrollbarShadowColor, 852 scrollbarTrackColor, 852 size, 854 styleFloat, 843 tableLayout, 853 textAlign, 835 textAlignLast, 835 textAutospace, 836 textDecoration, 836 textDecorationBlink, 836 textDecorationLineThrough, 836 textDecorationNone, 836 textDecorationOverline, 836 te^xtDecorationUnderline, 836 textlndent, 836 texUustify, 836 textJustifyTrim, 837 textKashidaSpace, 837 textOverflow, 837 textShadow, 837 textTransform, 837 textUnderlinePosition, 837 top, 844 unicodeBidi, 838 verticalAlign, 843 visibility, 843 whiteSpace, 838 widows, 854 width, 844; 845 wordBreak, 838 wordSpacing, 838 wordwrap, 838 writingMode, 838 zlndex, 846 zoom, 844 создание, 582 Стороны прямоугольника, 831 Страница загрузка, 534 контекстно-зависимая, 525 кэширование, 418 перезагрузка, 55 прокрутка, 349; 605 смещение, 424 фон, 603 Страница ветвления, 185 Строка, 146; 868 извлечение части, 887 объекдинение, 146 разделение, 884 состояния, 432 сообщение, 406; 432 Строковые даты, 914 переменные, 869 Стоковый объект прототип, 874 текст, 146 Структура управления, 106 Структурированные данные, 924 Схема узлов, 261 Сценарий, 573 анализ, 58 бессерверный, 42 ветвление, 229 защищенный, 452 исходный код, 57 межбраузерный, 50; 58 отсроченный, 88 серверный, 38 скрытие, 86 создание, 52 Счетчик цикла, 952 т Таблица, 853 истинности оператора И, 984 оператора ИЛИ, 984 стилей, 172; 575; 582; 810 импортированная, 812 Текст возвращение, 590 замена, 345 обтекание, 604 отображение, 59 расположение, 345 Текстовая область, 709; 1090 Текстовое поле, 693 выделение, 704 значение, 701 подстановка в функцию, 701 Текстовый объект, 134; 692 редактор, 53 узел, 73; 583 Текущее время, 472 Тело страницы, 601 Тип браузера, 186 данных, 95; 556 преобразования, 861 события, 576; 763 узла, 217 Точечный синтаксис, 75; 197 Предметный указатель 1177
У Узел, 76; 216 документа, 77 дочерний, 76; 247; 261; 302 замена, 346 методы, 219 родительский, 77 свойства, 217 содержимое, 221 текстовый, 73; 583 типы, 217 Унарный оператор, 975 Универсальная функция, 1009 Универсальное имя ресурса, 356 Универсальный идентификатор ресурса, 323 Управление строками, 147 табличными данными, 254 Управляющая структура, 106; 194; 945 Управляющее выделение, 364 Условие, 950; 951 Условное выражение, 950 Условный оператор, 106 Учет временной зоны, 914 ф Файл MagicCookie, 547 сведения, 559; 631 Фильтр, 210; 261; 374; 856 название, 863 преобразования, 859 статический, 858 Флажок, 677 состояние, 678 Фон, 846 параметры, 603 страницы, 603 цвет, 730 Форма, 132; 560; 650; 921 добавление, 72 изменение атрибутов, 657 отправка, 142; 666; 673 перезагрузка, 665 пример, 561 Формат даты, 915 Форматирование текста, 892 чисел, 896 Фрейм, 66; 393; 562 дочерний,156 1178 загрузка, 396 исходный код, 398 оглавления, 501 отключение, 396 отображение/скрытие, 500 прокрутка, 496 пустой, 397 синхронизация, 397 создание, 393 Функция, 88; 109; 996; 997 decodeURI(), 1025 decodeURIComponentO, 1025 encodeURIO, 1025 encodeURIComponent(), 1025 escape(), 1026 eval(), 1027 isFiniteO, 1028 isNaN(), 1028 NumberO, 1028 parseFloatO, 1028 parselnt(), 1028 toStringO, 1029 unescapeO, 1026 unwatch(), 1032 watch(), 1032 анонимная, 997 аргументы, ПО вложенная, 998 вызов, 110; 1004 глобальная, 1024 параметры, 109; 999 передача параметров, 468 передача форм и элементов, 653 преобразования чисел, 898 просмотра свойств, 957 создание, 997 строковая, 891 универсальная, 1009 Функция-конструктор, 925 Ц Цвет, 830 системный, 831 ссылки, 540; 602 фона, 730 Целевой объект, 744 Целое число, 101; 895 Цикл, 105; 108; 951 do-while, 956 for, 951 while, 955 Предметный указатель
выход, 954 продолжение, 954 Циклический поиск, 929 ч Число, 895 извлечение, 898 с плавающей точкой, 101; 895 случайное, 902 форматирование, 896 целое, 895 ш Шестнадцатеричные числа, 897 Шрифт динамическое изменение, 1043 Щ Щелчок, 310; 675 э Эквиваленты условных значений, 947 Экземпляр, 197 Элемент а, 613 anchor, 613 area, 643 blockquote свойство cite, 1040 body, 600 br, 1041 свойство clear, 1041 button, 671 fieldset, 668 font, 1042 свойство color, 1042 свойство face, 1044 свойство size, 1044 form, 136 frame, 398; 490; 503 frameset, 497 hr, 1046 свойство align, 1046 свойство color, 1048 свойство noShade, 1048 свойство size, 1049 свойство width, 1049 iframe, 159 img, 622 input, 136; 659 label, 669; 1050 свойство accessKey, 1050 свойство form, 1050 свойство htmlFor, 1050 legend, 668 link, 613 map, 646 marquee, 1051 метод start(), 1055 метод stop(), 1055 обработчик события onbounce, 1055 обработчик события onfinish, 1056 обработчик события onstart, 1056 свойство behavior, 1051 свойство bgColor, 1053 свойство direction, 1053 свойство height, 1054 свойство hspace, 1054 свойство loop, 1054 свойство scroll Amount, 1054 свойство scrollDelay, 1054 свойство trueSpeed, 1055 свойство vspace, 1054 свойство width, 1054 object, 254 optgroup, 733 option, 731 select, 139; 713 selection, 1078 style, 814 вставка, 329 выбор, 585 изменение цвета, 541 расположение при вставке, 329 содержимое, 208 создание, 74; 580 статический, 846 Элемент управления, 132; 306; 408; 651 я Язык базовый, 46 разметки документов, 38 программирования, 94 Предметный указатель 1179