DOM

(document object model)

Creating elements

Creating html elements

var div = document.createElement('div');

div instanceof HTMLDivElement; // true
div.nodeName // 'DIV'
div.nodeType === Node.ELEMENT_NODE; // true

Creating a `div` html element

var ul = document.createElement('ul');

ul instanceof HTMLUListElement; //true
ul.nodeName; // 'UL'
ul.nodeType === Node.ELEMENT_NODE; // true

Creating a `ul` html element

Node types

Creating character data elements

var comment = document.createComment('Empty node');

comment.nodeName; // #comment
comment instanceof CharacterData; // true;
comment.nodeType === Node.COMMENT_NODE; // true;

Creating `comment` character data element

var text = document.createTextNode('Warning');

text.nodeName; // #text
text instanceof CharacterData; // true;
text.nodeType === Node.TEXT_NODE; // true;

Creating `text` character data element

Adding elements

Node.appendChild method

// creating elements

var ulElement = document.createElement('ul');

var liElement1 = document.createElement('li');
var liElement2 = document.createElement('li');

var lineBreak1 = document.createTextNode('\n');
var lineBreak2 = lineBreak1.cloneNode(lineBreak1);
var lineBreak3 = lineBreak1.cloneNode(lineBreak1);

var text = document.createTextNode('Warning');
var comment = document.createComment('Empty node');

// appending elements

liElement1.appendChild(text);
liElement2.appendChild(comment);

ulElement.appendChild(lineBreak1);
ulElement.appendChild(liElement1);
ulElement.appendChild(lineBreak2);
ulElement.appendChild(liElement2);
ulElement.appendChild(lineBreak3);

// adding to the DOM

document.body.appendChild(ulElement);

Node.textContent property

// adding text node using appendChild
var text = document.createTextNode('Warning');
liElement1.appendChild(text);

// adding text node using textContent property
liElement1.textContent = 'Warning';

Writing

var ulElement = document.createElement('ul');
// creating and appending nodes
...
ulElement.textContent; // "\nWarning\n\n"

Reading

<ul>
	<li>Warning</li>
	<li><!-- Empty node --></li>
</ul>

Node.innerHTML property

var html = 
  "<div>Some text here</div>"
+ "<ul>"
+ "    <li>Warning</li>"
+ "    <li><!-- empty node --></li>"
+ "</ul>"

document.body.innerHTML = html;

Writing

Reading

Gotchas

var name = "<img src=x onerror=alert(1)>";
el.innerHTML = name; // shows the alert
document.body.innerHTML = "<div> & < > </div>";
document.body.innerHTML; // "<div> &-amp; &-lt; &-gt; </div>"

Node.insertBefore method

<body>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
    </ul>
</body>

Initial html

Appending `div` element as the last child of the body

Appending `div` element before the `ul` element

var div = document.createElement('div');
div.innerText = 'I am appended before';

document.body.insertBefore(div, ul);
var ul = document.createElement('ul');
ul.innerHTML = 
"<li>Warning</li><li><!-- empty node --></li>"
document.body.appendChild(ul);
<body>
    <div>I am appended before</div>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
    </ul>
</body>
var div = document.createElement('div');
div.innerText = 'I am appended at the bottom';

document.body.insertBefore(div, null);
<body>
    <div>I am appended before</div>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
    </ul>
    <div>I am appended at the bottom</div>
</body>

Inserting the same element multiple times

<body>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
    </ul>
</body>

Initial html

.cloneNode(deep)

Appending `div` element

var div = document.createElement('div');
div.innerText = 'I am div';

document.body.appendChild(div);
ul.appendChild(div);
ul.appendChild(div);
var ul = document.createElement('ul');
ul.innerHTML = 
"<li>Warning</li><li><!-- empty node --></li>"
document.body.appendChild(ul);
<body>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
        <div>I am div/div>
    </ul>
</body>
ul.appendChild(div.cloneNode(true));
<body>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
        <div>I am div</div>
        <div>I am div</div>
    </ul>
</body>

deep - true if the children of the node should also be cloned

DocumentFragment

<body>
    <ul></ul>
</body>

Initial html

Appending `li` elements using fragment

var fragment = document.createDocumentFragment();

var li1 = document.createElement('li');
var li2 = document.createElement('li');
li1.innerText = 'Warning';
li2.innerText = '<!-- empty node -->';

fragment.appendChild(li1);
fragment.appendChild(li2);
ul.appendChild(fragment);
var ul = document.createElement('ul');
document.body.appendChild(ul);
<body>
    <ul>
        <li>Warning</li>
        <li><!-- empty node --></li>
    </ul>
</body>

Traversing

Tree like structure

<html>
    <head>
        <title>Example document</title>
    </head>
    <body>
        <div>Some text here</div>
        <ul>
            <li>Warning</li>
            <li><!-- empty node --></li>
        </ul>
    </body>
</html>

Global references (shortcuts)

Reference to root element

Reference to body element

Reference to document

var document = window.document;

document.nodeName; // #document
document instanceof Node; // true
document.nodeType === Node.DOCUMENT_NODE; // true
var rootElement = document.documentElement;

rootElement.nodeName; // HTML
rootElement instanceof HTMLElement; // true
rootElement.nodeType === Node.ELEMENT_NODE; // true
var bodyElement = document.body;

bodyElement.nodeName; // BODY
bodyElement instanceof HTMLElement; // true
bodyElement.nodeType === Node.ELEMENT_NODE; // true

Reference to head element

var headElement = document.head;

headElement.nodeName; // HEAD
headElement instanceof HTMLElement; // true
headElement.nodeType === Node.ELEMENT_NODE; // true

Node Traversal functions

parentNode
previousSibling
nextSibling

Parents and neighbours

Childrens

 

Element Traversal functions

parentElement
previousElementSibling
nextSibling

Parents and neighbours

Childrens

 

var ulElement = document.createElement('ul');

var liElement1 = document.createElement('li');
var liElement2 = document.createElement('li');
var pElement1 = document.createElement('p');


var lineBreak1 = document.createTextNode('\n');
var lineBreak2 = lineBreak1.cloneNode(true);
var lineBreak3 = lineBreak1.cloneNode(false);

var text = document.createTextNode('Warning');
var comment = document.createComment('Empty node');

// appending elements

liElement1.appendChild(text);
liElement2.appendChild(comment);
liElement2.appendChild(pElement1);
liElement2.appendChild(text);

pElement1.setAttribute('id', 'bar');

ulElement.appendChild(lineBreak1);
ulElement.appendChild(liElement1);
ulElement.appendChild(lineBreak2);
ulElement.appendChild(liElement2);
ulElement.appendChild(lineBreak3);

// adding to the DOM

document.body.appendChild(ulElement);
var body = document.body,
    bar = document.getElementById('bar');

console.log(bar.nextSibling);            // "Warning" {Node}
console.log(bar.nextElementSibling);     // null

console.log(bar.previousSibling);        //  <!--Empty node--> {Node}
console.log(bar.previousElementSibling); // null

console.log(bar.parentElement);          //  li {Node}
console.log(bar.parentNode);             // li {Node}

console.log(bar.parentElement.parentElement.parentElement.parentElement.parentElement) //null
console.log(bar.parentElement.parentNode.parentNode.parentNode.parentNode)  //#document {Node}

var li = bar.parentNode;

console.log(li.children);                // [<p id="bar"></p>]
console.log(li.childNodes);              // [<!--Empty node-->, <p id="bar"></p>, "Warning"]

console.log(li.firstChild);              //?
console.log(li.firstElementChild);       //?

console.log(li.lastChild);               //?
console.log(li.lastElementChild);        //?

Fancier way to traverse

The main difference between these two interfaces is that the TreeWalker presents a tree-oriented view of the nodes in a subtree, rather than the iterator's list-oriented view.

 

In other words, an iterator allows you to move forward or back, but a TreeWalker allows you to also move to the parent of a node, to one of its children, or to a sibling.

 

according to

var node,
    iterator = document.createNodeIterator(
        document, 
        NodeFilter.SHOW_ELEMENT,
        function (node) {
	    return node.nodeName === ‘p’ ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
        }
    );

while(node = iterator.nextNode()) {
    console.log(node);
}
var treeWalker = document.createTreeWalker(
                    document.body,
                    NodeFilter.SHOW_ELEMENT,
                    { 
                        acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } 
                    },
                    false
                 );
nodeFilter = treeWalker.filter; // document.body in this case

nodeIterator

treeWalker

Modifying

Manipulating attributes

var input = document.createElement('input');
input.hasAttribute("disabled"); // false

Checking if attribute is present

Adding attribute or changing attribute value

input.getAttribute("disabled"); // "true"

Removing attribute

input.setAttribute("disabled", "true");
input.hasAttribute("disabled"); // true

Retrieving attribute value

input.removeAttribute("disabled");
input.hasAttribute("disabled"); // false

Manipulating classes

var div = document.createElement('div');
div.className; // ""

div.classList.add("class1");
div.className; // "class1"

div.classList.add("class2");
div.classList.add("class3");
div.className; // "class1 class2 class3"

Adding class

Removing class

div.classList.contains("class1"); // false
div.classList.contains("class2"); // true

Retrieving class by index

div.classList.remove("class1");
div.className; // "class2 class3"

Checking if class is present

div.classList.item(0); // "class2"

Toggling class

div.classList.toggle("class1");
div.className; // "class1 class2 class3"
div.classList.toggle("class1");
div.className; // "class2 class3"

Manipulating styles

var div = document.createElement('div');
div.getAttribute('style'); // null

div.style.setProperty('color', 'green');
div.style.display = 'none';
div.getAttribute('style'); // "color:green; display:none;"

Adding inline style

Removing inline style

Reading inline style

div.style.removeProperty('color', 'green');
div.style.display = "";
div.getAttribute('style'); // null
div.style.setProperty('color', 'green');
div.style.getPropertyValue('color'); // "green"
div.styel.color; // "green"
div.style.cssText; // "color: green;"

Reading computed style

var div = document.createElement('div');
document.body.appendChild(div);
		
div.style.getPropertyValue('display'); // ""
window.getComputedStyle(div).getPropertyValue('display'); // "block";

with CSSStyleDeclaration

Reading applied styles

var div = document.createElement('div');
div.getAttribute('style'); // null

var style = window.getComputedStyle(div);
style.getProperty('display'); // "block";

Adding style

Removing style

Reading style

div.style.removeProperty('color', 'green');   // what will be here if color is red?
div.style.display = "";
div.getAttribute('style'); // ""
div.style.setProperty('color', 'green', 'important');
div.style.getPropertyValue('color'); // "green"
div.styel.color; // "green"
div.style.cssText; // "color: green;"

CSSStyleDeclaration

Searching

getElementById

var div = document.createElement('div');
div.id = 'para1';
document.body.appendChild(div);

var foundDiv = document.getElementById('para1');
div === foundDiv; // true

Searching elements in the DOM

Searching elements in the memory

var div = document.createElement('div');
div.id = 'para1';

var foundDiv = document.getElementById('para1');
foundDiv === null; // true

getElementByClassName

var HTMLCollection = document.getElementsByClassName('searchable');
for (var i=0; i < HTMLCollection.length; i++) {
    console.log(HTMLCollection[i].nodeName);
}

// 'DIV'
// 'SPAN'

Searching elements in the DOM

<body>
    <div class="searchable"></div>
    <div class="non-searchable"></div>
    <span class="searchable"></span>
</body>

HTMLcollection is live

var div = HTMLCollection[0];
div.remove();

for (var i=0; i < HTMLCollection.length; i++) {
    console.log(HTMLCollection[i].nodeName);
}

// 'SPAN'

getElementByTagName

var HTMLCollection = document.getElementsByTagName('div');
for (var i=0; i < HTMLCollection.length; i++) {
    console.log(HTMLCollection[i].className);
}

// 'first'
// 'second'

Searching elements in the DOM

<body>
    <div class="first"></div>
    <div class="second"></div>
    <span class="third"></span>
</body>

querySelectorAll

var div = nodeList[0];
div.remove();

for (var i=0; i < nodeList.length; i++) {
    console.log(nodeList[i].textContent);
}

// This is div
// This is link
// This is span

Searching elements in the DOM

<div class="first">This is div</div>
<a href="http://google.com">This is link</a>
<span class="third">This is span</span>

NodeList is not live

var nodeList = document.querySelectorAll('div, a[href="http://google.com"], .third');
for (var i=0; i < nodeList.length; i++) {
    console.log(nodeList[i].textContent);
}

// This is div
// This is link
// This is span

querySelector

Example 1

<div class="first">
    <span>This is inner span</span>
</div>
<span>This is outer span</span>
var element = document.querySelector('span');
element.textContent; // This is inner span

Example 2

<span>This is outer span</span>
<div class="first">
    <span>This is inner span</span>
</div>
var element = document.querySelector('span');
element.textContent; // This is outer span

Removing

Node.removeChild method

var div = document.createElement('div');
document.body.appendChild('div');

// removing
var removed = document.body.removeChild(div);
removed === div; // true

childNode.remove method

var div = document.createElement('div');
document.body.appendChild('div');

// removing
div.remove();

Events

Events

  • mouse (onclick, oncontextmenu..)
  • keyboard (onkeyup, onkeydown..) 
  • loading (load, unload..)
  • selection API (selectstart, selectionchange)
  • frame/Object Events (onscroll, onresize..)
  • form (onblur, onfocus..) 
  • drag (ondrag, ondrop..)
  • clipboard (oncopy, oncut..)
  • media (onplay, onpause..)
  • animation (animationstart, animationend..)
  • transitionend

Types:

Add, remove events

elem.addEventListener( "click" , function() {
    alert('Hey!')
});


elem.removeEventListener( "click" , function() {    // will not remove EventListener
    alert('Hey!')
});
document.onclick = function(event) {
    console.log(event);
    console.log(event.type + " on " + event.currentTarget);
    console.log(event.clientX + ":" + event.clientY);
  }
var sayHey = function (e) {
  console.log("Hey ", e.type);
};
document.getElementById('button1').addEventListener("click", sayHey);
document.getElementById('button1').removeEventListener("click", sayHey);

Page hooks

DOMContentLoaded

  document.addEventListener("DOMContentLoaded", function(event) {
    console.log("DOM fully loaded and parsed");
  });

onload

The general idea is that window.onload fires when the document's window is ready for presentation and document.DOMContentLoaded fires when the DOM tree (built from the markup code within the document) is completed.

window.onload = function() {
    console.log('Page is ready for presentation');
}

beforeunload/unload

window.onbeforeunload = function() {
  return "Data is not saved, Are you sure you want to exit?";
};

Event Flow

So how it works?:

  • При наступлении события – элемент, на котором оно произошло, помечается как «целевой» (event.target).
  • Далее событие сначала двигается вниз от корня документа к event.target, по пути вызывая обработчики, поставленные через addEventListener(...., true).
  • Далее событие двигается от event.target вверх к корню документа, по пути вызывая обработчики, поставленные через on* и addEventListener(...., false).

Каждый обработчик имеет доступ к свойствам события:

  • event.target – самый глубокий элемент, на котором произошло событие.
  • event.currentTarget (=this) – элемент, на котором в данный момент сработал обработчик (до которого «доплыло» событие).
  • event.eventPhase – на какой фазе он сработал (погружение =1, всплытие = 3).

Shadow DOM

Simple it is..

Shadow DOM fixes CSS and DOM. It introduces scoped styles to the web platform

<html>
  <head></head>
  <body>
    <p id="hostElement"></p>
    <script>
      // create shadow DOM on the <p> element above
      var shadow = document.querySelector('#hostElement').attachShadow();
    </script>
  </body>
</html>

Create Shadow DOM

What else?

Standarts

 

Drafts

 

Copy of DOM

By Nicholas Sorokin

Copy of DOM

  • 1,522