Создание окон в браузере

Обновлено: 07.07.2024

Метод open создает новое окно браузера , аналогично команде "Новое окно" в меню браузера. Обычно это не вкладка, а именно новое окно, но в некоторых браузерах можно настроить то или иное поведение явным образом.

Если параметр strUrl - пустая строка, то в окно будет загружен пустой ресурс about:blank.

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

Связь между окнами

Метод open возвращает ссылку на новое окно, которая служит для обращения к нему и вызову его методов, если это соответствует ограничениям безопасности Same Origin.

Если окно с именем winName уже существует, то вместо открытия нового окна, strUrl загружается в существующее, ссылка на которое возвращается. При этом строка параметров не применяется.

В случае, когда окно открыть не удалось, например, оно заблокировано штатными Popup-blocker'ами Firefox/IE - вызов open вернет null.
Проверяйте его, если не хотите лишних ошибок в своих скриптах.

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

Если вы хотите открывать новое окно при каждом вызове open() - используйте для winName специальное значение '_blank'.

Строка параметров

Необязательная строка параметров состоит из списка разделенных запятой настроек нового окна. После открытия окна их уже нельзя будет изменить.

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

Если строка параметров указана, то не перечисленные в ней параметры будут отключены(кроме titlebar/close). Поэтому включите в ней свойства, которые нужны.

Если в параметрах не указаны размеры, то новое окно будет по размеру такое же, как последнее открытое.

Если не указана позиция нового окна, то оно откроется со сдвигом в 20-30 пикселей (зависит от браузера) от последнего открытого окна.
Такой сдвиг позволяет посетителю заметить, что открылось новое окно.
Если текущее окно максимизировано, то сдвига не будет: новое тоже будет максимизировано.

Основные кроссбраузерные параметры

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

left/top Расстояние от левой/верхней границы окна операционной системы до границы нового окна. Новое окно не может быть создано за границами экрана height/width Высота/ширина в пикселях внутренности нового окна, включая полосы прокрутки, если они есть. Минимальное значение: 100 menubar Если этот параметр установлен в yes, то в новом окне будет меню. toolbar Если этот параметр установлен в yes, то в новом окне будет навигация (кнопки назад, вперед и т.п.) и панель вкладок location Если этот параметр установлен в yes, то в новом окне будет адресная строка directories Если этот параметр установлен в yes, то в новом окне будут закладки/избранное status Если этот параметр установлен в yes, то в новом окне будет строка состояния resizable Если этот параметр установлен в yes, то пользователь сможет изменить размеры нового окна. Рекомендуется всегда устанавливать этот параметр. scrollbars Если этот параметр установлен в yes, то новое окно при необходимости сможет показывать полосы прокрутки

Всплывающее окно («попап» – от англ. Popup window) – один из древнейших способов показать пользователю ещё один документ.

… и откроется новое окно с указанным URL. Большинство современных браузеров по умолчанию будут открывать новую вкладку вместо отдельного окна.

Попапы существуют с доисторических времён. Они были придуманы для отображения нового контента поверх открытого главного окна. Но с тех пор появились другие способы сделать это: JavaScript может загрузить содержимое вызовом fetch и показать его в тут же созданном <div> , так что попапы используются не каждый день.

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

Однако, для некоторых задач попапы ещё используются, например для OAuth-авторизации (вход через Google/Facebook/…), так как:

Блокировка попапов

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

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

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

Что, если попап должен открываться в результате onclick , но не сразу, а только после выполнения setTimeout ? Здесь все не так-то просто.

Попап откроется в Chrome, но будет заблокирован в Firefox.

Но если мы уменьшим тайм-аут до одной секунды, то попап откроется и в Firefox:

Мы получили два разных результата из-за того, что Firefox «допускает» таймаут в 2000 мс или менее, но все, что свыше этого – не вызывает его доверия, т.к. предполагается, что в таком случае открытие окна происходит без ведома пользователя. Именно поэтому попап из первого примера будет заблокирован, а из второго – нет.

Полный синтаксис window.open

Синтаксис открытия нового окна: window.open(url, name, params) :

