W3docs

Всплывающие окна JavaScript и window.open()

Как открывать, управлять и закрывать окна браузера в JavaScript с помощью window.open(), window.close(), событий focus/blur и postMessage — плюс современные ограничения безопасности и лучшие практики.

Среди возможностей JavaScript открытие и управление отдельными окнами браузера позволяет строить потоки входа, OAuth-рукопожатия, предпросмотр для печати и насыщенные уведомительные интерфейсы. В этой главе рассматривается всё необходимое: открытие окна через window.open(), настройка его размеров и положения, обмен сообщениями с ним, реакция на события фокуса и выгрузки, а также корректное закрытие — вместе с современными ограничениями безопасности, которые определяют поведение браузеров во всех этих сценариях.

Для более простых однострочных диалогов (alert, prompt и confirm) см. JavaScript alert, prompt и confirm. Эта страница посвящена полноценным окнам браузера.

Понимание всплывающих окон JavaScript

Всплывающее окно — это отдельное окно верхнего уровня, открытое вашим сценарием. В отличие от модального alert(), оно имеет собственный документ, собственный URL и остаётся открытым до тех пор, пока пользователь (или ваш код) его не закроет. Всплывающие окна удобны для контента, который должен находиться за пределами текущей страницы: экран входа у провайдера OAuth, платёжный виджет или печатный отчёт. Единственной точкой входа для всего этого является метод window.open().

Как работает window.open()

window.open() принимает три аргумента и возвращает ссылку на новое окно (или null, если браузер его заблокировал):

let win = window.open(url, name, features);
АргументЗначение
urlСтраница для загрузки. Передайте пустую строку "", чтобы открыть пустое окно и заполнить его содержимым через сценарий.
nameИмя цели. Повторное использование того же имени приводит к повторному использованию того же окна, а не к открытию нового. Специальные значения, такие как _blank, всегда открывают новое окно.
featuresСтрока параметров, разделённых запятыми, например width=400,height=300,left=100,top=100. Опустите её, чтобы использовать значения по умолчанию.

warning Браузеры позволяют window.open() сработать только тогда, когда вызов происходит непосредственно внутри пользовательского жеста, такого как клик. Вызов на загрузке страницы или в setTimeout считается нежелательным всплывающим окном и блокируется — win возвращает null. Всегда вызывайте всплывающие окна из реального обработчика событий и проверяйте возвращаемое значение.

Создание базового всплывающего окна

Чтобы создать простое всплывающее окно, вызовите window.open() из обработчика клика. Метод открывает новое окно браузера и возвращает ссылку на него, которую можно использовать для дальнейшего управления окном.

<p>Click the button to trigger the popup!</p>
<button onclick="openPopup()">Open Popup</button>

<script>

// Function to open a new popup with a message
function openPopup() {
    let newWindow = window.open("", "Example", "width=400,height=400");
    // Use innerHTML for safer dynamic content injection
    newWindow.document.body.innerHTML = "<h1>Welcome to our popup!</h1>";
}
</script>

warning Примечание: document.write может перезаписать весь документ при вызове после загрузки страницы. Современная практика предпочитает innerHTML или методы манипуляций с DOM для более безопасного динамического внедрения контента.

Этот фрагмент кода создаёт кнопку на веб-странице. При нажатии открывается новое всплывающее окно размером 400×400 пикселей с приветственным сообщением.

Управление содержимым и поведением всплывающего окна

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

<p>Click the button to trigger the popup!</p>
<button onclick="openInteractivePopup()">Learn More</button>

<script>
// Function to open a popup and control its content and behavior
function openInteractivePopup() {
    // Open a new window with specific dimensions
    let popup = window.open("", "InteractivePopupExample", "width=400,height=400");
    // Use innerHTML to inject content safely
    popup.document.body.innerHTML = `
        <h1>Interactive Popup</h1>
        <p>Click the button to change this message.</p>
        <button onclick='document.body.innerHTML = "<h1>Content Updated!</h1><p>Thanks for interacting.</p>";'>Update Content</button>
    `;
}
</script>

