HTML, Excel, Word, SEOОсновы JavaScript ⇒ Окна и фреймы

ОСНОВЫ JavaScript

Учебник JavaScript
·Знакомство с JS. Переменные, операторы, операции
·Функции
·Модель HTML документа
·Иерархия документов в бразуере
·Формы
·Окна и фреймы
·Ссылки, заголовок, статус
·События
·События клавиатуры и мыши
·События. Таймер
·Стили. Управление стилями
·Слои и блоки. Управление видимостью
·Объекты JS
·Внешние объекты
·Внутренние объекты
·Массивы
·Регулярные выражения
·Математика в JS
·Пример простого калькулятора
·Дата и время
·Cookies и хранение состояния
·Немного об AJAX
·Работа с WebMoney

 

Окна и фреймы



Создание нового окна и доступ к нему

Фрейм как отдельное окно

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

Я ни в коей мере не буду рекомендовать вам использовать фреймы и всплывающие (и просто множественные) окна в своих приложениях. Но сведения о них могут пригодиться при разборе чужих скриптов и создании своих.  

Создание нового окна и доступ к нему

Для создания нового дочернего окна объект window, сам представляющий окно, содержит всего одну функцию – open(). Несмотря на кажущуюся простоту, эта функция позволяет определять целую группу параметров и свойств свежесозданного окна.

При простейшем вызове – то есть, вызове window.open() произойдет то же самое, что и при нажатии Control-N или Control-T в браузере (ну, с тем исключением, что браузер начнет возмущаться по поводу всплывающих окон – нужно будет его успокоить и сказать что все в порядке). То есть – откроется новое окно или вкладка браузера, которая будет иметь размеры по умолчанию, и содержать about:blank

Для того, чтобы загрузить в окно данные, есть несколько (думаю, вы уже привыкли) способов. 

Первый – это указать при открытии окна URL, который будет загружен в это окно. Делается это при помощи указания первого параметра – строки с нужным URL. Тогда после открытия этот URL будет запрошен браузером, как если бы вы вбили его в строку адреса и нажали Enter. 

Второй способ несколько сложнее, и основан на связи основного окна с дочерним. 

Для того чтобы им воспользоваться нужно результат функции open() занести в переменную.

Теперь эта переменная представляет новое окно – то есть, для работы с документом нового окна теми способами, которые вам удобнее (и которые вы изучали до этого) достаточно использовать свойство document этой переменной. К сожалению, второй способ сопряжен с массой неудобств. Основное неудобство состоит в том, что функция open() выполняется асинхронно. То есть никто не может гарантировать, что после ее вызова у созданного окна будет document – он может появиться через секунду, например. Обращение же к несозданным объектам (даже хуже – к наполовину созданным) может вызвать некоторые проблемы. В моем случае это было зависание браузера FireFox, и просто ошибка в браузере Internet Explorer

Поэтому чаще всего используется смешанная техника – сначала загружается уже готовый HTML-код, а после этого осуществляется доступ к нему при помощи результата работы функции open().

Связь окон не ограничивается доступом к дочернему окну из основного. Возможен также и обратный доступ – к главному из дочернего. Этот способ доступа используется даже чаще – дочернее окно отправляет данные главному. 

Функция open() имеет следующие параметры:

  1. URL. Этот параметр уже упоминался, он служит указанием, какой документ загружать. 

  2. Название окна или значение атрибуте target. По неизвестной мне причине, этот параметр позволяет как указать, в каком target открывать окно, так и указать имя нового окна. Если первое использование вам должно быть знакомо еще по языку HTML (то есть в данном случае оно работает как тот же target у ссылки), то случай, когда этот параметр обозначает имя окна нужно пояснить. Дело в том, что каждое окно браузера может иметь имя, причем это имя не связано с title окна или другими параметрами. Если окно с указанным именем уже существует, то оно не будет заново открыто. 

  3. Третий параметр представляет из себя список «спецификаций» окна, разделенных запятыми (например, 'width=200,height=100'). Настроек у окна довольно много, хотя не все они реализованы во всех браузерах. Наиболее общие из них – это height, width, left, top (эти параметры управляют размерами окна и положением относительно верхнего левого угла экрана), а также location, menubar и toolbar (эти параметры определяют, показывать ли элементы оформления браузера, такие как панель адреса или меню).  

Для того чтобы продемонстрировать техники работы с дочерними окнами, я предлагаю следующую задачу (предлагаю, естественно, себе, так как я же и буду ее решать): 

HTML-код содержит кнопку синхронизации форм; при открытии программно открываются два окна (с одним и тем же кодом); при нажатии на кнопку синхронизации данные формы переносятся в соседнее окно. 

Создавать большую форму я не буду – вы ведь и так уже умеете работать с формами. Вместо этого форма будет содержать простое текстовое поле. 

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

Итак, для начала, HTML-код. Я буду использовать уже знакомый вам атрибут onClick для вызова функции синхронизации по нажатию кнопки.

<html> 
        <head>
                <script type="text/javascript" src="sync.js"></script>
        </head>
        <body>
                <textarea id="sync_value"></textarea>
                <input type="button" id='btn' value="Sync" onClick="sync_func();" disabled='disabled' />
        </body>
</html> 

Как вы видите, код тривиальный, и в пояснениях не нуждается. 

Основную работу берет на себя включаемый скрипт. 

Структура скрипта будет уже не такой тривиальной. Как и раньше, разобъем задачу на несколько подзадач. 

В нашем скрипте должны быть следующие возможности: 

Естественно, поведение кода будет зависеть от того, главное это окно или дочернее. 

