241 lines
17 KiB
Markdown
241 lines
17 KiB
Markdown
# Открытие окон и методы window
|
||
|
||
Всплывающее окно ("попап" -- от англ. Popup window) -- один из старейших способов показать пользователю ещё один документ.
|
||
|
||
В этой статье мы рассмотрим открытие окон и ряд тонких моментов, которые с этим связаны.
|
||
|
||
[cut]
|
||
|
||
Простейший пример:
|
||
|
||
```js
|
||
//+ run
|
||
window.open("http://ya.ru");
|
||
```
|
||
|
||
...При запуске откроется новое окно с указанным URL.
|
||
|
||
Большинство браузеров по умолчанию создают новую вкладку вместо отдельного окна, но чуть далее мы увидим, что можно и "заказать" именно окно.
|
||
|
||
## Блокировщик всплывающих окон
|
||
|
||
Рекламные попапы очень надоели посетителям, аж со времён 20го века, поэтому современные браузеры всплывающие окна обычно блокируют. При этом пользователь, конечно, может изменить настройки блокирования для конкретного сайта.
|
||
|
||
**Всплывающее окно блокируется в том случае, если вызов `window.open` произошёл не в результате действия посетителя.**
|
||
|
||
Как же браузер понимает -- посетитель вызвал открытие окна или нет?
|
||
|
||
Для этого при работе скрипта он хранит внутренний "флаг", который говорит -- инициировал посетитель выполнение или нет. Например, при клике на кнопку весь код, который выполнится в результате, включая вложенные вызовы, будет иметь флаг "инициировано посетителем" и попапы при этом разрешены.
|
||
|
||
А если код был на странице и выполнился автоматически при её загрузке -- у него этого флага не будет. Попапы будут заблокированы.
|
||
|
||
|
||
## Полный синтаксис window.open
|
||
|
||
Полный синтаксис:
|
||
|
||
```js
|
||
win = window.open(url, name, params)
|
||
```
|
||
|
||
Функция возвращает ссылку но объект `window` нового окна, либо `null`, если окно было заблокировано браузером.
|
||
|
||
Параметры:
|
||
|
||
<dl>
|
||
<dt>`url`</dt>
|
||
<dd>URL для загрузки в новое окно.</dd>
|
||
<dt>`name`</dt>
|
||
<dd>Имя нового окна. Может быть использовано в параметре `target` в формах. Если позднее вызвать `window.open()` с тем же именем, то браузеры (кроме IE) заменяют существующее окно на новое.</dd>
|
||
<dt>`params`</dt>
|
||
<dd>Строка с конфигурацией для нового окна. Состоит из параметров, перечисленных через запятую. Пробелов в ней быть не должно.</dd>
|
||
</dl>
|
||
|
||
Значения параметров `params`.
|
||
|
||
<ol>
|
||
<li>Настройки расположения окна:
|
||
|
||
<dl>
|
||
<dt>`left/top` (число)</dt>
|
||
<dd>Координаты верхнего левого угла относительно экрана. Ограничение: новое окно не может быть позиционированно за пределами экрана.</dd>
|
||
<dt>`width/height` (число)</dt>
|
||
<dd>Ширина/высота нового окна. Минимальные значения ограничены, так что невозможно создать невидимое окно с нулевыми размерами.</dd>
|
||
</dl>
|
||
|
||
Если координаты и размеры не указаны, то обычно браузер открывает не окно, а новую вкладку.
|
||
|
||
</li>
|
||
<li>Свойства окна:
|
||
<dl>
|
||
<dt>`menubar` (yes/no)</dt>
|
||
<dd>Скрыть или показать строку меню браузера.</dd>
|
||
<dt>`toolbar` (yes/no)</dt>
|
||
<dd>Показать или скрыть панель навигации браузера (кнопки назад, вперед, обновить страницу и остальные) в новом окне.</dd>
|
||
<dt>`location` (yes/no)</dt>
|
||
<dd>Показать/скрыть поле URL-адреса в новом окне. По умолчанию Firefox и IE не позволяют скрывать строку адреса.</dd>
|
||
<dt>`status` (yes/no)</dt>
|
||
<dd>Показать или скрыть строку состояния. С другой стороны, браузер может в принудительном порядке показать строку состояния.</dd>
|
||
<dt>`resizable` (yes/no)</dt>
|
||
<dd>Позволяет отключить возможность изменять размеры нового окна. Значение `no` обычно неудобно посетителям.</dd>
|
||
<dt>`scrollbars` (yes/no)</dt>
|
||
<dd>Разрешает убрать полосы прокрутки для нового окна. Значение `no` обычно неудобно посетителям.</dd>
|
||
</dl>
|
||
</li>
|
||
<li>Еще есть небольшое количество не кросс-браузерных свойств, которые обычно не используются. Вы можете узнать о них в документации, например MDN: [window.open](https://developer.mozilla.org/en/DOM/window.open).</li>
|
||
</ol>
|
||
|
||
[warn]
|
||
Браузер подходит к этим параметрам интеллектуально. Он может проигнорировать их часть или даже все, они скорее являются "пожеланиями", нежели "требованиями".
|
||
[/warn]
|
||
|
||
Важные моменты:
|
||
|
||
<ul>
|
||
<li>Если при вызове `open` указан только первый параметр, параметр отсутствует, то используются параметры по умолчанию. Обычно при этом будет открыто не окно, а вкладка, что зачастую более удобно.</li>
|
||
<li>Если указана строка с параметрами, но некоторые `yes/no` параметры отсутствуют, то браузер выставляет их в `no`. Поэтому убедитесь, что все нужные вам параметры выставлены в `yes`.</li>
|
||
<li>Когда не указан `top/left`, то браузер откроет окно с небольшим смещением относительно левого верхнего угла последнего открытого окна.</li>
|
||
<li>Если не указаны `width/height`, новое окно будет такого же размера, как последнее открытое.</li>
|
||
</ul>
|
||
|
||
## Доступ к новому окну
|
||
|
||
Вызов `window.open` возвращает ссылку на новое окно. Она может быть использована для манипуляции свойствами окна, изменения URL, доступа к его переменным и т.п.
|
||
|
||
В примере ниже мы заполняем новое окно содержимым целиком из JavaScript:
|
||
|
||
```js
|
||
//+ run
|
||
var newWin = window.open("about:blank", "hello", "width=200,height=200");
|
||
|
||
newWin.document.write("Привет, мир!");
|
||
```
|
||
|
||
А здесь модифицируем содержимое после загрузки:
|
||
|
||
```js
|
||
//+ run
|
||
var newWin = window.open('/', 'example', 'width=600,height=400');
|
||
|
||
alert(newWin.location.href); // (*) about:blank, загрузка ещё не началась
|
||
|
||
newWin.onload = function() {
|
||
|
||
// создать div в документе нового окна
|
||
var div = *!*newWin*/!*.document.createElement('div');
|
||
div.innerHTML = 'Добро пожаловать!'
|
||
div.style.fontSize = '30px'
|
||
|
||
// вставить первым элементом в body нового окна
|
||
body.insertBefore(div, newWin.document.body.firstChild);
|
||
}
|
||
```
|
||
|
||
Обратим внимание: сразу после `window.open` новое окно ещё не загружено. Это демонстрирует `alert` в строке `(*)`. Поэтому в примере выше окно модифицируется при `onload`. Можно было и поставить обработчик на `DOMContentLoaded` для `newWin.document`.
|
||
|
||
**Связь между окнами -- двухсторонняя.**
|
||
|
||
Родительское окно получает ссылку на новое через `window.open`, а дочернее -- ссылку на родителя `window.opener`.
|
||
|
||
Оно тоже может его модифицировать.
|
||
|
||
Если запустить пример ниже, то новое окно заменит содержимое текущего на `'Test'`:
|
||
|
||
```js
|
||
//+ run
|
||
var newWin = window.open("about:blank", "hello", "width=200,height=200");
|
||
|
||
newWin.document.write(
|
||
"<script>*!*window.opener.document.body.innerHTML = 'Test'*/!*</script>"
|
||
);
|
||
```
|
||
|
||
|
||
[warn header="Same Origin Policy -- защита проверкой протокол-сайт-порт"]
|
||
Большинство действий, особенно получение содержимого окна и его переменных, возможны лишь в том случае, если URL нового окна происходит из того же источника (англ. - *"Same Origin"*), т.е. совпадают домен, протокол и порт.
|
||
|
||
Иначе говоря, если новое окно содержит документ с того же сайта.
|
||
|
||
Больше информации об этом будет позже, в главе [](/same-origin-policy).
|
||
[/warn]
|
||
|
||
|
||
## События
|
||
|
||
Наиболее важные события при работе с окном браузера:
|
||
|
||
<ul>
|
||
<li>`onresize` -- событие изменения размера окна.</li>
|
||
<li>`onscroll` -- событие при прокрутке окна.</li>
|
||
<li>`onload` -- полностью загрузилась страница со всеми ресурсами.</li>
|
||
<li>`onfocus/onblur` -- получение/потеря фокуса.</li>
|
||
</ul>
|
||
|
||
## Методы и свойства
|
||
|
||
<dl>
|
||
<dt>`window.closed`
|
||
<dd>Свойство `window.closed` равно `true`, если окно закрыто. Может быть использовано, чтобы проверить, закрыл ли посетитель попап.</dd>
|
||
<dt>`window.close()`</dt>
|
||
<dd>Закрывает попап без предупреждений и уведомлений. Вообще, метод `close()` можно вызвать для любого окна, в том числе, текущего. Но если окно открыто не с помощью `window.open()`, то браузер может проигнорировать вызов `close` или запросить подтверждение.
|
||
</dd>
|
||
</dl>
|
||
|
||
## Перемещение и изменение размеров окна
|
||
|
||
Существует несколько методов для перемещения/изменения размеров окна.
|
||
|
||
<dl>
|
||
<dt>`win.moveBy(x,y)`</dt>
|
||
<dd>Перемещает окно относительно текущего положения на `x` пикселей вправо и `y` пикселей вниз. Допускаются отрицательные значения.</dd>
|
||
<dt>`win.moveTo(x,y)`</dt>
|
||
<dd>Передвигает окно в заданную координатами `x` и `y` точку экрана монитора.</dd>
|
||
<dt>`win.resizeBy(width,height)`</dt>
|
||
<dd>Изменяет размер окна на заданную величину `width/height` (ширина/высота). Допускаются отрицательные значения.</dd>
|
||
<dt>`win.resizeTo(width,height)`</dt>
|
||
<dd>Изменяет размер окна на заданное значение.</dd>
|
||
</dl>
|
||
|
||
[warn]
|
||
Чтобы предотвратить использование этих методов с плохими целями, браузеры часто блокируют их выполнение. Как правило, они работают, если окно `win` открыто вызовом [window.open](https://developer.mozilla.org/en-US/docs/Web/API/window.open) из JavaScript текущей страницы и в нём нет дополнительных вкладок.
|
||
[/warn]
|
||
|
||
[warn header="Ни свернуть ни развернуть"]
|
||
Заметим, что JavaScript не может ни свернуть ни развернуть ни "максимизировать" (Windows) окно.
|
||
|
||
Эти функции операционной системы от Frontend-разработчиков скрыты. Вызовы, описанные выше, в случае свёрнутого или максимизированного окна не работают.
|
||
[/warn]
|
||
|
||
## Прокрутка окна
|
||
|
||
Прокрутка окна требуется, пожалуй, чаще всего. Мы уже говорили о ней в главе [](/metrics-window):
|
||
|
||
<dl>
|
||
<dt>`win.scrollBy(x,y)`</dt>
|
||
<dd>
|
||
Прокрутка окна на заданное число пикселей вперед или назад. Допускаются отрицательные значения.</dd>
|
||
<dt>`win.scrollTo(x,y)`</dt>
|
||
<dd>Прокручивает окно к заданным координатам.</dd>
|
||
<dt>`elem.scrollIntoView(top)`</dt>
|
||
<dd>Этот метод прокрутки вызывается на элементе. При этом окно прокручивается так, чтобы элемент был полностью видим. Если параметр `top` равен `true` или не задан, то верх элемента совпадает с верхом окна. Если он равен `false`, то окно прокручивается так, чтобы нижний край элемента совпал с нижним краем окна.
|
||
</dd>
|
||
</dl>
|
||
|
||
|
||
## Итого
|
||
|
||
<ul>
|
||
<li>Всплывающее окно открывается с помощью вызова `window.open(url, name, params)`.</li>
|
||
<li>Метод `window.open` возвращает ссылку на новое окно или `null`, если окно было заблокировано.</li>
|
||
<li>Современные браузеры блокируют окна, если `window.open` вызвано не в результате действия посетителя.</li>
|
||
<li>Обычно открывается вкладка, но если заданы размеры и позиция -- то именно окно.</li>
|
||
<li>Новое окно имеет ссылку на родительское в `window.opener`.</li>
|
||
<li>Окна могут общаться между собой как угодно, если они из одного источника. Иначе действуют жёсткие ограничения безопасности.</li>
|
||
</ul>
|
||
|
||
Всплывающие окна используются нечасто. Ведь загрузить новую информацию можно динамически, с помощью технологии AJAX, а показать -- в элементе `<div>`, расположенным над страницей (`z-index`). Ещё одна альтернатива -- тег `<iframe>`.
|
||
|
||
Но в некоторых случаях всплывающие окна бывают очень даже полезны. Например, отдельное окно сервиса онлайн-консультаций. Посетитель может ходить по сайту в основном окне, а общаться в чате -- во вспомогательном.
|
||
|
||
Если вы хотите использовать всплывающее окно, предупредите посетителя об этом, так же и при использовании `target="_blank"` в ссылках или формах. Иконка открывающегося окошка на ссылке поможет посетителю понять, что происходит и не потерять оба окна из поля зрения.
|
||
|