Для безопасного обмена данными между родительским окном и всплывающим используйте свойство window.opener для обращения к родителю и postMessage() для межсайтового или более безопасного обмена данными. Подробное рассмотрение этой темы см. в разделе Межоконное взаимодействие.

<!-- In parent window -->
<script>
let popup = window.open("popup.html", "Popup", "width=400,height=400");
popup.postMessage("Hello from parent!", "*");
</script>

<!-- In popup window -->
<script>
window.addEventListener("message", (event) => {
    console.log("Received:", event.data);
    // Respond back if needed
    window.opener.postMessage("Hello back!", event.origin);
});
</script>

Ключевые аспекты:

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

Расширенные методы и события окна

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

Изменение размера и перемещение элементов

JavaScript позволяет динамически изменять размер и положение элементов страницы, что особенно полезно при создании адаптивных и удобных веб-приложений. (Примечание: window.resizeTo() и window.moveTo() существуют для устаревших или ограниченных сред тестирования, однако современные браузеры жёстко ограничивают их по соображениям безопасности. В этом примере поведение имитируется с помощью стилизованного div. Для перетаскиваемых или изменяемых элементов интерфейса часто предпочтительнее position: absolute, а не relative, чтобы обеспечить предсказуемые вычисления координат.)

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Simulate Window Adjustments</title>
    <style>
        #simulatedWindow {
            width: 300px;
            height: 300px;
            position: absolute;
            background-color: #f3f3f3;
            border: 2px solid #ccc;
            margin: 20px;
            padding: 10px;
            transition: all 0.5s ease; /* Smooth transition for size and position changes */
        }
    </style>
</head>
<body>
    <button onclick="adjustSimulatedWindow()">Adjust Window</button>
    <div id="simulatedWindow">This is a simulated window. Click the button to adjust its size and position.</div>

    <script>
        function adjustSimulatedWindow() {
            const elem = document.getElementById('simulatedWindow');
            // Toggle size and position to demonstrate the effect
            if (elem.style.width === '500px') {
                elem.style.width = '300px';
                elem.style.height = '300px';
                elem.style.top = '0px';
                elem.style.left = '0px';
            } else {
                elem.style.width = '500px';
                elem.style.height = '500px';
                elem.style.top = '100px';
                elem.style.left = '100px';
            }
        }
    </script>
</body>
</html>

Ключевые аспекты:

  1. Структура HTML: Включает кнопку и элемент div, стилизованный под окно. div представляет окно, которое мы будем «изменять в размере» и «перемещать».
  2. CSS-стилизация: Определяет начальный размер и положение имитируемого окна с плавными переходами для визуального эффекта.
  3. Функция JavaScript: При нажатии кнопки функция adjustSimulatedWindow переключает размер и положение имитируемого окна. Изменение положения управляется путём изменения CSS-свойств top и left, имитируя перемещение окна по экрану.

Обработка событий окна

Обработка событий играет ключевую роль в создании интерактивных приложений. JavaScript предоставляет несколько событий, связанных с действиями окна, таких как onbeforeunload и onunload, которые можно использовать для выполнения кода в стратегически важные моменты.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>JavaScript Window Events Demo</title>
    <style>
        #message {
            padding: 20px;
            margin: 20px;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <p>Watch how the message updates based on window events. Initially, it changes upon loading. If you attempt to exit or click the mock exit link below, a prompt will appear asking if you want to leave the page. Cancelling the action will update the message.</p>
    <div id="message">Wait for it...</div>
    <!-- Mock link for simulating page leave -->
    <a href="#" onclick="simulatePageLeave(); return false;">Mock Page Leave</a>
    <script>
        window.onload = function() {
            document.getElementById('message').innerHTML = '<strong>Window loaded successfully!</strong>';
        };

        // Function to simulate page leave
        function simulatePageLeave() {
            // Show dialog asking if the user really wants to leave
            var confirmLeave = confirm('Are you sure you want to simulate leaving the page?');
            if (confirmLeave) {
                // If confirmed, update message as if leaving
                document.getElementById('message').innerHTML = '<strong>Leaving the page...</strong>';
            } else {
                // If cancelled, update message accordingly
                document.getElementById('message').innerHTML = '<strong>Decided to stay on the page!</strong>';
            }
        }

        window.onbeforeunload = function() {
            document.getElementById('message').innerHTML = '<strong>Preparing to leave the page...</strong>';
            return 'Are you sure you want to leave?';
        };
    </script>