Для проверки «подчиненности» окна будет использоваться одно из свойств объекта windowopener. Это свойство содержит ссылку на объект открывшего окна, если такое имеется, или null, если окно было открыто пользователем, а не скриптом.

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

Для стартовых проверок и установок можно использовать такой код: 

var is_child = false; 
var child_window; 
function init() { 
        is_child = (window.opener != null);
        if (is_child) {
                window.opener.ready();
                ready();
        } else {
                child_window = window.open('test.html', 'child');
        }
} 
 
function ready() { 
        document.getElementById('btn').disabled=false;
} 

Для того чтобы код отработал, нужно вызвать функцию init(), причем сразу после того как будут загружены все остальные элементы. Например, можно разместить в самом конце тела документа (перед закрывающим тегом body) вызов этой функции, вставив строчку

<script type="text/javascript"> init(); </script> 

Если сейчас открыть полученный документ (да, к слову – он должен называться test.html) – то вы увидите два окна, в которых кнопки после загрузки документов станут активными.

Некоторые из строчек я поясню. 

Каждое окно связано со своим объектом window. Соответственно, наборы глобальных переменных в каждом окне (так как глобальные переменные – это просто свойства объекта window) будут разными. Поэтому установка переменной is_child равной true в одном окне совершенно не значит, что в другом окне она тоже будет true.

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

Так что при объявлении функций, создании переменных и объявлении классов не нужно бояться «зацепить» другое окно – это можно сделать только специально. 

Как вы видите, сначала переменная is_child равна false – то есть окно считается самостоятельным. Функция init() проверяет, является ли окно дочерним – вот этой строчкой:

is_child = (window.opener != null); 

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

Далее, если окно оказалось основным – выполняется открытие нового окна, и присвоение этого окна переменной child_window. Если присвоение не делать, то новое окно будет недоступно.

В случае же, если окно дочернее, выполняются действия поинтереснее. 

Конструкция  

window.opener.ready(); 

вызывает функцию ready() для окна-родителя. Эта функция будет работать с глобальными переменными базового окна, то есть все действия будут выполняться в контексте того окна, которое открыло текущее.

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

В функции ready() ничего особенного нет – она просто подготавливает код к работе (и вызывается только тогда, когда оба окна открыты и все объекты в них созданы). Другими словами, она убирает атрибут disabled у кнопок (точнее, отключает путем присвоения этому атрибуту логического нуля).

Сложная часть работы выполнена, остались мелочи – синхронизация. 

Здесь мы будем использовать уже полученную переменную is_child, и, в зависимости от ее значения, или изменять содержимое элементов window.opener, или элементов child_window

Вот так примерно выглядит функция синхронизации:  

function sync_function() { 
        var value;
        value = document.getElementById('sync_value').value;
        if (is_child) {
                window.opener.document.getElementById('sync_value').value = value;
        } else {
                child_window.document.getElementById('sync_value').value = value;
        }
} 

Тут тоже все тривиально – сначала значение берется из текстового поля текущего окна, а потом записывается в текстовое поле другого окна. 

Текстовое поле ищется по ID – так как у нас нет формы, то получить доступ через массив forms не выйдет.

Можете проверить работу этого скрипта, открыв два окна так чтобы они не перекрывали друг друга. 

Вы можете заметить забавную вещь – если в дочернем окне открыть другую страницу (например, яндекс), а потом опять test.html, то скрипт продолжит работу. А если в то время, пока яндекс будет открыт, попробовать синхронизировать окна, то браузер выдаст сообщение об ошибке – но не невозможность найти элемент, а ошибку доступа. Это сделано для того, чтобы скрипты из разных доменов не могли друг на друга повлиять и сделать что-либо не очень хорошее. 

Фрейм как отдельное окно

Сейчас фреймы переживают свой упадок (то есть их почти никто не использует). Если вы все же хотите использовать их на своих страницах, то некоторые сведения о работе с фреймами из скрипта могут помочь. 

Фреймы, по сути, представляют собой вложенные окна внутри одного большого окна браузера. Для каждого фрейма создается отдельный объект window, и все фреймы доступны из главного окна в виде массива frames. При этом обращаться к фрейму можно как по индексу (в порядке объявления фреймов внутри фреймсета), так и по имени фрейма.

Например, в таком вот документе  

<html> 
        <head>
        </head>
        <frameset cols="100,*">
                        <frame name="left" src="left.html">
                        <frame name="right" src="right.html">
        </frameset>
</html> 

нулевой (он же левый) фрейм доступен как window.frames[0], и как window.frames.left

Объекты window, которые находятся внутри фреймов, также имеют связь с главным окном. 

Для того, чтобы получить обрамляющее окно, используется window.parent.  Для обращения к главному окну (или окну верхнего уровня) используется window.top

В случае, если окно находится «снаружи» всех остальных (то есть является окном верхнего уровня) свойства parent и top указывают на это же окно. 

Описанные свойства можно проиллюстрировать скриптом, который определяет степень вложенности окна внутри фреймов. 

var deep = 0; 
var current = window.self; 
while (current != window.top) { 
        deep++;
        current = window.parent;
} 
if (deep == 0) { 
        alert ("Окно верхнего уровня");
} else { 
        alert ("Окно находится на "+ deep +" уровне вложенности");
} 

Здесь используется еще одно свойство window – window.self. Обычно для сравнения ссылок на окно используется именно это свойство (хотя использование просто window дает тот же результат).

При работе с iframe ничего существенно не меняется – фреймы также доступны через массив frames.

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

Нужно на основе этой задачи сделать такую же синхронизацию, но – внутри двух фреймов. Проверку на дочернее окно в этом случае, соответственно, делать не нужно (но нужно проверять, левым или правым является фрейм). 



В начало страницы



В начало страницы