Веб-компонентыОлег Мохов
разработчик интерфейсов
26 октября 2013, ШРИ
GMail
Yandex.Mail
WebComponents● Templates
● Custom Elements
● Shadow DOM
● Imports
● Decorators
07
Templates
Templates<div id="mytemplate" hidden>
<img src="logo.png"/>
<div class="comment"></div>
</div>
01.
02.
03.
04.
09
Templates<script id="mytemplate" type="text/x-handlebars-template">
<img src="logo.png"/>
<div class="comment"></div>
</script>
01.
02.
03.
04.
10
Templates<template>
<img src="logo.png"/>
<div class="comment"></div>
</template>
01.
02.
03.
04.
11
Преимущества <template>1. Содержание остаётся эффективно инертным, пока оно не
активировано. По сути разметка является скрытым DOM'ом и не
рендерится.
2. Содержимое шаблона не порождает побочных эффектов: картинки не
грузятся, видео не проигрывается, скрипты не выполняются.
3. Так же внутренности шаблона не видны при выборе нод через
querySelector() или document.getElementById() .
4. Шаблоны могут находиться в любом месте, даже там, где есть строгие
ограничения на содержимое, например в <head> или <table> .
12
Пример <template><template>
<img src="kitten.jpg"/>
</template>
Demo
01.
02.
03.
13
Пример <template><template>
<img src="kitten.jpg"/>
</template>
var content = document.querySelector('template').content;
document.querySelector('#container').appendChild(
content.cloneNode(true));
01.
02.
03.
01.
02.
03.
14
<template> и стили1. Стили тоже не применяются, пока шаблон не активирован
2. Добавлен селектор :host(<selector>) , который позволяет
применять селекторы только на шаблон
3. НО при использовании стилей в шаблоне надо очень аккуратно
смотреть на оптимизаторы кода, которые делают структурные
изменения
15
Поддержка <template>: ~46%
16
WebComponents● Templates
● Custom Elements
● Shadow DOM
● Imports
● Decorators
17
CustomElements
Yandex.Mail
Yandex.Mail
Yandex.Mail
Yandex.Mail
Верстка почты<div class="header">...</div>
<div class="folders">...</div>
<div class="messages">...</div>
<div class="message">...</div>
01.
02.
03.
04.
23
Верстка почты. HTML5<header>...</header>
<div class="folders">...</div>
<div class="messages">...</div>
<div class="message">...</div>
01.
02.
03.
04.
24
Верстка почты. Web-Components<header>...</header>
<folders>...</folders>
<messages>...</messages>
<message>...</message>
01.
02.
03.
04.
25
Отзывчивость
Lifecycle callbackscreatedCallback
экземпляр элемента создан
enteredViewCallbackэкземпляр элемента добавлен в документ
leftViewCallbackэкземпляр элемента удалён из документа
attributeChangedCallback(attrName, oldVal, newVal)добавление/удаление/изменение аттрибута attrName
27
Создание кастомного элементаvar Folders = Object.create(HTMLElement.prototype);01.
28
Создание кастомного элементаvar Folders = Object.create(HTMLElement.prototype);
Folders.createdCallback = function() {
01.
02.
29
Создание кастомного элементаvar Folders = Object.create(HTMLElement.prototype);
Folders.createdCallback = function() {
this.addEventListener('click', function(e) {
alert('Thanks!');
});
};
01.
02.
03.
04.
05.
06.
30
Создание кастомного элементаvar Folders = Object.create(HTMLElement.prototype);
Folders.createdCallback = function() {
this.addEventListener('click', function(e) {
alert('Thanks!');
});
};
document.register('folders', {prototype: Folders});
Demo
01.
02.
03.
04.
05.
06.
07.
31
Lifecycle callbacksunresolved (inherits from HTMLElement)
элемент есть на странице, но не зарегистрирован через
document.register
unknown (inherits from HTMLUnknownElement)элемент браузеру не известен
Demo
32
Поддержка CustomElements:~45%
33
WebComponents● Templates
● Custom Elements
● Shadow DOM
● Imports
● Decorators
34
Shadow DOMShadow DOM реализует инкапсуляцию DOM-дерева. В него прячется
оформительская вёрстка, необходимая для создания визуально-
красивого контрола/виджета и т.д
http://w3c.github.io/webcomponents/spec/shadow/index.html
39
Shadow DOM JSvar Shadow = Object.create(HTMLElement.prototype);
Shadow.createdCallback = function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = "Ололо";
};
document.register('x-browser', {prototype: Shodow});
01.
02.
03.
04.
05.
06.
40
Templates + Custom Elements + Shadow DOM
Shadow DOM JSvar Shadow = Object.create(HTMLElement.prototype);
Shadow.createdCallback = function() {
var shadow = this.createShadowRoot();
shadow.innerHTML = "Ололо";
};
document.register('x-browser', {prototype: Shodow});
01.
02.
03.
04.
05.
06.
42
Shadow DOM + Templatesvar Shadow = Object.create(HTMLElement.prototype);
Shadow.createdCallback = function() {
var shadow = this.createShadowRoot();
var template = document
.querySelector('template#myTemplate');
shadow.appendChild(template.content);
};
document.register('x-browser', {prototype: Shodow});
01.
02.
03.
04.
05.
06.
07.
08.
43
Поддержка ShadowDom: ~33%
44
WebComponents● Templates
● Custom Elements
● Shadow DOM
● Imports
● Decorators
45
Imports● <link rel="stylesheet"> для загрузки CSS
● <script src> для загрузки скриптов
● <img> для загрузки картинок
● <audio> для загрузки аудио
● <video> для загрузки видео
● ??? для загрузки HTML
46
Imports hacks● <iframe>
47
Imports hacks● <iframe> — живёт своей жизнью, т.е свой контекст относительно
текущей страницы и трудности взаимодействия JavaScript и абсолютно
невозможно стилизовать.
48
Imports hacks● <iframe> — живёт своей жизнью, т.е свой контекст относительно
текущей страницы и трудности взаимодействия JavaScript и абсолютно
невозможно стилизовать.
● AJAX
49
Imports hacks● <iframe> — живёт своей жизнью, т.е свой контекст относительно
текущей страницы и трудности взаимодействия JavaScript и абсолютно
невозможно стилизовать.
● AJAX — требует JavaScript'а :(
50
Imports hacks● <iframe> — живёт своей жизнью, т.е свой контекст относительно
текущей страницы и трудности взаимодействия JavaScript и абсолютно
невозможно стилизовать.
● AJAX — требует JavaScript'а :(
● хаки типа <script type="text/html">
51
Imports hacks● <iframe> — живёт своей жизнью, т.е свой контекст относительно
текущей страницы и трудности взаимодействия JavaScript и абсолютно
невозможно стилизовать.
● AJAX — требует JavaScript'а :(
● хаки типа <script type="text/html">
52
Imports<head>
<link rel="import" href="/path/to/imports/stuff.html">
</link>
01.
02.
03.
53
Особенности Imports● Вёрстка и CSS глобальные
● JavaScript глобальный, но поддерживает локальный скоуп через
document.currentScript.ownerDocument
● Кэширование вёрстки в браузере
● Не блокируют загрузку страницы (async)
54
Поддержка HTMLImports: ?
55
WebComponents● Templates
● Custom Elements
● Shadow DOM
● Imports
● Decorators
56
DecoratorsA decorator is something that enhances or overrides the presentation of
an existing element.
http://www.w3.org/TR/components-intro/#decorator-section
57
Decorators Example<decorator id="details-open">
<template>
<a id="summary">
▾
<content select="summary"></content>
</a>
<content></content>
</template>
</decorator>
01.
02.
03.
04.
05.
06.
07.
08.
09.
58
Decorators Example<details open>
<summary>Timepieces</summary>
<ul>
<li>Sundial
<li>Cuckoo clock
<li>Wristwatch
</ul>
</details>
01.
02.
03.
04.
05.
06.
07.
08.
59
Decorators Exampledetails[open] {
decorator: url(#details-open);
}
01.
02.
03.
60
Decorators Example
61
BEM
BEM● Разделение на блоки (Imports)
● Уровни переопределения (Decorators)
● BEMJSON (Templates)
● BEMHTML (Shadow DOM)
● Блок (Custom Elements)
● Система сборки (Браузер)
64
<folders></folders>
{
block: 'folders'
}
01.
01.
02.
03.
65
BEM/BEViS ~ WebComponents
Будущее уже здесь!
i-bem.jsРеализация блока i-bem в JS. Обеспечивает хелперы для
представления блока в виде JS объекта с определёнными методами и
свойствами.
68
Декларативность{
block: 'folders',
js: true
}
01.
02.
03.
04.
69
Декларативность<div class="folders i-bem"
onclick="return {"folders":{}}">
</div>
01.
02.
03.
70
ДекларативностьBEM.DOM.decl('folders',
onSetMod: {
'js': function() {...}
}
});
01.
02.
03.
04.
05.
71
Изменение модификатораBEM.DOM.decl('folders',
onSetMod: {
'disabled': {
'yes': function() {this.setMod('aaa', 'bbb')}
}
}
});
01.
02.
03.
04.
05.
06.
07.
72
СобытияBEM.DOM.decl('folders',
onSetMod: {
'disabled': {
'yes': function() {this.trigger('disabled')}
}
}
});
01.
02.
03.
04.
05.
06.
07.
73
Событияon(e, [data], fn, [ctx])
подписка на событие e
onFirst(e, [data], fn, [ctx])подписка только на первое событие e
un([e], [fn], [ctx]) —отписка от конкретного события e или всех событий
trigger(e, [data])нотификация о событии e
74
Поиск элементов в терминахБЭМfindBlockInside({String})
ищет блок с заданным именем
findBlockInside({blockName: '', modName: '', modVal:''})
ищет блок с заданными именем, модификатором и значением
findBlocksInside({String|Object})ищет блоки -"-
75
Поиск элементов в терминахБЭМfindElem(elemName[, elemMod, elemModVal])
ищет элемент, возвращает jQuery-объект (некэширует
результат)
76
Поиск элементов в терминахБЭМfindElem(elemName[, elemMod, elemModVal])
ищет элемент, возвращает jQuery-объект (некэширует
результат)
elem(elemName[, elemMod, elemModVal])ищет элемент, возвращает jQuery-объект (кэширует результат)
77
Расширение поведенияBEM.DOM.decl({'name': 'b-link',
'modName': 'pseudo',
'modVal': 'yes'}, {
_onClick : function() {
this
.__base.apply(this, arguments)
.setMod('status', 'clicked');
}
});
01.
02.
03.
04.
05.
06.
07.
08.
09.
78
Итого● Веб-компоненты уже внедряются в браузеры
● Стоит следить за веб-компонентами, т.к они сильно облегчают работу
фронтендерам
● BEM == веб-компоненты. Можно использовать уже сейчас и привыкать
79
Ссылки● Спецификация W3C
● http://jonrimmer.github.io/are-we-componentized-yet/
● Статьи на HTML5Rocks:
– http://www.html5rocks.com/en/tutorials/webcomponents/template/
– http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/
– http://www.html5rocks.com/en/tutorials/webcomponents/customelements/
– http://www.html5rocks.com/en/tutorials/webcomponents/imports/
● Polymer Project
80
Домашнее задание
Веб-компоненты
Олег Мохов
Разработчик интерфейсов
82