ÐлаÑÑоÑма «веб-компоненÑÑ» вклÑÑÐ°ÐµÑ Ð² ÑÐµÐ±Ñ Ð½ÐµÑколÑко ÑÑандаÑÑов Web Components, коÑоÑÑе Ð½Ð°Ñ Ð¾Ð´ÑÑÑÑ Ð² ÑазÑабоÑке.
ÐаÑнÑм Ð¼Ñ Ñо ÑÑандаÑÑа Custom Elements, коÑоÑÑй позволÑÐµÑ ÑоздаваÑÑ Ñвои ÑÐ¸Ð¿Ñ ÑлеменÑов.
ÐаÑем Custom Elements?
ÐÑиÑиÑно наÑÑÑоеннÑй ÑиÑаÑÐµÐ»Ñ ÑкажеÑ: «ÐаÑем еÑÑ ÑÑандаÑÑ Ð´Ð»Ñ ÑвоиÑ
Ñипов ÑлеменÑов? Я Ð¼Ð¾Ð³Ñ ÑоздаÑÑ Ð»Ñбой ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¸ пÑÑмо ÑейÑаÑ! РлÑбом из ÑовÑеменнÑÑ
бÑаÑзеÑов можно пиÑаÑÑ Ð»Ñбой HTML, иÑполÑзÑÑ Ñвои Ñеги: <mytag>. Ðли ÑоздаваÑÑ ÑлеменÑÑ Ð¸Ð· JavaScript пÑи помоÑи document.createElement('mytag').»
Ðднако, по ÑмолÑÐ°Ð½Ð¸Ñ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ñ Ð½ÐµÑÑандаÑÑнÑм названием (напÑÐ¸Ð¼ÐµÑ <mytag>) воÑпÑинимаеÑÑÑ Ð±ÑаÑзеÑом, как неÑÑо неопÑеделÑнно-непонÑÑное. ÐÐ¼Ñ ÑооÑвеÑÑÑвÑÐµÑ ÐºÐ»Ð°ÑÑ HTMLUnknownElement, и Ñ Ð½ÐµÐ³Ð¾ Ð½ÐµÑ ÐºÐ°ÐºÐ¸Ñ
-либо оÑобÑÑ
меÑодов.
СÑандаÑÑ Custom Elements позволÑÐµÑ Ð¾Ð¿Ð¸ÑÑваÑÑ Ð´Ð»Ñ Ð½Ð¾Ð²ÑÑ ÑлеменÑов Ñвои ÑвойÑÑва, меÑодÑ, обÑÑвлÑÑÑ Ñвой DOM, подобие конÑÑÑÑкÑоÑа и многое дÑÑгое.
ÐавайÑе поÑмоÑÑим ÑÑо на пÑимеÑÐ°Ñ .
Так как ÑпеÑиÑикаÑÐ¸Ñ Ð½Ðµ оконÑаÑелÑна, Ñо Ð´Ð»Ñ Ð·Ð°Ð¿ÑÑка пÑимеÑов ÑекомендÑеÑÑÑ Ð¸ÑполÑзоваÑÑ Google Chrome, лÑÑÑе â поÑледнÑÑ ÑбоÑÐºÑ Chrome Canary, в коÑоÑой, как пÑавило, оÑÑÐ°Ð¶ÐµÐ½Ñ Ð¿Ð¾Ñледние изменениÑ.
ÐовÑй ÑлеменÑ
ÐÐ»Ñ Ð¾Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑлеменÑа иÑполÑзÑеÑÑÑ Ð²Ñзов document.registerElement(имÑ, { prototype: пÑоÑоÑип }).
ÐдеÑÑ:
имÑâ Ð¸Ð¼Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ñега, напÑимеÑ"mega-select". Ðно обÑзано ÑодеÑжаÑÑ Ð´ÐµÑиÑ"-". СпеÑиÑикаÑÐ¸Ñ ÑÑебÑÐµÑ Ð´ÐµÑиÑ, ÑÑÐ¾Ð±Ñ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð² бÑдÑÑем конÑликÑов Ñо ÑÑандаÑÑнÑми ÑлеменÑами HTML. ÐелÑÐ·Ñ ÑоздаÑÑ ÑлеменÑtimerилиmyTimerâ бÑÐ´ÐµÑ Ð¾Ñибка.пÑоÑоÑипâ обÑекÑ-пÑоÑоÑип Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑлеменÑа, он должен наÑледоваÑÑ Ð¾ÑHTMLElement, ÑÑÐ¾Ð±Ñ Ñ ÑлеменÑа бÑли ÑÑандаÑÑнÑе ÑвойÑÑва и меÑодÑ.
ÐоÑ, к пÑимеÑÑ, новÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ <my-timer>:
<script>
// пÑоÑоÑип Ñ Ð¼ÐµÑодами Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑлеменÑа
var MyTimerProto = Object.create(HTMLElement.prototype);
MyTimerProto.tick = function() { // Ñвой меÑод tick
this.innerHTML++;
};
// ÑегиÑÑÑиÑÑем новÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð² бÑаÑзеÑе
document.registerElement("my-timer", {
prototype: MyTimerProto
});
</script>
<!-- ÑепеÑÑ Ð¸ÑполÑзÑем новÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ -->
<my-timer id="timer">0</my-timer>
<script>
// вÑзовем меÑод tick() на ÑлеменÑе
setInterval(function() {
timer.tick();
}, 1000);
</script>
ÐÑполÑзоваÑÑ Ð½Ð¾Ð²Ñй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð² HTML можно и до его обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ ÑеÑез registerElement.
ÐÐ»Ñ ÑÑого в бÑаÑзеÑе пÑедÑÑмоÑÑен ÑпеÑиалÑнÑй Ñежим «обновлениÑ» ÑÑÑеÑÑвÑÑÑÐ¸Ñ ÑлеменÑов.
ÐÑли бÑаÑÐ·ÐµÑ Ð²Ð¸Ð´Ð¸Ñ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑÑнÑм именем, в коÑоÑом еÑÑÑ Ð´ÐµÑÐ¸Ñ - (Ñакие ÑлеменÑÑ Ð½Ð°Ð·ÑваÑÑÑÑ Â«unresolved»), Ñо:
- Ðн ÑÑÐ°Ð²Ð¸Ñ ÑÐ°ÐºÐ¾Ð¼Ñ ÑлеменÑÑ ÑпеÑиалÑнÑй CSS-пÑевдоклаÑÑ
:unresolved, Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÑеÑез CSS можно бÑло показаÑÑ, ÑÑо он еÑÑ Â«Ð½Ðµ подгÑÑзилÑÑ». - ÐÑи вÑзове
registerElementÑакие ÑлеменÑÑ Ð°Ð²ÑомаÑиÑеÑки обновÑÑÑÑ Ð´Ð¾ нÑжного клаÑÑа.
РпÑимеÑе ниже ÑегиÑÑÑаÑÐ¸Ñ ÑлеменÑа пÑоиÑÑ Ð¾Ð´Ð¸Ñ ÑеÑез 2 ÑекÑÐ½Ð´Ñ Ð¿Ð¾Ñле его поÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð² ÑазмеÑке:
<style>
/* ÑÑÐ¸Ð»Ñ Ð´Ð»Ñ :unresolved ÑлеменÑа (до ÑегиÑÑÑаÑии) */
hello-world:unresolved {
color: white;
}
hello-world {
transition: color 3s;
}
</style>
<hello-world id="hello">Hello, world!</hello-world>
<script>
// ÑегиÑÑÑаÑÐ¸Ñ Ð¿ÑоизойдÑÑ ÑеÑез 2 Ñек
setTimeout(function() {
document.registerElement("hello-world", {
prototype: {
__proto__: HTMLElement.prototype,
sayHi: function() { alert('ÐÑивеÑ!'); }
}
});
// Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ Ñипа ÑлеменÑов еÑÑÑ Ð¼ÐµÑод sayHi
hello.sayHi();
}, 2000);
</script>
Ðожно ÑоздаваÑÑ Ñакие ÑлеменÑÑ Ð¸ в JavaScript â обÑÑнÑм вÑзовом createElement:
var timer = document.createElement('my-timer');
РаÑÑиÑение вÑÑÑоеннÑÑ ÑлеменÑов
ÐÑÑе Ð¼Ñ Ð²Ð¸Ð´ÐµÐ»Ð¸ пÑÐ¸Ð¼ÐµÑ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑлеменÑа на оÑнове базового HTMLElement. Ðо можно ÑаÑÑиÑиÑÑ Ð¸ дÑÑгие, более конкÑеÑнÑе HTML-ÑлеменÑÑ.
ÐÐ»Ñ ÑаÑÑиÑÐµÐ½Ð¸Ñ Ð²ÑÑÑоеннÑÑ
ÑлеменÑов Ñ registerElement пÑедÑÑмоÑÑен паÑамеÑÑ extends, в коÑоÑом можно задаÑÑ, какой Ñег Ð¼Ñ ÑаÑÑиÑÑем.
ÐапÑимеÑ, кнопкÑ:
<script>
var MyTimerProto = Object.create(HTMLButtonElement.prototype);
MyTimerProto.tick = function() {
this.innerHTML++;
};
document.registerElement("my-timer", {
prototype: MyTimerProto,
extends: 'button'
});
</script>
<button is="my-timer" id="timer">0</button>
<script>
setInterval(function() {
timer.tick();
}, 1000);
timer.onclick = function() {
alert("ТекÑÑее знаÑение: " + this.innerHTML);
};
</script>
ÐажнÑе деÑали:
- ÐÑоÑоÑип ÑепеÑÑ Ð½Ð°ÑледÑÐµÑ Ð½Ðµ оÑ
HTMLElement, а оÑHTMLButtonElement - ЧÑÐ¾Ð±Ñ ÑаÑÑиÑиÑÑ ÑлеменÑ, нÑжно ÑнаÑледоваÑÑ Ð¿ÑоÑоÑип Ð¾Ñ ÐµÐ³Ð¾ клаÑÑа.
- Ð HTML ÑказÑваеÑÑÑ Ð¿Ñи помоÑи аÑÑибÑÑа
is="..." - ÐÑо пÑинÑипиалÑное оÑлиÑие ÑазмеÑки Ð¾Ñ Ð¾Ð±ÑÑного обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð±ÐµÐ·
extends. ТепеÑÑ<my-timer>ÑабоÑаÑÑ Ð½Ðµ бÑдеÑ, нÑжно иÑполÑзоваÑÑ Ð¸ÑÑ Ð¾Ð´Ð½Ñй Ñег иis. - РабоÑаÑÑ Ð¼ÐµÑодÑ, ÑÑили и ÑобÑÑÐ¸Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸.
- ÐÑи клике на ÐºÐ½Ð¾Ð¿ÐºÑ ÐµÑ Ð½Ðµ оÑлиÑиÑÑ Ð¾Ñ Ð²ÑÑÑоенной. РвÑÑ Ð¶Ðµ, ÑÑо новÑй ÑлеменÑ, Ñо Ñвоими меÑодами, в данном ÑлÑÑае
tick.
ÐÑи Ñоздании нового ÑлеменÑа в JS, еÑли иÑполÑзÑеÑÑÑ extends, необÑ
одимо ÑказаÑÑ Ð¸ иÑÑ
однÑй Ñег в Ñом ÑиÑле:
var timer = document.createElement("button", "my-timer");
ÐизненнÑй Ñикл
РпÑоÑоÑипе Ñвоего ÑлеменÑа Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ задаÑÑ ÑпеÑиалÑнÑе меÑодÑ, коÑоÑÑе бÑдÑÑ Ð²ÑзÑваÑÑÑÑ Ð¿Ñи Ñоздании, добавлении и Ñдалении ÑлеменÑа из DOM:
createdCallback | ÐÐ»ÐµÐ¼ÐµÐ½Ñ Ñоздан |
attachedCallback | ÐÐ»ÐµÐ¼ÐµÐ½Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½ в докÑÐ¼ÐµÐ½Ñ |
detachedCallback | ÐÐ»ÐµÐ¼ÐµÐ½Ñ ÑдалÑн из докÑменÑа |
attributeChangedCallback(name, prevValue, newValue) | ÐÑÑибÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½, изменÑн или ÑдалÑн |
Ðак вÑ, навеÑнÑка, замеÑили, createdCallback ÑвлÑеÑÑÑ Ð¿Ð¾Ð´Ð¾Ð±Ð¸ÐµÐ¼ конÑÑÑÑкÑоÑа. Ðн вÑзÑваеÑÑÑ ÑолÑко пÑи Ñоздании ÑлеменÑа, поÑÑÐ¾Ð¼Ñ Ð²ÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑÑ Ð¸Ð½Ð¸ÑиализаÑÐ¸Ñ Ð¸Ð¼ÐµÐµÑ ÑмÑÑл опиÑÑваÑÑ Ð² нÑм.
ÐавайÑе иÑполÑзÑем createdCallback, ÑÑÐ¾Ð±Ñ Ð¸Ð½Ð¸ÑиализиÑоваÑÑ ÑаймеÑ, а attachedCallback â ÑÑÐ¾Ð±Ñ Ð°Ð²ÑомаÑиÑеÑки запÑÑкаÑÑ ÑÐ°Ð¹Ð¼ÐµÑ Ð¿Ñи вÑÑавке в докÑменÑ:
<script>
var MyTimerProto = Object.create(HTMLElement.prototype);
MyTimerProto.tick = function() {
this.timer++;
this.innerHTML = this.timer;
};
MyTimerProto.createdCallback = function() {
this.timer = 0;
};
MyTimerProto.attachedCallback = function() {
setInterval(this.tick.bind(this), 1000);
};
document.registerElement("my-timer", {
prototype: MyTimerProto
});
</script>
<my-timer id="timer">0</my-timer>
ÐÑого
ÐÑ ÑаÑÑмоÑÑели, как ÑоздаваÑÑ Ñвои DOM-ÑлеменÑÑ Ð¿Ñи помоÑи ÑÑандаÑÑа Custom Elements.
Ðалее Ð¼Ñ Ð¿ÐµÑейдÑм к изÑÑÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑей по ÑабоÑе Ñ DOM.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)