url URL для загрузки в новом окне. name Имя нового окна. У каждого окна есть свойство window.name , в котором можно задавать, какое окно использовать для попапа. Таким образом, если уже существует окно с заданным именем – указанный в параметрах URL откроется в нем, в противном случае откроется новое окно. params Строка параметров для нового окна. Содержит настройки, разделённые запятыми. Важно помнить, что в данной строке не должно быть пробелов. Например width=200,height=100 .

Параметры в строке params :

  • Позиция окна:
    • left/top (числа) – координаты верхнего левого угла нового окна на экране. Существует ограничение: новое окно не может быть позиционировано вне видимой области экрана.
    • width/height (числа) – ширина и высота нового окна. Существуют ограничения на минимальную высоту и ширину, которые делают невозможным создание невидимого окна.
    • menubar (yes/no) – позволяет отобразить или скрыть меню браузера в новом окне.
    • toolbar (yes/no) – позволяет отобразить или скрыть панель навигации браузера (кнопки вперёд, назад, перезагрузки страницы) нового окна.
    • location (yes/no) – позволяет отобразить или скрыть адресную строку нового окна. Firefox и IE не позволяют скрывать эту панель по умолчанию.
    • status (yes/no) – позволяет отобразить или скрыть строку состояния. Как и с адресной строкой, большинство браузеров будут принудительно показывать её.
    • resizable (yes/no) – позволяет отключить возможность изменения размера нового окна. Не рекомендуется.
    • scrollbars (yes/no) – позволяет отключить полосы прокрутки для нового окна. Не рекомендуется.

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

    Пример: минималистичное окно

    Давайте откроем окно с минимальным набором настроек, просто чтобы посмотреть, какие из них браузер позволит отключить:

    В этом примере большинство настроек заблокированы и само окно находится за пределами видимой области экрана. Посмотрим, что получится в результате. Большинство браузеров «исправит» странные значения – как, например, нулевые width/height и отрицательные left/top . Например, Chrome установит высоту и ширину такого окна равной высоте и ширине экрана, так что попап будет занимать весь экран.

    Давайте исправим значения и зададим нормальные координаты ( left и top ) и значения размеров окна ( width и height ):

    Большинство браузеров выведет окно с заданными нами настройками.

    Правила для опущенных параметров:

    • Если третий аргумент при вызове open отсутствует или он пустой, будут использованы настройки окна по умолчанию.
    • Если строка параметров передана, но некоторые параметры yes/no пропущены, то считается, что указано no , так что соответствующие возможности будут отключены, если на это нет ограничений со стороны браузера. Поэтому при задании параметров убедитесь, что вы явно указали все необходимые yes.
    • Если координаты left/top не заданы, браузер попытается открыть новое окно рядом с предыдущим открытым окном.
    • Если не заданы размеры окна width/height , браузер откроет новое окно с теми же размерами, что и предыдущее открытое окно.

    Доступ к попапу из основного окна

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

    Например, здесь мы генерируем содержимое попапа из JavaScript:

    А здесь содержимое окна модифицируется после загрузки:

    Обратите внимание: сразу после window.open новое окно ещё не загружено. Это демонстрируется в строке (*) . Так что нужно ждать onload , чтобы его изменить. Или же поставить обработчик DOMContentLoaded на newWin.document .

    Окна имеют свободный доступ к содержимому друг друга только если они с одного источника (у них совпадают домен, протокол и порт (protocol://domain:port).

    Доступ к открывшему окну из попапа

    Попап также может обратиться к открывшему его окну по ссылке window.opener . Она равна null для всех окон, кроме попапов.

    Если вы запустите код ниже, то он заменит содержимое открывшего (текущего) окна на «Тест»:

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

    Закрытие попапа

    Чтобы закрыть окно: win.close()

    Для проверки, закрыто ли окно: win.closed .

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

    Если окно закрыто, то его свойство closed имеет значение true . Таким образом можно легко проверить, закрыт ли попап (или главное окно) или все ещё открыт. Пользователь может закрыть его в любой момент, и наш код должен учитывать эту возможность.

    Этот код откроет и затем закроет окно:

    Прокрутка и изменение размеров

    Методы для передвижения и изменения размеров окна:

    win.moveBy(x,y) Переместить окно относительно текущей позиции на x пикселей вправо и y пикселей вниз. Допустимы отрицательные значения (для перемещения окна влево и вверх). win.moveTo(x,y) Переместить окно на координаты экрана (x,y) . win.resizeBy(width,height) Изменить размер окна на указанные значения width/height относительно текущего размера. Допустимы отрицательные значения. win.resizeTo(width,height) Изменить размер окна до указанных значений.

    Также существует событие window.onresize .

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

    Методами JavaScript нельзя свернуть или развернуть («максимизировать») окно на весь экран. За это отвечают функции уровня операционной системы, и они скрыты от фронтенд-разработчиков.

    Методы перемещения и изменения размера окна не работают для свернутых и развёрнутых на весь экран окон.

    Прокрутка окна

    Мы уже говорили о прокрутке окна в главе Размеры и прокрутка окна.

    win.scrollBy(x,y) Прокрутить окно на x пикселей вправо и y пикселей вниз относительно текущей прокрутки. Допустимы отрицательные значения. win.scrollTo(x,y) Прокрутить окно до заданных координат (x,y) . elem.scrollIntoView(top = true) Прокрутить окно так, чтобы elem для elem.scrollIntoView(false) появился вверху (по умолчанию) или внизу.

    Также существует событие window.onscroll .

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

    Теоретически, установить попап в фокус можно с помощью метода window.focus() , а убрать из фокуса – с помощью window.blur() . Также существуют события focus/blur , которые позволяют отследить, когда фокус переводится на какое-то другое окно.

    Раньше на «плохих» сайтах эти методы могли становиться средством манипуляции. Например:

    Когда пользователь пытается перевести фокус на другое окно, этот код возвращает фокус назад. Таким образом, фокус как бы «блокируется» в попапе, который не нужен пользователю.

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

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

    Но все-таки иногда методы фокусировки бывают полезны. Например:

    • Когда мы открываем попап, может быть хорошей идеей запустить для него newWindow.focus() . Для некоторых комбинаций браузера и операционной системы это устранит неоднозначность – заметит ли пользователь это новое окно.
    • Если нужно отследить, когда посетитель использует веб-приложение, можно отслеживать window.onfocus/onblur . Это позволит ставить на паузу и продолжать выполнение анимаций и других интерактивных действий на странице. При этом важно помнить, что blur означает, что окно больше не в фокусе, но пользователь может по-прежнему видеть его.

    Итого

    Всплывающие окна используются нечасто. Ведь загрузить новую информацию можно динамически, а показать – в элементе <div> , расположенным над страницей ( z-index ). Ещё одна альтернатива – тег <iframe> .

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

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

    В итоге было задумано сделать собственное простое решение.


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

    • Arctic Modal,
    • jquery-modal,
    • iziModal,
    • Micromodal.js,
    • tingle.js,
    • Bootstrap Modal (из библиотеки Bootstrap) и др.

    (в статье не рассматриваем решения на базе Frontend-фреймворков)

    Несколькими из них я пользовался сам, но почти у всех находил какие-то недостатки. Некоторые из них требуют подключения библиотеки jQuery, которая есть не на всех проектах. Для разработки своего решения, нужно сначала определиться с требованиями.

    Что мы ждём от модальных окон? Отвечая на этот вопрос, я основывался на докладе «Знакомьтесь, модальное окно» Анны Селезнёвой, а так-же на относительно старой статье NikoX «arcticModal — jQuery-плагин для модальных окон».

    Итак, чтобы нам хотелось видеть?

    Дисклеймер: Прежде чем мы рассмотрим подробности, сразу дам ссылку на готовый код получившейся библиотеки (HystModal) на GitHub, а также ссылку на демо+документацию.

    Начнём с разметки.

    1. Разметка HTML и CSS

    1.1. Каркас модальных окон

    Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.

    Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):

    Сделаем так, чтобы .hystmodal растягивался на всё окно браузера и закрывал собой содержимое страницы. Чтобы этого добиться, установим фиксированное позиционирование в CSS и приравняем свойства top, bottom, left и right к нулю.

    В этом коде сделаны ещё две вещи:

    1. Так как мы хотим центрировать окно внутри страницы, превращаем .hystmodal в flex-контейнер с выравниваем его потомков по центру по вертикали и горизонтали.
    2. Окно может быть больше высоты экрана браузера, поэтому мы устанавливаем overflow-y: auto , чтобы при переполнении возникала полоса прокрутки. Также, для сенсорных экранов (в основном для Safari) нам стоит установить свойство -webkit-overflow-scrolling: touch , чтобы сенсорная прокрутка работала именно на этом блоке а не на странице.

    Теперь установим стили для самого окна.

    Кажется возникли сложности.

    Проблема №1. Если высота окна больше высоты окна браузера, то контент окна будет обрезан сверху.


    Это возникает из-за свойства justify-content: center . Оно позволяет нам удобно выровнять потомков по основной оси (по вертикали), но если потомок становится больше родителя то часть его становится недоступной даже при прокручиваемом контейнере. Подробнее можно посмотреть на stackoverflow. Решение – установить justify-content: flex-start , а потомку установить margin:auto . Это выровняет его по центру.

    Проблема №2. В ie-11 если высота окна больше высоты окна браузера, то фон окна обрезается.

    Решение: мы можем установить flex-shrink:0 потомку – тогда обрезки не происходит.

    Проблема №3. В браузерах кроме Chrome нет отступа от нижней границы окна (т.е. padding-bottom не сработал).

    Сложно сказать баг это браузеров или наоборот соответствует спецификации, но решения два:

    • установить псевдоэлемент ::after после потомка и дать ему высоту вместо padding
    • обернуть элемент в дополнительный блок и дать отступы уже ему.

    Воспользуемся вторым методом. Добавим обертку .hystmodal__wrap . Так мы заодно обойдём и проблему №1, а вместо padding у родителя установим margin-top и margin-top у самого .hystmodal__window .

    Наш итоговый html:

    В код также добавлены некоторые aria и role атрибуты для обеспечения доступности.

    Обновленный код CSS для обертки и окна.

    1.2 Скрываем окно

    Сейчас наше окно всегда видно. Когда говорят о скрытии элементов, первое что приходит на ум это переключать свойство display со значения none до нашего значения flex.

    Но этот подход нас не устроит, ведь свойство display не анимируется. Все переходы дочерних элементов, указанные в свойстве transition, работать не будут.

    Нам поможет другое свойство visibility:hidden . Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированное
    позиционирование – они будут полностью скрыты и не повлияют на остальную страницу. Кроме того, на элементы с visibility:hidden нельзя установить фокус с клавиатуры, а от скрин-ридеров мы уже скрыли окна с помощью атрибута aria-hidden="true" .

    Добавим также классы для открытого окна:

    1.3 Оформление подложки

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

    Просто разместим элемент .hystmodal__shadow прямо перед закрывающим </body> . В будущем, сделаем так, чтобы этот элемент создавался автоматически из js при инициализации библиотеки.

    1.4 Отключение прокрутки страницы

    Когда модальное окна открывается, мы хотим, чтобы страница под ним не прокручивалась.
    Самый простой способ этого добиться — повесить overflow:hidden для body или html, когда окно открывается. Однако с этим есть проблема:

    Проблема №4. В браузере Safari на iOS страница будет прокручиваться, даже если на тег html или body повешен overflow:hidden .
    Решается двумя способами, либо блокированием событий прокрутки (touchmove, touchend или touchsart) из js вида:

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

    ps: можно конечно применить библиотеку scroll-lock, в которую заложено это решение, но в статье было решено воспользоваться другим вариантом.

    Другое решение – основано частично на CSS. Пусть когда окно открывается, на элемент <html> будет добавляться класс .hystmodal__opened :

    Благодаря position:fixed , окно не будет прокручиваться даже в safari, однако здесь тоже не всё гладко:

    Проблема №5. При открытии/закрытии окна страница прокручивается в начало.
    Действительно, это происходит из-за изменения свойства position, текущая прокрутка окна сбрасывается.

    Для решения, нам нужно написать следующий JS (упрощенно):

    При открытии:

    При закрытии:

    Отлично, приступим к JavaScript коду.

    2. Код JavaScript

    2.2 Каркас библиотеки

    Нам нужна совместимость со старыми браузерами включая IE11 поэтому нам нужно выбрать из 2 вариантов кодинга:

    • Разрабатывать на старом стандарте ES5, и использовать только те фичи, которые поддерживают все браузеры.
    • Применить современный синтаксис ES6, но подключить транспайлер Babel, который автоматически преобразует код для всех браузеров и встроит необходимые полифилы.
      Было принято решение использовать второй вариант, с прицелом на будущее.
      Приступим.

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

    Итак, мы описали класс HystModal . Чтобы всё работало, нужно всего лишь подключить наш скрипт и создать экземпляр класса:

    Проблема №6: если в браузере есть фиксированный скроллбар (который влияет на ширину страницы), то при открытии/закрытии окна происходит сдвиг контента, когда полоса прокрутки то появляется то пропадает.

    Действительно – скроллбар пропадает и контент страницы перераспределяется. Чтобы решить эту проблему, можно добавить отступ справа к тегу html, равный ширине скроллбара когда он пропадает.

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

    Дополним метод _bodyScrollControl()

    Почему код метода close() упрощён? Дело в том, что просто убирая классы CSS у элементов, мы не можем анимировать закрытие окна.

    Проблема №7. При закрытии окна, свойство visibility:hidden применяется сразу и не даёт возможности анимировать закрытие окна.

    Причина этого известна: свойство visibility:hidden не анимируется. Конечно, можно обойтись без анимации, но, если она нужна, сделаем следующее.

    • Создадим дополнительный CSS-класс .hystmodal—moved почти такой-же как и .hystmodal--active
    • Затем при закрытии сначала добавим этот класс к окну и повесим обработчик события «transitionend» на модальном окне. Затем удалим класс `.hystmodal—active , таким образом вызывая css-переход. Как только переход завершится, сработает обработчик события «transitionend», в котором сделаем всё остальное и удалим сам обработчик события.

    Ниже: новая версия методов закрытия окна:

    Вы заметили, что мы создали ещё один метод _closeAfterTransition() и перенесли основную логику закрытия туда. Это нужно, чтобы удалить обработчик события transitionend после закрытия окна, ведь в метод removeEventListener необходимо передать именно ту функцию, которую мы привязывали.

    Кроме того, если анимация не будет нужна, можно просто вызвать this._closeAfterTransition() не вешая его на событие.

    Как мы помним, внутри addEventListener, this будет указывать на селектор где происходит событие, а не на наш экземпляр класса, поэтому в конструкторе нужно добавить ещё одну строчку для жёсткой привязки метода к this.

    2.2 Закрытие окна по клику на оверлей

    Нам нужно обработать ещё одно событие – закрытие окна по клику на элемент подложки .hystmodal__wrap . Мы можем повесить обработчик клика на документ для делегирования события как при открытии и проверить что событие произошло на .hystmodal__wrap примерно так:

    Это будет работать, но есть один малозаметный недостаток.

    Проблема №8. Если кнопку мыши нажать внутри окна, а отпустить за его пределами (над подложкой), окно закрывается.

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

    Окно закрывается потому что по спецификации, если нажатие и отпускание мыши были на разных элементах, то событие click сработает на самом ближайшем общем для них элементе, а у нас это как раз .hystmodal__wrap .

    Мы могли бы решить это изменением html, добавляя ещё один div сразу после .hystmodal__window и размещая его визуально под окном. Но нам бы не хотелось добавлять лишний пустой div ещё сильнее усложняя разметку.

    Мы можем разбить наш addEventListener на два отдельных обработчика: для событий mousedown и mouseup и будем проверять чтобы оба события происходили именно на .hystmodal__wrap . Добавим новые обработчики событий в наш метод eventsFeeler()

    2.3 Управление фокусом

    У нас заготовлено два метода для управления фокусом: focusContol() для переноса фокуса внутрь окна и обратно при его закрытии, а также focusCatcher(event) для блокирования ухода фокуса из окна.

    Решения для фокуса были реализованы аналогично js-библиотеке «Micromodal» (Indrashish Ghosh). А именно:

    1. В служебный массив сохраним все css селекторы на которых может быть установлен фокус (свойство помещаем в init()):

    2. В методе focusContol() находим первый такой селектор в окне и устанавливаем на него фокус, если окно открывается. Если же окно закрывается – то переводим фокус на this.starter :

    3. В методе focusCatcher() находим в окне и превращаем в массив коллекцию всех элементов на которых может быть фокус. И проверяем, если фокус должен был выйти на пределы окна, то вместо этого устанавливаем фокус снова на первый или последний элемент (ведь фокус можно переключать как по Tab так и по Shift+Tab в обратную сторону).

    Результирующий код метода focusCatcher:

    По сути мы реализовали все необходимое для успешного создания модальных окон, осталось ещё несколько дел:

    Проблема №9. В IE11 не работают методы Element.closest() и Object.assign() .

    Для поддержки Element.closest, воспользуемся полифилами для closest и matches от MDN.

    Можно их вставить просто так, но так как у нас проект всё равно собирается webpack, то удобно воспользоваться пакетом element-closest-polyfill который просто вставляет этот код.

    Для поддержки Object.assign , можно воспользоваться уже babel-плагином @babel/plugin-transform-object-assign

    3. Заключение и ссылки

    Повторяя начало статьи, всё изложенное выше, я оформил в маленькую библиотеку hystModal под MIT-лицензией. Вышло 3 кБ кода при загрузке с gzip. Ещё написал для неё подробную документацию на русском и английском языке.

    Что вошло ещё в библиотеку hystModal, чего не было в статье:

    • Настройки (вкл/выкл управление фокусом, варианты закрытия, ожидание анимации закрытия)
    • Коллбеки (функции вызывающиеся перед открытием окна и после его закрытия (в них передаётся объект модального окна))
    • Добавлен запрет на какие-либо действия пока анимация закрытия окна не завершится, а также ожидание анимации закрытия текущего окна перед открытием нового (если окно открывается из другого окна).
    • Оформление кнопки-крестика закрытия в CSS
    • Минификация CSS и JS плагинами Webpack.

    Если вам будет интересна эта библиотека, буду рад звёздочке в GitHub, или напишите в Issues о найденных багах. (Особенно большие проблемы, наверное, в грамматике английской версии документации, так как мои знания языка пока на начальном уровне. Связаться со мной также можно в Instagram

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

    1 Этап. – Подготовительный.
    Этап 2. – HTML и JavaScript код для создания диалогового окна.

    Пришло время создать код для первого диалогового окна. Согласно документации, окна в jQuery UI — это обычные “дивы” (div), к которым применен соответствующий класс и метод инициализации. Внутрь такого блока помещается содержимое окна.
    В тэг body добавим следующий код:

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


    Теперь, если открыть в браузере файл index.html, то мы получим следующее:

    Обратите внимание, это окно уже обладает такими свойствами drag-n-drop, изменение размера, и возможностью закрытия.
    Теперь создадим простую форму для возможности вызова диалоговых окон из другого диалогового окна. Вставим код ниже в содержимое нашего первого окна, т.е. внутрь дива вместо строки «Привет, мир!»:

    Этот шаблон пригодится нам на следующих этапах.

    Этап 3. – Кастомизация диалога посредством стилей и диалоговых опций.

    Заменим инициализирующий окно код таким:

    Пропишем новые новые стили в тег head:


    Теперь окно с формой внутри смотрится чуть симпатичнее:

    В свойствах диалога, записями width: 'auto’ и height: 'auto' мы указали окну подгонять свой размер под размер содержимого.

    Этап 4 – Добавление кнопки для открытия диалогового окна.

    Кнопки (компонент Buttons) в jQuery UI, позволяют “навешивать” на свои события (например на нажатие) различные функции, чем сейчас и надо заняться.
    Для начала создадим кнопку, добавив HTML код:

    в тэг body.
    Затем проинициализируем её, добавив строчку:

    в функцию $(document).ready().
    Раз уж начали экспериментировать с кнопками, то переопределим наши чекбоксы в форме в некое подобие кнопок, для более презентабельного вида.



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

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

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

    Код с небольшими изменениями, основной мотив статьи, порядок следования этапов создания оконного интерфейса при помощи jQuery UI взяты отсюда – англоязычный источник.
    Демо.
    Часть 2.

    Читайте также: