After some time, it became clear that the main idea of Prototype came into conflict with the world. The creators of the browsers responded to the resurgence of Javascript by adding new APIs, many of which clashed with the implementation of Prototype.
- Sam Stephenson, creator of Prototype.js, You Are Not Your Code
Array.prototype.forEach()
, map()
, etc., jquery inspired developers to HTMLElement.prototype.querySelector()
and querySelectorAll()
.<template>
tags is parsed by the browser, but does not cause the execution of scripts and the loading of additional resources (images, audio ...) until we insert it into the document.<audio>
and <video>
elements. In the code, we place one tag, and the browser displays several elements (sliders, buttons, player window). In Chrome, these and some other elements use<menu>
or <user-info>
?In web components, templates are DOM fragments. The browser parses their contents, but does not execute until we insert it into the document. That is, the browser will not load pictures, audio and video, will not execute scripts.
<template id="tmpl-user"> <h2 class="name"> </h2> <img src="photo.jpg"> </template>
<template>
. You can reach it using js: var tmpl = document.querySelector('#tmpl-user'); // <template> var content = tmpl.content; var imported; // : content.querySelector('.name').innerText = ''; // , // document.importNode() // // `` , // `photo.jpg` imported = document.importNode(content); // : document.body.appendChild(imported);
All examples in the article should be viewed in Chrome Canary with flags enabled:
- Experimental Web Platform features
- Enable HTML Imports
- Enable Experimental Javascript
<div hidden data-template="my-template"> <p>Template Content</p> <img></img> </div>
<script type="x-template">
). <sctipt type="x-template" data-template="my-template"> <p>Template Content</p> <img src="{{ image }}"></img> </script>
<template>
does not have these flaws. We work with DOM, not with strings. When to execute the code, we also decide.<audio>
code looks like this: <audio controls src="kings-speech.wav"></audio>
In order for Chrome in DevTools to display the contents of the Shadow DOM, in the settings for DevTools, the General tab, in the Elements section, check Show Shadow DOM .
<audio>
in DevTools:<audio>
tag in the example above, in its place, the browser renders the contents of the shadow tree .<style>
do not apply to the parent document. We also have the ability to limit the influence of the styles of the parent document on the contents of the shadow tree. More on that later. <div class="shadow-host"> . </div> <script> var shadowHost = document.querySelector('.shadow-host'); var shadowRoot = shadowHost.createShadowRoot(); shadowRoot.innerText = ' .' </script>
<content>
<content>
tag in the standard.It is important that<content>
projects the contents of the host, rather than transferring it from the host to the shadow tree. The descendants of the host remain in place, the document styles (and not the shadow tree) apply to them.<content>
is a kind of window between worlds.
<template id="content-tag"> <p> <strong>shadow tree</strong>. </p> <p> <strong>shadow host</strong>: </p> <content></content> </template> <div class="shadow-host"> <h1 class="name"></h1> <img src="varlam.png"> <p class="description"> </p> </div> <script> var host = document.querySelector('.shadow-host'), template = document.querySelector('#content-tag'), shadow = host.createShadowRoot(); shadow.appendChild(template.content); </script>
<template id="color-green"> <style> div { background-color: green; } </style> <div></div> </template> <div class="shadow-host"></div> <script> var host = document.querySelector('.shadow-host'), template = document.querySelector('#color-green'), shadow = host.createShadowRoot(); shadow.appendChild(template.content); </script>
color
, font-size
and others , affect the contents of shadow tree. We avoid this by setting shadowRoot.resetStyleInheritance = true
. <template id="reset"> <p> .</p> <content></content> </template> <div class="shadow-host"> <p>Host Content</p> </div> <script> var host = document.querySelector('.shadow-host'), template = document.querySelector('#reset'), shadow = host.createShadowRoot(); shadow.resetStyleInheritance = true; shadow.appendChild(template.content); </script>
applyAuthorStyles
property. <template id="no-author-st"> <div class="border">div.border</div> </template> <style> /* */ .border { border: 3px dashed red; } </style> <div class="shadow-host"></div> <script> var host = document.querySelector('.shadow-host'), template = document.querySelector('#no-author-st'), shadow = host.createShadowRoot(); shadow.applyAuthorStyles = false; // - shadow.appendChild(template.content); </script>
applyAuthorStyles
, we get a different result:applyAuthorStyles = false
applyAuthorStyles = true
div ^ p
selector is similar to div p
with the exception that it crosses one shadow border ( Shadow Boundary ).div ^^ p
similar to the previous one, but crosses ANY number of shadow borders. <template id="hat"> <p class="shadow-p"> . </p> </template> <style> /* */ .shadow-host ^ p.shadow-p { color: red; } </style> <div class="shadow-host"></div> <script> var host = document.querySelector('.shadow-host'), template = document.querySelector('#hat'), shadow = host.createShadowRoot(); shadow.appendChild(template.content); </script>
iframe
. The latter is too isolated. In order to interact with an external document, you have to invent crazy ways to send messages. Changing the external view using css is simply not possible.iframe
, the Shadow DOM is part of your document. And although the shadow tree is somewhat isolated, if we wish, we can change its presentation with the help of styles, or pick it up with a script.<audio>
, <video>
or <input type="date">
.HTMLElement
. Thus, when the browser stumbles upon a <my-super-element>
markup, it parses it as an HTMLElement
. In the case of <mysuperelement>
, the result will be an HTMLUnknownElement
. <dog></dog> <x-dog></x-dog> <dl> <dt>dog type</dt> <dd id="dog-type"></dd> <dt>x-dog type</dt> <dd id="x-dog-type"></dd> </dl> <script> var dog = document.querySelector('dog'), dogType = document.querySelector('#dog-type'), xDog = document.querySelector('x-dog'), xDogType = document.querySelector('#x-dog-type'); dogType.innerText = Object.prototype.toString.apply(dog); xDogType.innerText = Object.prototype.toString.apply(xDog); </script>
play()
method of the <audio>
element.HTMLElement
or its successor,HTMLButtonElement
: var myElementProto = Object.create(HTMLElement.prototype, { // API lifecycle callbacks });
document.registerElement()
: var myElement = document.registerElement('my-element', { prototype: myElementProto });
<x-cat></x-cat> <div> <strong>Cat's life:</strong> <pre id="cats-life"></pre> </div> <script> var life = document.querySelector('#cats-life'), xCatProto = Object.create(HTMLElement.prototype, { nickName: 'Cake', writable: true }); xCatProto.meow = function () { life.innerText += this.nickName + ': meow\n'; }; xCatProto.createdCallback = function () { life.innerText += 'created\n'; }; xCatProto.attachedCallback = function () { life.innerText += 'attached\n'; }; xCatProto.detachedCallback = function () { life.innerText += 'detached\n'; }; xCatProto.attributeChangedCallback = function (name, oldVal, newVal) { life.innerText += ( 'Attribute ' + name + ' changed from ' + oldVal + ' to ' + newVal + '\n'); }; document.registerElement('x-cat', { prototype: xCatProto }); document.querySelector('x-cat').setAttribute('friend', 'Fiona'); document.querySelector('x-cat').meow(); document.querySelector('x-cat').nickName = 'Caaaaake'; document.querySelector('x-cat').meow(); document.querySelector('x-cat').remove(); </script>
<div>
or <ul>
well suited for low-level layout, while Custom Elements will allow you to write modular, readable code at a high level. <link rel="import" href="widget.html"> <sctipt> var link = document.querySelector('link[rel="import"]'); // // *import*. var importedContent = link.import; importedContent.querySelector('article'); </sctipt>
Object.observe()
object. var o = {}; Object.observe(o, function (changes) { changes.forEach(function (change) { // change.object console.log('property:', change.name, 'type:', change.type); }); }); ox = 1 // property: x type: add ox = 2 // property: x type: update delete ox // property: x type: delete
<html> <head> <link rel="import" href="todo.html"> </head> <body> <x-todo></x-todo> </body> </html> <script> // JS API : var xTodo = document.querySelector('x-todo'); xTodo.items(); // xTodo.addItem(taskText); // xTodo.removeItem(taskIndex); // </script>
<canvas>
also appeared. Now we have a huge number of opportunities to create interactive applications on the client. This standard also introduced the elements <article>
, <header>
, and others. The markup has become “make sense”, has acquired semantics.Source: https://habr.com/ru/post/210058/
All Articles