Luiz Corte Real
<minha-tag />
document.registerElement('minha-tag', {...})
document.registerElement({ createdCallback() {...}, attachedCallback() {...}, detachedCallback() {...}, attributeChangedCallback() {...} });
<html-gl>
<li class="broadcast">
<div class="image_background"></div>
<img src="./pic/boxes/box_argo.png">
<p>
Select me with DevTools
</p>
<p>
<img src="./assets/img/imdb.png">
<span>7.8<span>/10</span></span>
</p>
</li>
</html-gl>
Demo
DOM dentro de DOM ⇒ encapsulamento!
DemoFonte: webcomponents.org
Fonte: webcomponents.org
não estamos aqui para falar de libs
ou de interfaces ultra sofisticadas
para solucionar problemas comuns
v1 ⇒ Raça
v2 ⇒ Bootstrap-like
v3 ⇒ Elo7 Bootstrap
elo7.com.br/bootstrap
<desktop:sidebar links="${links}" active="Meu perfil"/>
⟱
<nav class="links">
<a class="link active" href="#" title="Meu perfil">
Meu perfil
</a>
<a class="link " href="#" title="Conta">
Conta
</a>
<a class="link " href="#" title="Loja">
Loja
</a>
</nav>
<desktop:page css="saleConversation" jsFiles="...">
<section class='order-detail'>
<desktop:headerDetails user="..."/>
<order:buyerDetail order="..."/>
</section>
<desktop:saleConversationBox>
<desktop:saleConversation messages="..."/>
</desktop:saleConversationBox>
</desktop:page>
Parece isolado
Componentes de interface realmente isolados
<iframe src="meucomponente.html"></iframe>
<iframe>
é um container isolado!
Problema: integração no layout
JS resolve, mas e o progressive enhancement?
elo7-chat__bubble
no CSS
Elo7.Chat.Bubble
no JS
...
Equipe triste
Reaproveitamento difícil
Não resolve todos os problemas
Ok, we can deal with that ?
<g-map lat="23.45" lon="67.89"></g-map>
não ❤ progressive enhancement
<img-slider>
<img src="foto1.jpg">
<img src="foto2.jpg">
<img src="foto3.jpg">
</img-slider>
❤ progressive enhancement
Demo
<w7-component>
<link rel='stylesheet' href='...'>
<link rel='stylesheet' href='...'>
<div class='conversation-content'>
<ol class='conversation'>
<!-- ... -->
</ol>
</div>
<script src='...'></script>
<script src='...'></script>
<script src='...'></script>
</w7-component>
var proto = Object.create(HTMLElement.prototype);
proto.attachedCallback = function() {
var self = this;
if (document.readyState === 'complete') {
activateShadowDom(self);
} else {
document.addEventListener('DOMContentLoaded',
function() {
activateShadowDom(self);
}, false);
}
};
document.registerElement('w7-component', {
prototype: proto
});
activateShadowDom(HTMLElement)
function activateShadowDom(el) {
var root = el.createShadowRoot(),
children = el.children;
for (var i = 0, max = children.length; i < max; i++) {
var child = children[i];
if (isCSS(child)) {
deactivateCSS(child);
root.appendChild(transformCSSToImport(child));
} else {
root.appendChild(children[i].cloneNode(true));
}
}
}
w7-component {
...
}
.attachment {
...
}
.bubble {
...
}
.attachment {
...
}
Não funciona sempre :(
w7-component {
...
}
w7-component .attachment {
...
}
:not(w7-component) .bubble {
...
}
.bubble {
...
}
.attachment {
...
}
w7-component {
...
}
+ (num <link>
dentro de um <noscript>
)
w7-component .attachment {
...
}
:not(w7-component) .bubble {
...
}
No componente:
onComponentLoaded(['ajax', 'zoom'],
function(component, ajax, zoom) {
var root = component.get();
var forms = root.querySelectorAll('form');
// ...
zoom.on('close', function() {
component.remove();
});
}
No registrador do componente:
window.onComponentLoaded = function(deps, callback) {
// 1. detectar tag do componente
// 2. executar callback após carregamento das deps
};
No registrador do componente:
window.onComponentLoaded = function(deps, callback) {
var scriptTags = document.querySelectorAll(
'w7-component > script:not([data-executed])');
var component =
new Component(scriptTags[0].parentNode);
for (var i = 0; i < scriptTags.length; i++) {
var scriptTag = scriptTags[i];
scriptTag.setAttribute('data-executed', '');
}
// 2. executar callback após carregamento das deps
};
No registrador do componente:
window.onComponentLoaded = function(deps, callback) {
var scriptTags = document.querySelectorAll(
'w7-component > script:not([data-executed])');
var component =
new Component(scriptTags[0].parentNode);
for (var i = 0; i < scriptTags.length; i++) {
var scriptTag = scriptTags[i];
scriptTag.setAttribute('data-executed', '');
}
define(deps, function() {
var loadedDeps = toArray(arguments);
loadedDeps.unshift(component);
callback.apply(null, loadedDeps);
});
};
+ checagens de suporte a Web Components e setTimeouts
Mas, e se, na mesma página...
<w7-component>
<-- CSS, HTML -->
<script src='doc-1.1.js'>
</script>
</w7-component>
<w7-component>
<-- CSS, HTML -->
<script src='doc-2.0.js'>
</script>
</w7-component>
Boom!
(escopo JS continua global)Luiz Corte Real
luiz.real@elo7.com @srsaudeSlides online: elo7.github.io/web-components-no-elo7