From 0e31dfe42cd17c1e717d1eab645ef50c96c13667 Mon Sep 17 00:00:00 2001 From: dmitryskripunov Date: Tue, 7 Jan 2020 19:11:22 +0000 Subject: [PATCH 1/4] Translate customelements.md via GitLocalize --- .../web-components/customelements.md | 1127 +++++++++++++++++ 1 file changed, 1127 insertions(+) create mode 100644 src/content/ru/fundamentals/web-components/customelements.md diff --git a/src/content/ru/fundamentals/web-components/customelements.md b/src/content/ru/fundamentals/web-components/customelements.md new file mode 100644 index 00000000000..d40ca2b3f19 --- /dev/null +++ b/src/content/ru/fundamentals/web-components/customelements.md @@ -0,0 +1,1127 @@ +project_path: "/web/fundamentals/_project.yaml" +book_path: "/web/fundamentals/_book.yaml" +description: Custom elements allow web developers to define new HTML tags, extend + existing ones, and create reusable web components. + +{# wf_updated_on: 2018-09-20 #} +{# wf_published_on: 2016-06-28 #} +{# wf_blink_components: Blink>DOM #} + +# Custom Elements v1: веб-компоненты для повторного использования {: .page-title } + +{% include "web/_shared/contributors/ericbidelman.html" %} + +### Краткое изложение {: #tldr .hide-from-toc } + +При помощи [Custom +Elements](https://html.spec.whatwg.org/multipage/scripting.html#custom-elements) +(* пользовательские элементы. Здесь и далее примеч. пер.) веб-разработчики могут +** создавать новые теги HTML **, совершенствовать существующие или улучшать +созданные другими разработчиками компоненты. Этот API – фундамент [ Web +Components ](http://webcomponents.org/). За счет него у нас имеется основанный +на веб-стандартах способ создания компонентов для повторного использования при +помощи лишь чистого кода JS/HTML/CSS. Благодаря нему нам необходимо писать +меньше кода и мы получаем модульный код, который можем повторно использовать в +нашем приложении. + +## Введение + +Обратите внимание: В данной статье описывается новая спецификация Custom Elements . Если вы использовали +пользовательские элементы, то, вероятно, знакомы с версией 0, +поддержка которой реализована в Chrome 33 . Принцип работы тот же, однако в +спецификацию версии 1 внесены важные поправки в API. Читайте далее, чтобы +узнать, что нового появилось в этой версии или ознакомьтесь с разделом История и поддержка браузером для получения +дополнительной информации. + +Браузер предоставляет нам великолепный инструмент для структурирования +веб-приложений. Этот инструмент называется HTML. Вы, должно быть, слышали о нем! +Это декларативный, портируемый язык с хорошей поддержкой и с ним легко работать. +Каким бы великолепным не казался HTML, его словарный состав и расширяемость +ограничены. В [ живом стандарте HTML ](https://html.spec.whatwg.org/multipage/) +всегда не хватало способа автоматического объединения поведения, реализуемого +при помощи JS, с вашей разметкой... до сих пор. + +За счет Пользовательских элементов осуществляется модернизация HTML, заполнение +недостающих кусочков мозаики и объединение структуры и поведения. Если мы не +можем решить проблему за счет имеющихся средств HTML, то можем создать для ее +решения пользовательский элемент. ** Благодаря Пользовательским элементам +расширяются функциональные возможности браузера и в то же время сохраняются +преимущества использования HTML **. + +## Определение нового элемента {: #define} + +Для того чтобы определить новый элемент HTML, нам необходимо воспользоваться +возможностями JavaScript! + +Свойство ` customElements ` глобального объекта window используется для +определения нового пользовательского элемента и обучения браузера тому, как его +отображать. Вызовите ` customElements.define() `, передав в качестве параметров +имя тега, который хотите создать, и `класс` JavaScript, который наследуется от +базового класса `HTMLElement`. + +**Пример:** - определение боковой выдвижной навигационной панели для мобильных +устройств, ``: + +``` +class AppDrawer extends HTMLElement {...} +window.customElements.define('app-drawer', AppDrawer); + +// Or use an anonymous class if you don't want a named constructor in current scope. +window.customElements.define('app-drawer', class extends HTMLElement {...}); +``` + +Пример использования: + +``` + +``` + +Важно помнить, что использование пользовательского элемента ничем не отличается +от использования `
` или любого другого элемента. Его образцы могут быть +объявлены на странице, созданы динамически при помощи кода JavaScript, могут +быть добавлены обработчики событий и т.д. Читайте далее для ознакомления с +большим количеством примеров. + +### Определение JavaScript API элемента {: #jsapi} + +Функциональные возможности пользовательского элемента определяются при помощи +[`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) +ES2015, который расширяет `HTMLElement`. За счет наследования от `HTMLElement` +гарантируется, что пользовательский элемент перенимает весь DOM API, и +обеспечивается то, что любые добавленные к классу свойства/методы становятся +частью интерфейса DOM элемента. По сути, используйте класс для создания +**публичного JavaScript API**. + +**Пример**: определение интерфейса DOM ``: + +``` +class AppDrawer extends HTMLElement { + + // A getter/setter for an open property. + get open() { + return this.hasAttribute('open'); + } + + set open(val) { + // Reflect the value of the open property as an HTML attribute. + if (val) { + this.setAttribute('open', ''); + } else { + this.removeAttribute('open'); + } + this.toggleDrawer(); + } + + // A getter/setter for a disabled property. + get disabled() { + return this.hasAttribute('disabled'); + } + + set disabled(val) { + // Reflect the value of the disabled property as an HTML attribute. + if (val) { + this.setAttribute('disabled', ''); + } else { + this.removeAttribute('disabled'); + } + } + + // Can define constructor arguments if you wish. + constructor() { + // If you define a constructor, always call super() first! + // This is specific to CE and required by the spec. + super(); + + // Setup a click listener on itself. + this.addEventListener('click', e => { + // Don't toggle the drawer if it's disabled. + if (this.disabled) { + return; + } + this.toggleDrawer(); + }); + } + + toggleDrawer() { + ... + } +} + +customElements.define('app-drawer', AppDrawer); +``` + +В этом примере мы создаем выдвижную панель со свойствами `open`, `disabled` и +методом `toggleDrawer()`. Он также [отражает свойства как атрибуты +HTML](#reflectattr). + +Удобная особенность пользовательских элементов - то, что **`this` внутри +определения класса относится к самому элементу DOM** , то есть к экземпляру +класса. В нашем примере `this` относится к `` . За счет этого +элемент может подключить слушатель `click` к себе самому! И вы не ограничены +слушателями событий! Весь API DOM доступен внутри кода элемента. Используйте +`this` для доступа к свойствам элемента, обращения к его дочерним элементам ( +`this.children` ), запроса узлов ( `this.querySelectorAll('.items')` ) и т.д. + +**Правила создания пользовательских элементов** + +1. Имя пользовательского элемента **должен содержать дефис (-)**. Таким образом, +`` , `` и `` - допустимые имена, а `` +и `` - нет. Благодаря этому парсер HTML может отличить пользовательские +элементы от стандартных. Это также обеспечивает прямую совместимость при +добавлении новых тегов в HTML. +2. Вы не можете зарегистрировать один и тот же тэг более одного раза. При +попытке это выполнить будет выкинута ошибка `DOMException`. Как только вы +сообщили браузеру о новом тэге, то все. Назад дороги нет. +3. Пользовательские элементы не могут быть самозакрывающимися, поскольку +согласно стандарту HTML только [несколько +элементов](https://html.spec.whatwg.org/multipage/syntax.html#void-elements) +могут быть самозакрывающимися. Всегда добавляйте закрывающийся тэг ( + drawer + ). + +## Реакции (ответные действия) пользовательского элемента {: #reactions} + +Пользовательский элемент может определять специальные хуки жизненного цикла для +запуска кода в интересные периоды его существования. Они называются **реакциями +пользовательского элемента.** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ИмяВызывается
constructorЭкземпляр элемента создан или обновлён. +Полезна для инициализации состояния, установки слушаетелей событий или +создания теневого dom (shadow dom). Смотри спецификацию +чтобы узнать об ограничениях использования constructor.
connectedCallbackВызывается каждый раз когда элемент добавляется в DOM. Полезна для +запуска кода установки, такого как получение ресурсов или отрисовки. Как +правило, вы должны попытаться отложить работу до этого времени.
disconnectedCallbackВызывается каждый раз когда элемент удаляется из DOM. Удобна для +запуска кода очистки.
attributeChangedCallback(attrName, oldVal, newVal)Вызывается когда наблюдаемый атрибут был +добавлен, удалён, обновлён или заменён. Так же вызывается для установки +значений, когда элемент создаётся парсером, или улучшается +(upgrade). +Примечание: только атрибуты из списка в свойстве +observedAttributes получат этот вызов.
adoptedCallbackПользовательский элемент был перемещён в новый document +(например кто-то вызвал document.adoptNode(el))
+ +Обратите внимание: Браузер вызывает `attributeChangedCallback()` при изменении +значений любого атрибут, указанный в массиве `observedAttributes` (обратитесь к +разделу, посвященное [Отслеживание изменений значений атрибутов](#attrchanges) +). По сути, это делается для оптимизации производительности. Когда пользователи +изменяют общие свойства, например, `style` или `class`, вы наверняка не захотите +получить тонны вызовов этих функций. + +**Вызовы реакций синхронны**. Если кто-либо вызывает `el.setAttribute()` для +вашего элемента, то браузер тут же вызывает `attributeChangedCallback()`. +Подобным образом будет вызван `disconnectedCallback()` сразу после того, как ваш +элемент удален из DOM (например пользователь вызвал `el.remove()`). + +**Пример**: добавление реакций пользовательского элемента для ``: + +``` +class AppDrawer extends HTMLElement { + constructor() { + super(); // always call super() first in the constructor. + ... + } + connectedCallback() { + ... + } + disconnectedCallback() { + ... + } + attributeChangedCallback(attrName, oldVal, newVal) { + ... + } +} +``` + +Определяйте реакции, если/когда это имеет смысл. Если ваш элемент достаточно +сложен и выполняет подключение к IndexedDB в `connectedCallback()`, то выполните +необходимый для завершения работы с элементом код в disconnectedCallback(). Но +будьте бдительны! Вы не можете полагаться во всех ситуациях исключительно на +код, выполняемый при удалении элемента из DOM. Например, +`disconnectedCallback()` никогда не будет вызван при закрытии пользователем +вкладки. + +## Свойства и атрибуты + +### Преобразование значений свойств в значения атрибутов HTML {: #reflectattr} + +Преобразование значения свойств HTML обратно в DOM в значение атрибута HTML – +обычное дело. Например, когда значения `hidden` или `id` изменяются в коде JS: + +``` +div.id = 'my-id'; +div.hidden = true; +``` + +значения применяются к существущему DOM в качестве атрибутов: + +``` +