Содержание

JavaScript · Bootstrap v5.0

Индивидуальный или скомпилированный

Плагины могут быть включены индивидуально (с использованием отдельного файла js/dist/*.js в Bootstrap), или все сразу с помощью bootstrap.js или минифицированного bootstrap.min.js (не включайте оба).

Если Вы используете bundler (Webpack, Rollup…), Вы можете использовать файлы /js/dist/*.js готовые для UMD.

Использование Bootstrap как модуля

Мы предоставляем версию Bootstrap, построенную как ESM (bootstrap.esm.js и bootstrap.esm.min.js), которая позволяет Вам использовать Bootstrap в качестве модуля в Вашем браузере, если Ваши целевые браузеры поддерживают его.

<script type="module">
  import { Toast } from 'bootstrap.esm.min.js'
  Array.from(document.querySelectorAll('.toast'))
    .forEach(toastNode => new Toast(toastNode))
</script>

Несовместимые плагины

Из-за ограничений браузера некоторые из наших плагинов, а именно плагины Dropdown, Tooltip и Popover, нельзя использовать в теге <script> с типом module, потому что они зависят от Popper. Для получения дополнительной информации об этой проблеме см здесь.

Зависимости

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

Наши раскрывающиеся списки, всплывающие окна и всплывающие подсказки также зависят от Popper.

Все еще хотите использовать jQuery? Это возможно!

Bootstrap 5 разработан для использования без jQuery, но все же можно использовать наши компоненты с jQuery. Если Bootstrap обнаружит jQuery в объекте window, он добавит все наши компоненты в систему плагинов jQuery; это означает, что вы сможете использовать $('[data-bs-toggle="tooltip"]').tooltip() для включения всплывающих подсказок. То же самое и с другими нашими компонентами.

Атрибуты данных

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

Селекторы

В настоящее время для запросов к элементам DOM мы используем собственные методы querySelector и querySelectorAll из соображений производительности, поэтому Вы должны использовать допустимые селекторы. Если Вы используете специальные селекторы, например:

collapse:Example, не забудьте их экранировать.

События

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

Все инфинитивные события обеспечивают функциональность preventDefault().

Это дает возможность остановить выполнение действия до его запуска. Возврат false от обработчика событий также автоматически вызывает preventDefault().

var myModal = document.getElementById('myModal')
myModal.addEventListener('show.bs.modal', function (event) {
  if (!data) {
    return event.preventDefault() // останавливает отображение модального окна
  }
})

События jQuery

Bootstrap обнаружит jQuery, если jQuery присутствует в объекте window, а атрибут data-bs-no-jquery не установлен в <body>. Если jQuery найден, Bootstrap будет генерировать события благодаря системе событий jQuery. Поэтому, если Вы хотите прослушивать события Bootstrap, вам придется использовать методы jQuery (

.on, .one) вместо addEventListener.

$('#myTab a').on('shown.bs.tab', function () {
  // сделайте что-нибудь...
})

Программный API

Все конструкторы принимают необязательный объект параметров или ничего (который запускает плагин с его поведением по умолчанию):

var myModalEl = document. getElementById('myModal')
var modal = new bootstrap.Modal(myModalEl) // инициализирован по умолчанию
var modal = new bootstrap.Modal(myModalEl, { keyboard: false }) // инициализирован без клавиатуры

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

Селекторы CSS в конструкторах

Вы также можете использовать селектор CSS в качестве первого аргумента вместо элемента DOM для инициализации плагина. В настоящее время элемент для плагина находится с помощью метода querySelector, поскольку наши плагины поддерживают только один элемент.

var modal = new bootstrap.Modal('#myModal')
var dropdown = new bootstrap.Dropdown('[data-bs-toggle="dropdown"]')

Асинхронные функции и переходы

Все программные методы API асинхронныи возвращаются вызывающей стороне после начала перехода, но до его завершения.

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

var myCollapseEl = document.getElementById('myCollapse')
myCollapseEl.addEventListener('shown.bs.collapse', function (event) {
  // Действие, выполняемое после раскрытия сворачиваемой области
})

Кроме того, вызов метода переходного компонента будет проигнорирован

.

var myCarouselEl = document.getElementById('myCarousel')
var carousel = bootstrap.Carousel.getInstance(myCarouselEl) // Получить экземпляр карусели
myCarouselEl.addEventListener('slid.bs.carousel', function (event) {
  carousel.to('2') // Перейдет к слайду 2, как только переход к слайду 1 завершится
})
carousel.to('1') // Начнется переход к слайду 1 и вернется к вызывающему
carousel.to('2') // !! Будет проигнорировано, так как переход к слайду 1 не завершен !!

Настройки по умолчанию

Вы можете изменить настройки плагина по умолчанию, изменив его объект Constructor. Default:

// изменяет значение по умолчанию для опции `keyboard` модального плагина на false bootstrap.Modal.Default.keyboard = false

Нет конфликта (только если Вы используете jQuery)

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

var bootstrapButton = $.fn.button.noConflict() // return $.fn.button к ранее присвоенному значению
$.fn.bootstrapBtn = bootstrapButton // give $().bootstrapBtn функциональность Bootstrap

Номера версий

Доступ к версии каждого из плагинов Bootstrap можно получить через свойство

VERSION конструктора плагина. Например, для плагина всплывающей подсказки:

bootstrap.Tooltip.VERSION // => "5.0.2"

Никаких специальных резервных вариантов при отключенном JavaScript

Плагины Bootstrap не особо изящен при отключенном JavaScript. aria-[\w-]*$/i var DefaultAllowlist = { // Глобальные атрибуты разрешены для любого указанного ниже элемента. ‘*’: [‘class’, ‘dir’, ‘id’, ‘lang’, ‘role’, ARIA_ATTRIBUTE_PATTERN], a: [‘target’, ‘href’, ‘title’, ‘rel’], area: [], b: [], br: [], col: [], code: [], div: [], em: [], hr: [], h2: [], h3: [], h4: [], h5: [], h5: [], h6: [], i: [], img: [‘src’, ‘srcset’, ‘alt’, ‘title’, ‘width’, ‘height’], li: [], ol: [], p: [], pre: [], s: [], small: [], span: [], sub: [], sup: [], strong: [], u: [], ul: [] }

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

var myDefaultAllowList = bootstrap.Tooltip.Default.allowList
// Чтобы разрешить элементы таблицы
myDefaultAllowList.table = []
// Чтобы разрешить элементы td и атрибуты параметров данных в элементах td
myDefaultAllowList.td = ['data-bs-option']
// Вы можете отправить собственное регулярное выражение для проверки своих атрибутов.
data-my-app-[\w-]+/ myDefaultAllowList['*'].push(myCustomRegex)

Если Вы хотите обойти нашу очистку, потому что предпочитаете использовать специальную библиотеку, например DOMPurify, Вам следует сделать следующее:

var yourTooltipEl = document.getElementById('yourTooltip')
var tooltip = new bootstrap.Tooltip(yourTooltipEl, {
  sanitizeFn: function (content) {
    return DOMPurify.sanitize(content)
  }
})

JavaScript. Начало работы · Bootstrap v5.0.2

Индивидуальные или cкомпилированные

Плагины можно подключать по одному (файлами js/dist/*.js) или все сразу – с помощью bootstrap.js или «облегченного» bootstrap.min.js (не подключайте оба сразу).

Если вы используете сборщики пакетов (например, Webpack, Rollup), то вы можете использовать файлы /js/dist/*.js готовые к UMD. Universal Module Definition — это набор шаблонов для обеспечения работы модуля в разных средах выполнения.

Использование Bootstrap в качестве модуля

Мы предоставляем версию Bootstrap, построенную как ESM (bootstrap. esm.js и bootstrap.esm.min.js

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

<script type="module">
  import { Toast } from 'bootstrap.esm.min.js'

  Array.from(document.querySelectorAll('.toast'))
    .forEach(toastNode => new Toast(toastNode))
</script>

Несовместимые плагины

Из-за ограничений браузера некоторые из наших плагинов, а именно плагины Dropdown, Tooltip и Popover, нельзя использовать в теге <script> в качестве module, поскольку они зависят от Popper.js. Для получения дополнительной информации о проблеме см. Здесь.

Зависимости

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

Наши выпадающие списки, всплывающие окна и подсказки также зависят от Popper.

Хотите использовать jQuery? Это возможно!

Bootstrap 5 разработан для использования без jQuery, но вы можете использовать наши компоненты с jQuery. Если Bootstrap обнаружит jQuery в объекте window он добавит все наши компоненты в систему плагинов jQuery; это означает, что вы сможете использовать $('[data-toggle="tooltip"]').tooltip()

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

Атрибуты данных

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

Селекторы

В настоящее время для запроса элементов DOM мы используем собственные методы querySelector и querySelectorAll по соображениям производительности, поэтому вы должны использовать допустимые селекторы. Если вы используете специальные селекторы, например: collapse:Example, не забудьте их «экранировать».

События

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

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

var myModal = document.getElementById('myModal')

myModal.addEventListener('show.bs.modal', function (event) {
  if (!data) {
    return event.preventDefault() // останавливает отображение модального окна
  }
})

Cобытия jQuery

Bootstrap обнаружит jQuery если jQuery присутствует в объекте window и не установлен атрибут data-no-jquery в <body>. Если jQuery найден, Bootstrap будет генерировать события благодаря системе событий jQuery. Поэтому, если вы хотите прослушивать события Bootstrap, вам придется использовать методы jQuery (.on и .one) вместо addEventListener.

$('#myTab a').on('shown.bs.tab', function () {
  // сделайте что-нибудь...
})

Алгоритмическое API

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

var myModalEl = document.getElementById('myModal')
var modal = new bootstrap.Modal(myModalEl) // инициализирован по умолчанию
var modal = new bootstrap.Modal(myModalEl, { keyboard: false }) // инициализирован без клавиатуры

Если вы хотите получить конкретный экземпляр плагина, каждый плагин предоставляет метод getInstance. Чтобы извлечь его непосредственно из элемента, сделайте это: bootstrap. Popover.getInstance (myPopoverEl).

Селекторы CSS в конструкторах

Вы также можете использовать селектор CSS в качестве первого аргумента вместо элемента DOM для инициализации плагина. В настоящее время элемент для плагина находится с помощью метода querySelector, поскольку наши плагины поддерживают только один элемент.

var modal = new bootstrap.Modal('#myModal')
var dropdown = new bootstrap.Dropdown('[data-bs-toggle="dropdown"]')

Асинхронные функции и библиотека «переходов»

Все методы алгоритмических API асинхронны и возвращают пользователю значение после того, как «переход» начат и до того, как «переход» закончен.

Чтобы выполнить действие по завершению «перехода», вы можете отследить соответствующее событие.

var myCollapseEl = document.getElementById('#myCollapse')

myCollapseEl.addEventListener('shown.bs.collapse', function (event) {
  // Действие, выполняемое после раскрытия сворачиваемой области
})

Кроме того, вызов метода переходного компонента будет проигнорирован.

var myCarouselEl = document.getElementById('myCarousel')
var carousel = bootstrap.Carousel.getInstance(myCarouselEl) // Получить экземпляр карусели

myCarouselEl.addEventListener('slid.bs.carousel', function (event) {
  carousel.to('2') // Перейдет к слайду 2, как только переход к слайду 1 завершится
})

carousel.to('1') // Начнется переход к слайду 1 и вернется к вызывающему
carousel.to('2') // !! Будет проигнорировано, так как переход к слайду 1 не завершен !!

Настройки по умолчанию

Вы можете изменить их для плагина, изменяя объект плагина Constructor.Default:

// изменяет значение по умолчанию для опции `keyboard` модального плагина на false
bootstrap.Modal.Default.keyboard = false

Нет конфликта (только если вы используете jQuery)

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

var bootstrapButton = $.fn.button.noConflict() // возвращает $.fn.button к ранее присвоенному значению
$.fn.bootstrapBtn = bootstrapButton // придаёт $().bootstrapBtn функциональность Bootstrap

Номера версий

Доступ к версии каждого из плагинов Bootstrap можно получить через свойство VERSION конструктора плагина. Например, для плагина всплывающей подсказки:

bootstrap.Tooltip.VERSION // => "5.0.1"

Отсутствие fallback’a при отключеном JavaScript

Плагины Bootstrap не особенно изящны, когда JavaScript отключен. Если вы хотите подсказать юзеру, что делать в таком случае, используйте тэг <noscript> для пояснений о пере-включении JavaScript.

Сторонние библиотеки

Официально Bootstrap не поддерживает сторонние JavaScript библиотеки, такие как Prototype или UI-jQuery. aria-[\w-]*$/i var DefaultAllowlist = { // Глобальные атрибуты разрешены для любого указанного ниже элемента. ‘*’: [‘class’, ‘dir’, ‘id’, ‘lang’, ‘role’, ARIA_ATTRIBUTE_PATTERN], a: [‘target’, ‘href’, ‘title’, ‘rel’], area: [], b: [], br: [], col: [], code: [], div: [], em: [], hr: [], h2: [], h3: [], h4: [], h5: [], h5: [], h6: [], i: [], img: [‘src’, ‘srcset’, ‘alt’, ‘title’, ‘width’, ‘height’], li: [], ol: [], p: [], pre: [], s: [], small: [], span: [], sub: [], sup: [], strong: [], u: [], ul: [] }

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

var myDefaultAllowList = bootstrap.Tooltip.Default.allowList

// Чтобы разрешить элементы таблицы
myDefaultAllowList. data-my-app-[\w-]+/
myDefaultAllowList['*'].push(myCustomRegex)

Если Вы хотите обойти нашу очистку, потому что предпочитаете использовать специальную библиотеку, например DOMPurify, Вам следует сделать следующее:

var yourTooltipEl = document.getElementById('yourTooltip')
var tooltip = new bootstrap.Tooltip(yourTooltipEl, {
  sanitizeFn: function (content) {
    return DOMPurify.sanitize(content)
  }
})

Используйте Promise.all для остановки асинхронного выполнения/ожидания блокировки выполнения в JS

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

Асинхронные операции обычно используются для выборки данных, что также называется асинхронным JavaScript и XML (AJAX) — методом отправки запросов с веб-страницы, не требующим обновления браузера. Это было относительно сложно и включало XMLHttpRequest API, но он действительно стал популярным благодаря функции jQuery $.ajax() , которая сделала его более доступным.

tl;dr

Чтобы убедиться, что ваш асинхронный код не замедляет работу ваших приложений, проверьте свой код и убедитесь, что:

  • блокировать друг друга.
  • Не используйте await внутри циклов. Создайте массив промисов и await Promise.all вместо этого.

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

Обещания — прекрасный мощный инструмент.

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

Мы можем увидеть это в действии, написав функцию, которая имитирует медленное сетевое соединение: когда функция вызывается, она будет ждать 1 секунду перед разрешением (это жаргон обещаний для «асинхронная работа завершена»).

Это кодовая статья!

Все примеры кода в этой статье можно запустить в консоли. Чтобы увидеть их в действии, откройте инструменты разработчика (команда + опция + I ), скопируйте и вставьте образец кода в консоль и нажмите клавишу ввода.

Все примеры кода в этом посте можно запустить в инструментах разработки вашего браузера!

Если вы не хотите использовать консоль, вы также можете использовать CodePen или создать файл JavaScript в своем любимом редакторе для запуска в браузере.

Промисы лежат в основе многих наших рабочих процессов извлечения данных.

Один из наиболее распространенных способов работы с Promises — это загрузка данных с помощью Fetch API или библиотеки, такой как Axios. Например, если мы хотим загрузить случайное изображение собаки из Dog CEO, наш код может использовать Fetch API (и обещания) следующим образом:

Fetch отправляет запрос в REST API Dog CEO и ожидает ответа. Как только ответ возвращается, он разрешает промис с данными, которые вернулись. Он предоставляет помощники для обработки различных типов ответов (в данном случае JSON), которые вызываются в .затем , и после этого мы можем делать с данными все, что захотим, объединяя дополнительные вызовы .затем .

Промисы не возвращают значения для использования вне себя.

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

Рассуждение имеет смысл: промисы асинхронны, но они не должны блокировать синхронный код, который не зависит от них, поэтому асинхронный код быть изолированным.

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

Вложенные промисы трудно отслеживать.

Если наш контент состоит из нескольких асинхронных шагов, вложение в промисы может стать сложным для отслеживания:

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

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

Асинхронные функции упрощают использование промисов…

Чтобы упростить работу с промисами, асинхронные функции вводят ключевые слова async и await , которые позволяют нам получить преимущества промисов — ожидание асинхронного выполнения всех завершить, прежде чем продолжить — без умственных затрат на цепочку . затем вызовы и вложенные промисы.

Давайте рефакторим код, который мы написали до сих пор в этой статье, используя асинхронные функции, чтобы его было немного легче читать: разрешенное значение обещания в качестве возвращаемого значения. Это удаляет много шаблонов, связанных с промисами, и это хорошо.

… но асинхронные функции также создают новые проблемы.

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

Давайте рассмотрим два примера:

  1. Две несвязанные асинхронные операции, которые загружают данные, а затем выполняют отдельные действия.
  2. Асинхронная цепочка: одна операция, загружающая массив, затем серия вызовов, зависящих от результата исходного вызова.

С помощью промисов мы могли бы настроить это так:

Если вы запустите это в своей консоли, вы увидите, что Вещь 1 и Вещь 2 выполняются почти одновременно.

Если мы рефакторим для использования асинхронных функций, наш код может выглядеть так:

Это выглядит красиво и чисто, но если мы запустим его в нашей консоли, мы заметим проблему: теперь код выполняется в два раза дольше, чем ! 😱

Обещания выполняются параллельно, потому что им все равно, что происходит за их пределами — поэтому мы можем получить доступ к их содержимому только внутри . затем . Это означает, что и asyncThing1() , и asyncThing2() выполняются одновременно в нашем первом примере.

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

Но есть и хорошие новости: мы можем это исправить, не отказываясь от преимуществ асинхронных функций!

Поскольку асинхронные функции под капотом являются промисами, мы можем запускать как asyncThing1() , так и asyncThing2() параллельно, вызывая их без await . Затем мы можем использовать await и Promise.all , которые возвращают массив результатов после завершения всех промисов.

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

Асинхронные операции с зависимостями

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

С промисами эта настройка может выглядеть так:

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

Чтобы очистить это, нашим первым побуждением может быть рефакторинг этого кода для использования асинхронных функций:

Так намного чище! 😍

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

Чтобы очистить это, мы можем использовать .map вместо цикла for и создать массив обещаний, а затем использовать Promise. all , чтобы дождаться их завершения.

Этот код по-прежнему гораздо более читаем, чем вложенные промисы и циклы for, и он позволяет запросам на загрузку комментариев выполняться параллельно.

Сохраняйте асинхронные функции быстрыми!

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

Есть другие идеи по ускорению асинхронных функций? Напишите мне в Твиттере!

Как правильно использовать preventDefault(), stopPropagation() или возвращать false; о событиях | Джейкоб Уорд

Я уверен, что об этом уже много раз писали и, вероятно, на StackOverflow есть сотни ответов. Несмотря на это, мы по-прежнему просматриваем базы кода и неоднократно находим неправильное использование (или взаимозаменяемое использование, или комбинированное использование) event.preventDefault() , event.stopPropagation() и возвращают false; .

Итак, сегодня мы узнаем, в чем разница между этими тремя и как именно они работают.

preventDefault() , stopPropagation(), и возвращают false; не являются взаимозаменяемыми и не являются инструментами проб и ошибок.

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

Изображение предоставлено FineUploader

HTML

Наш HTML состоит из трех частей:

  1. ввод для обработки диалога загрузки файла. Это скрыто ( display: none; ), так как мы будем вызывать диалог загрузки, используя следующие два элемента.
  2. Раздел с классом file-upload__dropzone , который действует как основная «зона перетаскивания», куда мы сможем перетаскивать файлы (код не включен ) или щелкните, чтобы открыть диалоговое окно загрузки файла.
  3. Тег a с классом file-upload__btn --upload , который будет действовать как кнопка «Загрузить файлы», при нажатии на которую открывается диалоговое окно загрузки файла.

JavaScript

Наш JavaScript, как и наш HTML, также состоит из трех частей:

  1. Функция fileUpload для запуска события click при загрузке файла input .
  2. Назначение зоны сброса div и кнопка для переменных.
  3. Добавление прослушивателей событий к тем, которые при нажатии вызывают функцию fileUpload .

Если бы мы попробовали это сейчас, мы могли бы увидеть некоторое странное поведение — после открытия первого диалогового окна и выбора файла снова откроется второе диалоговое окно с предложением. Продолжайте читать, и все будет раскрыто.

Предотвращает поведение браузера по умолчанию (например, открытие ссылки), но не предотвращает всплытие события в DOM.

В нашем сценарии нажатие на кнопку «Загрузить файлы» вызовет функцию fileUpload , как и следовало ожидать.

Будучи тегом a , он также имеет поведение по умолчанию — это переход браузера к местоположению в атрибуте href . В этом случае у нас установлено значение # , что в большинстве браузеров просто приведет к тому, что страница вернется наверх.

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

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

Здесь мы взяли событие click и предотвратили его поведение по умолчанию с помощью event. preventDefault() , а затем вызвали функцию fileUpload() .

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

Предотвращает всплытие события в DOM, но не останавливает поведение браузера по умолчанию.

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

В нашем случае это означает, что когда мы нажимаем кнопку «Загрузить файл», это событие click также вызывается для всех его родительских элементов, включая нашу зону сброса.

Чтобы увидеть это в действии, мы можем удалить вызов fileUpload() в прослушивателе событий кнопки, и функция по-прежнему будет вызываться, когда мы нажимаем кнопку, потому что событие click всплывет в DOM и будет вызвано на дропзоне.

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

Теперь мы видим, что событие click не только не всплывает в DOM, но и после удаления вызова метода preventDefault тег снова действует должным образом, переходя к его атрибуту href .

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

Мы могли бы использовать как preventDefault , так и stopPropagation , а затем вызывать функцию fileUpload , вот так.

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

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

Он вызывает событие click на кнопке, а также переходит к ее значению href , затем всплывает вверх по DOM, вызывая событие click в зоне перетаскивания.

… в контексте jQuery , возврат false немедленно завершит обратный вызов прослушивателей событий. Это имеет эффект обоих:

  1. Предотвращение поведения по умолчанию — переход браузера к атрибуту href тега a .
  2. Остановка распространения любого события — остановка события click от всплытия DOM.

Если мы рефакторим наш код в jQuery, мы увидим это на практике.

Мы вызываем метод fileUpload , затем возвращаем false , чтобы предотвратить любое поведение по умолчанию или распространение событий.