main sources
- DOM Living Standart
- HTML Living Standart
- Document Object Model (DOM) Level 3 Core Specification
- DOM Parsing and Serialization
Introduction
JavaScript
provides many methods for working with, Document Object Model
or in short DOM
(document object model): some of them are more useful than others; some are used often, others almost never; some are relatively new, others are outdated.
, , - .
, , , .
. , .
, , , .
:
<ul id="list" class="list">
<li id="item1" class="item">1</li>
<li id="item2" class="item">2</li>
<li id="item3" class="item">3</li>
</ul>
(ul
) (li
). (id
) CSS- (class
). id
class
— . : , .. , — , .. .
, "":
const log = console.log
NonElementParentNode
() , .
(nodes) (elements)? , "" — , "". , , .. — , (HTML- ( ) , , ).
, Document
, .
: , .
createElement(tag)
Document
:
const listEl = document.createElement('ul')
. : , , DOM
, .. , , — (template literals), .
(, ) getElementById(id)
Document
:
// const listEl = document.getElementById('list') log(listEl) // ul#list.list - " `ul` `id === list`" `class`
()? id
window
:
log(listEl === window.list) // true
, window
, window
, , window.localStorage
localStorage
. , id
window
:
log(list) // ul#list.list
, React
, DOM
, , Virtual DOM
. , window
window
.
ParentNode
(), .. , ( ).
children
—
const { children } = list // list.children log(children) /* HTMLCollection(3) 0: li#item1.item 1: li#item2.item 2: li#item3.item length: 3 */
HTML (). — (NodeList
).
length
, forEach()
(NodeList
), ( ). , (HTMLCollection
) .. , , map()
, filter()
, reduce()
., . Array.from()
spread-:
const children = Array.from(list.children) // const children = [...list.children] log(children) // [li#item1.item, li#item2.item, li#item3.item] -
firstElementChild
— —lastElementChild
— —
log(list.firstElementChild) // li#item1.item log(list.lastElementChild) // li#item2.item
, :
const createEl = (id, text, tag = 'li', _class = 'item') => { const el = document.createElement(tag) el.id = id el.className = _class el.textContent = text return el }
4 : , , CSS-. 2 ( ) . . , .
prepend(newNode)
—append(newNode)
—
// const newItem = createEl('item0', 0) // list.prepend(newItem) // const newItem2 = createEl('item4', 4) // list.append(newItem2) log(children) /* HTMLCollection(5) 0: li#item0.item 1: li#item1.item 2: li#item2.item 3: li#item3.item 4: li#item4.item */
HTMLCollection
, "", .. , , . , , , .
replaceChildren(nodes)
—
const newItems = [newItem, newItem2] // list.replaceChildren(...newItems) // list.replaceChildren(newItem, newItem2) log(children) // 2
querySelector(selector)
querySelectorAll(selector)
. , getElementById()
, , document
. CSS- (id
, class
, tag
..):
// `li` `id === item0` const itemWithId0 = list.querySelector('#item0') log(itemWithId0) // li#item0.item // `li` `class === item` const allItems = list.querySelectorAll('.item') log(allItems) // /* NodeList(2) 0: li#item0.item 1: li#item4.item length: 2 */
:
const getEl = (selector, parent = document, single = true) => single ? parent.querySelector(selector) : [...parent.querySelectorAll(selector)]
3 : CSS-, ( ). 2 ( ) . , ( ), , :
const itemWithId0 = getEl('#item0', list) log(itemWithId0) // li#item0.item const allItems = getEl('.item', list, false) log(allItems) // [li#item0.item, li#item4.item]
NonDocumentTypeChildNode
, , .. , document
.
previousElementSibling
—nextElementSibling
—
log(itemWithId0.previousElementSibling) // null log(itemWithId0.nextElementSibling) // #item4
ChildNode
, .. , .
before(newNode)
—after(newNode)
—
// `li` `id === item4` const itemWithId4 = getEl('#item4', list) // const newItem3 = createEl('item3', 3) // `itemWithId4` itemWithId4.before(newItem3) // const newItem4 = createEl('item2', 2) // `itemWithId0` itemWithId0.after(newItem4)
replaceWith(newNode)
—
// const newItem5 = createEl('item1', 1) // `itemWithId0` itemWithId0.replaceWith(newItem5)
remove()
—
itemWithId4.remove()
Node
.
nodeType
—
log(list.nodeType) // 1 // /* 1 -> ELEMENT_NODE () 3 -> TEXT_NODE () 8 -> COMMENT_NODE () 9 -> DOCUMENT_NODE (document) 10 -> DOCUMENT_TYPE_NODE (doctype) 11 -> DOCUMENT_FRAGMENT_NODE () .. */
nodeName
—
log(list.nodeName) // UL // /* - HTML- () - - #text - #comment - #document - doctype - #document-fragment */
baseURI
—
log(list.baseURI) // .../dom/index.html
parentNode
—parentElement
—
const itemWithId1 = getEl('#item1', list) log(itemWithId1.parentNode) // #list log(itemWithId1.parentElement) // #list
hasChildNodes()
—true
,childNodes
—
log(list.hasChildNodes()) // true log(list.childNodes) /* NodeList(3) 0: li#item1.item 1: li#item2.item 2: li#item3.item */
firstChild
— —lastChild
— —
log(list.firstChild) // #item1 log(list.lastChild) // #item3
nextSibling
—previousSibling
—
log(itemWithId1.nextSibling) // #item2 log(itemWithId1.previousSibling) // null
textContent
— / /
// log(itemWithId1.textContent) // 1 // itemWithId1.textContent = 'item1' log(itemWithId1.textContent) // item1 // log(list.textContent) // item123
/ () / — innerText
.
cloneNode(deep)
— . , : — , —
// const newList = list.cloneNode(false) // `id` newList.removeAttribute('id') // newList.textContent = 'new list' // list.after(newList) // const newList2 = newList.cloneNode(true) newList.after(newList2)
isEqualNode(node)
—isSameNode(node)
—
log(newList.isEqualNode(newList2)) // true log(newList.isSameNode(newList2)) // false
contains(node)
—true
,
log(list.contains(itemWithId1)) // true
insertBefore(newNode, existingNode)
— (newNode
) (existingNode
)
// const itemWithIdA = createEl('#item_a', 'a') // `itemWithId1` list.insertBefore(itemWithIdA, itemWithId1)
appendChild(node)
—
// const itemWithIdC = createEl('#item_c', 'c') // list.appendChild(itemWithIdC)
replaceChild(newNode, existingNode)
— (existingNode
) (newNode
):
// const itemWithIdB = createEl('item_b', 'b') // `itemWithId1` list.replaceChild(itemWithIdB, itemWithId1)
removeChild(node)
—
// `li` `id === item2` const itemWithId2 = getEl('#item2', list) // list.removeChild(itemWithId2)
Document
Document
.
URL
documentURI
—
log(document.URL) // .../dom/index.html log(document.documentURI) // ^
documentElement
:
log(document.documentElement) // html
getElementsByTagName(tag)
—
const itemsByTagName = document.getElementsByTagName('li') log(itemsByTagName) /* HTMLCollection(4) 0: li##item_a.item 1: li#item_b.item 2: li#item3.item 3: li##item_c.item */
getElementsByClassName(className)
— CSS-
const itemsByClassName = list.getElementsByClassName('item') log(itemsByClassName) // ^
createDocumentFragment()
— :
// const fragment = document.createDocumentFragment() // const itemWithIdD = createEl('item_d', 'd') // fragment.append(itemWithIdD) // list.append(fragment)
. , template
( cloneNode()
DocumentFragment
).
createTextNode(data)
—
createComment(data)
—
importNode(existingNode, deep)
—
// const newList3 = document.importNode(list, true) // list.before(newList3) // newList3.remove()
createAttribute(attr)
—
NodeIterator
TreeWalker
NodeIterator
TreeWalker
(traverse) . , :
// createNodeIterator(root, referenceNode, pointerBeforeReferenceNode, whatToShow, filter) const iterator = document.createNodeIterator(list) log(iterator) log(iterator.nextNode()) // #list log(iterator.nextNode()) // #item_a log(iterator.previousNode()) // #item_a log(iterator.previousNode()) // #list log(iterator.previousNode()) // null // createTreeWalker(root, whatToShow, filter) // - https://dom.spec.whatwg.org/#interface-nodefilter const walker = document.createTreeWalker(list, '0x1', { acceptNode: () => 1 }) log(walker) log(walker.parentNode()) // null log(walker.firstChild()) // #item_a log(walker.lastChild()) // null log(walker.previousSibling()) // null log(walker.nextSibling()) // #item_b log(walker.nextNode()) // #item3 log(walker.previousNode()) // #item_b
Element
.
localName
tagName
—
log(list.localName) // ul log(list.tagName) // UL
id
— /className
— / CSS-
log(list.id) // list list.id = 'LIST' log(LIST.className) // list
classList
— CSS- (DOMTokenList
)
const button = createEl('button', 'Click me', 'my_button', 'btn btn-primary') log(button.classList) /* DOMTokenList(2) 0: "btn" 1: "btn-primary" length: 2 value: "btn btn-primary" */
classList
classList.add(newClass)
—classList.remove(existingClass)
—classList.toggle(className, force?)
— .force
true
, , (toggle() === add()
).force
false
, , (toggle() === remove()
)classList.replace(existingClass, newClass)
— (existingClass
) (newClass
)classList.contains(className)
—true
, (className.includes(className)
)
// button.classList.add('btn-lg') // button.classList.remove('btn-primary') // `btn-lg`, button.classList.toggle('btn-lg') // button.classList.replace('btn', 'btn-success') log(button.className) // btn-success log(button.classList.contains('btn')) // false log(button.className.includes('btn-success')) // true
hasAttributes()
—true
, -getAttributesNames()
—getAttribute(attrName)
—setAttribute(name, value)
—removeAttribute(attrName)
—hasAttribute(attrName)
—true
toggleAttribute(name, force)
— .force
classList.toggle()
log(button.hasAttributes()) // true log(button.getAttributeNames()) // ['id', 'class'] log(button.getAttribute('id')) // button button.setAttribute('type', 'button') button.removeAttribute('class') log(button.hasAttribute('class')) // false
, /, .. / . removeAttribute()
, : , disabled
, false
— disabled
removeAttribute()
.
data-*
, *
. . , id
. , , , , — - window
, id
.
, data-id
getEl('[data-id="id"]')
.
data- -
dataset
. , data-id
dataset.id
.
closest(selectors)
— ,
LIST.append(button) log(button.closest('#LIST', 'document.body')) // #LIST
matches(selectors)
—true
,
log(button.matches('.btn', '[type="button"]')) // `btn`, `type` `button`, // `true`
insertAdjacentElement(where, newElement)
— / / / .where
. :
beforebegin
—afterbegin
—beforeend
—afterend
—
insertAdjacentText(where, data)
—
Text
—
Comment
—
const text = new Text('JavaScript') log(text) // "JavaScript" const part = text.splitText(4) log(part) // "Script" log(part.wholeText()) // Script const comment = new Comment('TODO') log(comment) // <!--TODO-->
Document
location
—
log(document.location)
location
:
hash
— - URL (#
, ), ,#top
host
— , ,localhost:3000
hostname
— , ,localhost
href
—origin
—protocol
+host
pathname
—port
— , ,3000
protocol
— , ,https
search
— (?
, ), ,?name=John&age=30
location
:
reload()
—
replace()
—
title
—
log(document.title) // DOM
head
—
body
—
images
— (HTMLCollection
), ,
const image = document.createElement('img') image.className = 'my_image' image.src = 'https://miro.medium.com/max/875/1*ZIH_wjqDfZn6NRKsDi9mvA.png' image.alt = "V8's compiler pipeline" image.width = 480 document.body.append(image) log(document.images[0]) // .my_image
links
— , ,
const link = document.createElement('a') link.className = 'my_link' link.href = 'https://github.com/azat-io/you-dont-know-js-ru' link.target = '_blank' link.rel = 'noopener noreferrer' link.textContent = ' JS' document.body.append(link) log(document.links[0]) // .my_link
forms
— , ,
const form = document.createElement('form') form.className = 'my_form' document.body.append(form) log(document.forms[0]) // .my_form
:
open()
— .close()
—write()
— (, )writeln()
—designMode
— . :on
off
.document.designMode = 'on'
DevTools
Enter
. , : / , ..execCommand()
— . . / (copy
paste
).navigator.clipboard.writeText()
,navigator.clipboard.readText()
.
InnerHTML
/ innerHTML
/ . :
const itemsTemplate = ` <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> ` LIST.innerHTML = itemsTemplate log(LIST.innerHTML) /* <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> */
Element
outerHTML
— / / : ,innerHTML
+
log(LIST.outerHTML) /* <ul id="LIST" class="list"> <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> </ul> */
insertAdjacentHTML(where, string)
— .where
insertAdjacentElement()
insertAdjacentHTML()
— (tagged template literals) . , (template engine) , Pug
, Handlebars
. . ( History API
) , , (Single Page Application
SPA
). , , - -.
, :
. ? :
const createElFromStr = (str) => { // const el = document.createElement('div') // - el.innerHTML = str // // `firstChild()`, `#text` // const child = el.fisrtElementChild // el.remove() // return child } // const listTemplate = ` <ul id="list"> <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> </ul> ` // const listEl = createElFromStr(listTemplate) // document.body.append(listEl)
. DOMParser()
:
const createElFromStr = (str) => { // const parser = new DOMParser() // const { body: { children } } = parser.parseFromString(str, 'text/html') // return children[0] } const listTemplate = ` <ul id="list"> <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> </ul> ` const listEl = createElFromStr(listTemplate) document.body.append(listEl)
, Range
— createContextualFragment()
:
const createElFromStr = (str) => { // const range = new Range() // const fragment = range.createContextualFragment(str) // return fragment } // const createFragment = (str) => new Range().createContextualFragment(str) const listTemplate = ` <ul id="list"> <li data-id="item1" class="item">1</li> <li data-id="item2" class="item">2</li> <li data-id="item3" class="item">3</li> </ul> ` document.body.append(createFragment(listTemplate))
, , :
// const createEl = (tag, opts) => { const el = document.createElement(tag) // for (const key in opts) { el[key] = opts[key] } // return el } const button = createEl('button', { // id: 'my_button', className: 'btn btn-primary', textContent: 'Click me', title: 'My button', autofocus: true, // style: 'color: red; cursor: pointer;', // .. onmouseenter: function () { this.style.color = 'green' }, onmouseout: function () { this.style.color = 'blue' }, onclick: () => alert('!') }) document.body.append(button)
JS
DOM
. , -. , () , DOM- ( jQuery
), , .
, — , , .
VDS .
10% !