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,536