</body>
</html>

Ключевые аспекты:

  1. Имитационная ссылка для симуляции ухода со страницы: Ссылка с href="#" и обработчиком onclick, вызывающим simulatePageLeave(); return false;, имитирует попытку покинуть страницу. return false; предотвращает действие ссылки по умолчанию, оставляя пользователя на текущей странице.
  2. Диалог подтверждения: Функция simulatePageLeave показывает диалог подтверждения, аналогичный тому, что появляется при реальной попытке выгрузки страницы. Пользователь может решить, хочет ли он «уйти» или нет.
  3. Обновление сообщений: В зависимости от выбора пользователя в диалоге подтверждения сообщение в div обновляется, отражая сделанный выбор и имитируя поведение при реальной попытке покинуть страницу.
  4. Примечание о поведении браузера: Современные браузеры игнорируют пользовательские строки, возвращаемые обработчиком onbeforeunload, и отображают только стандартный диалог подтверждения. Пример демонстрирует срабатывание события, однако точный текст подсказки контролируется браузером.
Информация

Изменение innerHTML элемента делает взаимодействие с пользователем более плавным и ненавязчивым. Такой подход отлично работает для интерактивных сайтов и образовательных инструментов.

Закрытие всплывающего окна

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

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Popup Example</title>
    <script>
        var myPopup = null; // Initialize the popup variable.

        // Function to open a popup
        function openPopup() {
            // Check if the popup already exists and is not closed
            if (myPopup === null || myPopup.closed) {
                myPopup = window.open("", "PopupWindow", "width=400,height=400");
                // Set the content of the popup using innerHTML
                myPopup.document.body.innerHTML = `
                    <html>
                    <head><title>Popup Content</title></head>
                    <body>
                        <h1>Welcome!</h1>
                        <p>This is your popup window.</p>
                        <button onclick="window.close()">Close Window</button>
                    </body>
                    </html>
                `;
                // Ensure the popup gets focus
                myPopup.focus();
            } else {
                // Bring the already opened popup to the front
                myPopup.focus();
            }
        }

        // Function to close the popup
        function closePopup() {
            if (myPopup && !myPopup.closed) {
                myPopup.close();
                myPopup = null; // Reset the popup variable after closing it.
            }
        }
    </script>
</head>
<body>
    <button onclick="openPopup()">Open Popup</button>
    <button onclick="closePopup()">Close Popup</button>
</body>
</html>

Ключевые аспекты:

  1. Управление состоянием: Переменная myPopup изначально равна null и проверяется на то, является ли она null или было ли окно закрыто (myPopup.closed). Это помогает решить, создавать ли новое всплывающее окно или переводить фокус на уже существующее.
  2. Дублирование содержимого: Благодаря правильной инициализации или закрытию всплывающего окна проблема дублирования содержимого исключается. Каждое открытие всплывающего окна начинается с чистого листа.
  3. Управление фокусом: Использование myPopup.focus() гарантирует, что если всплывающее окно уже открыто, оно переместится на передний план при повторном нажатии «Open Popup».
Информация

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

Фокус и потеря фокуса окна

События focus и blur можно использовать для обнаружения того, когда окно или страница получает или теряет фокус. Это может быть полезно для приостановки активности, когда пользователь переключается между вкладками или окнами.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Focus and Blur Events Demo</title>
    <style>
        body { transition: background-color 0.5s ease; } /* Smooth transition for background color */
    </style>
    <script>
        // Function to handle focus event
        function handleFocus() {
            document.getElementById('status').innerHTML = 'Window is focused';
            document.body.style.backgroundColor = '#DFF0D8'; // Light green background
        }

        // Function to handle blur event
        function handleBlur() {
            document.getElementById('status').innerHTML = 'Window is not focused';
            document.body.style.backgroundColor = '#F2DEDE'; // Light red background
        }

        window.addEventListener('focus', handleFocus);
        window.addEventListener('blur', handleBlur);
    </script>
</head>
<body>
    <h1>Focus and Blur Events on Window</h1>
    <p>Status: <span id="status">Window is focused</span></p>
    <p><strong>Instructions:</strong> To test this functionality, click inside this window to focus, then click away to another window or tab to trigger the blur effect. Notice the background color change and status update.</p>
</body>
</html>

Ключевые аспекты:

  • Обработчики событий: handleFocus() и handleBlur() обновляют содержимое страницы и цвет фона в зависимости от состояния фокуса окна.
  • Визуальная обратная связь: Изменения цвета фона дают мгновенную и наглядную визуальную обратную связь о состоянии фокуса, улучшая интерактивный опыт.

Безопасность и блокировщики всплывающих окон

Поскольку всплывающие окна исторически использовались в злоупотреблениях, современные браузеры применяют строгие правила. Знание этих правил экономит часы отладки вопроса «почему моё окно равно null?».

  • Требование жеста. Всплывающее окно открывается только в рамках синхронного действия пользователя (клик, нажатие клавиши, касание). После await или setTimeout жест считается «использованным» и вызов блокируется.
  • window.opener и noopener. При открытии окна новая страница может читать и даже перенаправлять открывателя через window.opener. Для ссылок на ненадёжные сайты это создаёт риск фишинга, поэтому добавьте rel="noopener" к якорям или передайте noopener в строке параметров:
// Anchor form — the new tab cannot touch this page
// <a href="https://example.com" target="_blank" rel="noopener noreferrer">Open</a>

// Scripted form — returns null because the link is severed
window.open("https://example.com", "_blank", "noopener");
  • Обнаружение заблокированного всплывающего окна. Всегда проверяйте возвращаемое значение, так как заблокированный вызов возвращает null:
const win = window.open("/report", "report", "width=600,height=800");
if (!win || win.closed || typeof win.closed === "undefined") {
  // Popup was blocked — fall back to navigating in the same tab
  location.href = "/report";
}

Лучшие практики использования всплывающих окон и методов window

  1. Согласие и контроль пользователя: Всегда следите за тем, чтобы всплывающие окна не нарушали пользовательский опыт. Предоставьте пользователям достаточный контроль для закрытия нежелательных всплывающих окон.
  2. Соображения безопасности: Учитывайте последствия безопасности внешнего содержимого во всплывающих окнах. Используйте надёжные источники и защищённые соединения для защиты данных пользователей.
  3. Оптимизация производительности: Используйте всплывающие окна и методы window экономно, так как они могут влиять на производительность вашего веб-приложения. Оптимизируйте их использование для баланса функциональности и эффективности ресурсов.

Заключение

Эффективное использование всплывающих окон JavaScript и методов window может значительно улучшить функциональность и пользовательский опыт веб-приложений. Следуя приведённым примерам и лучшим практикам, разработчики могут внедрять эти возможности эффективно и ответственно. Не забывайте ставить пользовательский опыт и безопасность на первое место во всех реализациях, чтобы сохранить целостность и эффективность ваших веб-приложений.

Связанные главы

Практика

Практика
Какие из следующих методов позволяют показывать всплывающие окна в JavaScript?
Какие из следующих методов позволяют показывать всплывающие окна в JavaScript?
Was this page helpful?