المعرفة:: JavaScript الحالة::مؤرشفة المراجع:: JavaScript Essential Training, The Complete JavaScript Course 2022 From Zero to Expert
What is DOM?
- Allows us to make JavaScript interact with the browser.
- We can write JavaScript to create, modify and delete HTML elements set styles, classes and attributes, and listen and respond to events.
- DOM tree is generated from an HTML document, which we can then interact with.
- DOM is a very complex API that contains lots of methods and properties to interact with the DOM tree.
- More info on MDN.
Selecting Elements
Selecting whole document
console.log(document.documentElement);
Selecting head
console.log(document.head);
Selecting body
console.log(document.body);
Selecting other elements
Access elements with querySelector
methods
https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll
const header = document.querySelector('.header');
const allSections = document.querySelectorAll('.section');
console.log(allSections);
Access elements with getElement
methods
getElementsByTagName
andgetElementsByClassName
returnsHTMLCollection
and notNodeList
.HTMLCollection
is automatically updated if there’s a change happened to DOM.
const element = document.getElementById("id");
const allButtons = document.getElementsByTagName('button');
const elements = document.getElementsByClassName("names");
Creating Elements
// Creating and inserting elements
// create an empty div
const message = document.createElement('div');
// add a class to it
message.classList.add('cookie-message');
// add content
// message.textContent = 'We use cookied for improved functionality and analytics.';
message.innerHTML =
'We use cookied for improved functionality and analytics. <button class="btn btn--close-cookie">Got it!</button>';
Inserting Elements
insertAdjacentHTML
: parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position.
Position | Details |
---|---|
beforebegin | Before the element. Only valid if the element is in the DOM tree and has a parent element. |
afterbegin | Just inside the element, before its first child. |
beforeend | Just inside the element, after its last child. |
afterend | After the element. Only valid if the element is in the DOM tree and has a parent element. |
// insertAdjacentHTML(position, text)
const containerMovements = document.querySelector('.movements');
const html = `<div class="movements__row"></div>`;
containerMovements.insertAdjacentHTML('afterbegin', html);
// insertAdjacentElement: inserts a given element node at a given position relative to the element it is invoked upon.
// 'beforebegin': Before the targetElement itself.
// 'afterbegin': Just inside the targetElement, before its first child.
// 'beforeend': Just inside the targetElement, after its last child.
// 'afterend': After the targetElement itself.
activeElem.insertAdjacentElement("beforebegin", tempDiv);
activeElem.insertAdjacentElement("afterend", tempDiv);
prepend()
,append()
,after()
, andbefore()
methods: inserts a set of Node objects or string objects. For these four methods, String objects are inserted as equivalent Text nodes.prepend()
: before the first child of the Element.append()
: after the last child of the Element.after()
inserts in the children list of the Element’s parent, just after the Element. (As a sibling)before()
inserts in the children list of this Element’s parent, just before this Element. (As a sibling)
// header.prepend(message);
header.append(message);
// header.append(message.cloneNode(true));
// header.before(message);
// header.after(message);
// prepend: adding before the first child of the Element
let div = document.createElement("div");
let p = document.createElement("p");
let span = document.createElement("span");
div.append(p);
div.prepend(span);
console.log(div.childNodes); // NodeList [ <span>, <p> ]
appendChild()
adds a node to the end of the list of children of a specified parent node.
// appendChild: adds a node and return it to be worked with
let p = document.createElement("p");
document.body.appendChild(p);
insertBefore()
: inserts a node before a reference node as a child of a specified parent node.
parentDiv.insertBefore(newNode, sp2);
Deleting Elements
remove()
: removes the element from the DOM.removeChild()
method of the Node interface removes a child node from the DOM and returns the removed node.
message.remove();
message.parentElement.removeChild(message);
// removeChild: removes a child node from the DOM and returns the removed node.
let d = document.getElementById("top");
let d_nested = document.getElementById("nested");
let throwawayNode = d.removeChild(d_nested);
Replacing Elements
replaceChild
: replaces a child node within the given (parent) node.
parentDiv.replaceChild(sp1, sp2);
Styles
- Changing styles using JavaScript modifies inline style.
- CSS attributes must be in camelCase without spaces or hyphen.
<div style="color:red" id="myElement">..</div>
message.style.backgroundColor = '#37383d';
message.style.width = '120%';
const element = document.getElementById("myElement");
const elementStyle = element.style;
document.querySelector(".site-title").style.color;
// "black"
document.querySelector(".sity-title").style.color = "rebeccapurple";
Reading styles
- Accessing styles values using dot notation works only for attributes set by the code itself.
- To access CSS styles we can use
getComputedStyle()
method. - parseFloat can be used to get CSS value without the unit.
console.log(getComputedStyle(message).color);
console.log(getComputedStyle(message).height);
message.style.height =
Number.parseFloat(getComputedStyle(message).height, 10) + 30 + 'px';
Setting custom style properties (variables) using setProperty()
:root {
--color-primary: #5ec576;
--color-primary-darker: #4bbb7d;
--color-primary-opacity: #5ec5763a;
}
document.documentElement.style.setProperty('--color-primary', 'orangered');
Attributes
- Non-standard Attributes can’t be accessed directly, instead
getAttribute
should be used. src
andhref
attributes returns the absolute URLs if they are accessed directly and the relative if the it’s accessed usinggetAttribute
.
const logo = document.querySelector('.nav__logo');
console.log(logo.alt);
console.log(logo.className); // nav__logo
logo.alt = 'Beautiful minimalist logo';
// Non-standard Attributes
console.log(logo.designer); // won't work
console.log(logo.getAttribute('designer'));
logo.setAttribute('company', 'Bankist');
console.log(logo.src); // absolute URL
console.log(logo.getAttribute('src')); // Relative URL
The Element.attributes
property returns a live collection of all attribute nodes registered to the specified node. It is a NamedNodeMap
, a key/value pair of strings that represents any information regarding that attribute.
const para = document.getElementsByTagName("p")[0];
const atts = para.attributes;
// hasAttribute
const result = element.hasAttribute(name);
// removeAttribute
document.getElementById("div1").removeAttribute("align");
Data Attributes
- The
dataset
read-only property of theHTMLElement
interface provides read/write access to custom data attributes (data-) on elements. - Properties should be accessed in camelCase.
<img
src="img/logo.png"
alt="Bankist logo"
class="nav__logo"
id="logo"
designer="Jonas"
data-version-number="3.0"
/>
// Data attributes
console.log(logo.dataset.versionNumber); // 3.0
Classes
https://developer.mozilla.org/en-US/docs/Web/API/Element/className
logo.classList.add('c', 'j');
div.classList.add("foo", "bar", "baz");
logo.classList.remove('c', 'j');
div.classList.remove("foo", "bar", "baz");
// add or remove multiple classes using spread syntax
const cls = ["foo", "bar"];
div.classList.add(...cls);
div.classList.remove(...cls);
// Don't use
// This will override all existing classes
logo.className = 'jonas';
// if visible is set remove it, otherwise add it
div.classList.toggle("visible");
logo.classList.toggle('c');
// replace class "foo" with class "bar"
div.classList.replace("foo", "bar");
// contains
logo.classList.contains('c'); // in arrays it's includes
DOM Traversing
Downwards (children)
Element.children
: all child elements of an element.Element.firstElementChild
andElement.lastElementChild
: returns an element’s first/last child Element, or null.Node.childNodes
,Node.firstChild
,Node.lastChild
: returns all child nodes, including non-element nodes like text and comment nodes.
const h1 = document.querySelector('h1');
// Going downwards: child
console.log(h1.querySelectorAll('.highlight'));
console.log(h1.childNodes); // all notes
console.log(h1.children); // only elements
h1.firstElementChild.style.color = 'white';
h1.lastElementChild.style.color = 'orangered';
Upwards (parents)
Node.parentNode
returns the parent of the specified node in the DOM tree.Document
andDocumentFragment
nodes can never have a parent, soparentNode
will always return null. It also returns null if the node has just been created and is not yet attached to the tree.
Node.parentElement
returns the DOM node’s parent Element, or null.Element.closest()
traverses the element and its parents (upwards) until it finds a node that matches the specified CSS selector. It returns the closest ancestor element, the element itself or null.- Opposite of
querySelector
.
- Opposite of
const h1 = document.querySelector('h1');
// Going upwards: parents
console.log(h1.parentNode);
console.log(h1.parentElement);
h1.closest('.header').style.background = 'var(--gradient-secondary)';
h1.closest('h1').style.background = 'var(--gradient-primary)';
Sideways (siblings)
- Only direct siblings can be accessed.
Element.previousElementSibling
andElement.nextElementSibling
: returns the Element immediately prior to / following the specified one in its parent’s children list.Node.previousSibling
andNode.nextSibling
returns the node immediately preceding / following the specified one in its parent’schildNodes
list.- These four methods return null if the specified node is the first in that list.
- To get all siblings, including the node itself we can use
Node.parentElement.children
.
const h1 = document.querySelector('h1');
// Going sideways: siblings
console.log(h1.previousElementSibling);
console.log(h1.nextElementSibling);
console.log(h1.previousSibling);
console.log(h1.nextSibling);
console.log(h1.parentElement.children);
[...h1.parentElement.children].forEach(function (el) {
if (el !== h1) el.style.transform = 'scale(0.5)';
});
Traverse the DOM tree using querySelector()
and querySelectorAll()
document.querySelectorAll("main li").forEach(item => (item.style.backgroundColor = "red"));