
Доброго времени суток, друзья!
В этой статье я хочу поделиться с Вами некоторыми находками, сделанными мной в процессе изучения JavaScript. Возможно, Вы найдете для себя что-то интересное. Данная часть серии будет посвящена, преимущественно, работе с DOM.
Настоятельно рекомендую применить к body следующие стили:
body { margin: 0; min-height: 100vh; overflow: hidden;}
Если планируете тестировать примеры, используйте эту функцию для очистки документа для того, чтобы каждый раз не создавать новый:
const clear = () => document.body.innerHTML = ''clear()
1. Активный элемент
Свойство activeElement позволяет получить элемент, находящийся в фокусе.
const input = document.createElement('input')input.setAttribute('type', 'text')input.setAttribute('placeholder', 'Введите свое имя')input.className = 'username'document.body.append(input)input.focus()console.log(document.activeElement)// <input type="text" placeholder="Введите свое имя" class="username">
2. Редактирование страницы
Свойство designMode позволяет редактировать страницу, открытую в браузере.
document.designMode = 'on'

3. Стили элемента
Метод getComputedStyle() позволяет получить стили элемента. Для получения определенного свойства следует использовать getPropertyValue().
// напишем вспомогательную функцию для получения определенного свойства элемента// мы будем использовать ее в нескольких примерахconst getStyle = (element, property) => getComputedStyle(element).getPropertyValue(property)// возьмем инпут из первого примера// и определим его ширину и высотуconst inputWidth = getStyle(input, 'width')const inputHeight = getStyle(input, 'height')console.log(`Ширина: ${inputWidth}\nВысота: ${inputHeight}`)// Ширина: 156.8px// Высота: 16px// позиционируем элемент, используя полученные данные// предположим, что мы собираемся анимировать элемент// поэтому не хотим использовать transform: translate(-50%, -50%)// допустим также, что мы не знаем размеров элемента// поэтому не можем использовать calc(50% - ширина/высота элемента)input.setAttribute('style', `position: absolute; top: calc(50% - ${inputHeight.replace('px', '') / 2}px); left: calc(50% - ${inputWidth.replace('px', '') / 2}px);`)
4. Определение браузера
Объект Navidator, в числе прочего, позволяет получить информацию о браузере пользователя.
let browserconst agent = navigator.userAgentif (agent.indexOf('Google')) { browser = 'Google Chrome'} else if (agent.indexOf('Safari')) { browser = 'Apple Safari'} else if (agent.indexOf('Opera')) { browser = 'Opera'} else if (agent.indexOf('Firefox')) { browser = 'Mozilla Firefox'} else if (agent.indexOf('MSIE')) { browser = 'Microsoft Interner Explorer'}console.log(browser) // Google Chrome// вероятно, в данном случае надо было использовать switchif (browser === 'Google Chrome' || browser === 'Mozilla Firefox') { console.log('ok') // ok} else if (browser === 'Opera' || browser === 'Apple Safari') { console.log('50/50')} else if (browser === 'Microsoft Interner Explorer') { console.log('!ok')}
5. Получение координат
Объект Navigator также позволяет получить информацию о местонахождении пользователя, т.е. его координаты.
const success = position => { // деструктурируем объект const { latitude, longitude, altitude, speed } = position.coords console.log(`${latitude.toFixed(2)}\n${longitude.toFixed(2)}\n${altitude}\n${speed}`) // об этом ниже getCityAndWeather(latitude, longitude)}navigator.geolocation.getCurrentPosition(success)/* 56.90 60.63 null null*/// вот как мы можем использовать полученные данные// определим город пользователя и погодуconst getCityAndWeather = (latitude, longitude) => { // прокси для преодоления CORS const proxy = 'https://cors-anywhere.herokuapp.com/' // данный сервис был куплен Facebook и станет платным в 2021 году const api = `${proxy}https://api.darksky.net/forecast/fd9d9c6418c23d94745b836767721ad1/${latitude}, ${longitude}` fetch(api) .then(response => response.json()) .then(data => { console.log(data) // много всего // получаем город const city = data.timezone // получаем температуру const { temperature, summary } = data.currently // переводим фаренгейт в цельсий const celsius = Math.floor((temperature - 32) * (5 / 9)).toFixed() // выводим результат console.log( `${city}\n${celsius}C\n${summary}` ) /* Asia/Yekaterinburg 15C Overcast */ })}
6. Получение элементов
Как нам получить все элементы DOM? Использовать рекурсию.
const template = `<div> <p> Lorem ispum <span>dolor sit amet</span> </p></div><a href="#">link</a>`document.body.innerHTML = templateconst getElements = element => { for (const i of element.children) { console.log(i.tagName) // 0 -> ! -> false -> ! -> true if (!!i.children.length) { console.log('дочерний элемент') getElements(i) } }}getElements(document.body)/* DIV дочерний элемент P дочерний элемент SPAN A*/
7. Разбор URL
Как нам получить отдельные части URL? Это можно сделать двумя способами.
// с помощью регуляркиconst regex = /(\w+):\/\/([\w.]+)\/(\S*)/const url = 'https://example.com/index.html'const result = url.match(regex)// полный адрес (абсолютный путь), протокол, хост, страницаconsole.log(result[0], result[1], result[2], result[3])// https://example.com/index.html https example.com index.html// с помощью конструктора URLconst url2 = new URL('https://example.com/search?query=fetch&page=2#awesome-page')console.log(url2) // много всегоconst { origin, protocol, host, pathname} = url2console.log( `${origin} ${protocol} ${host} ${pathname}`)// https://example.com https: example.com /search// рекомендую почитать про свойство searchParams// searchParams.get(), searchParams.append(), searchParams.has(), searchParams.delete() и т.д.
8. Позиционирование одного элемента относительно другого
const toCenter = (element, parent) => { element.style.position = 'relative' element.style.left = (parent.clientWidth - element.offsetWidth) / 2 + 'px' element.style.top = (parent.clientHeight - element.offsetHeight) / 2 + 'px'}const div = document.createElement('div')div.setAttribute('style', 'width: 150px; height: 150px; background: red;')document.body.append(div)const div2 = document.createElement('div')div2.setAttribute('style', 'width: 100px; height: 100px; background: green;')div.append(div2)const div3 = document.createElement('div')div3.setAttribute('style', 'width: 50px; height: 50px; background: blue;')div2.append(div3)toCenter(div, document.body)toCenter(div2, div)toCenter(div3, div2)

9. Ширина и высота документа
Как нам получить полную ширину и высоту документа?
const pageWidth = Math.max( document.body.scrollWidth, document.documentElement.scrollWidth, document.body.offsetWidth, document.documentElement.offsetWidth, document.body.clientWidth, document.documentElement.clientWidth)const pageHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight)// один из вариантов использования// определяем центр страницыconst pageCenter = [pageWidth / 2, pageHeight / 2]console.log(pageCenter)// создаем элемент для позиционированияconst p = document.createElement('p')p.textContent = 'Lorem ipsum dolor sit amet'document.body.append(p)p.style.position = 'absolute'// получаем ширину и высоту элемента, используя getStyleconst elementWidth = getStyle(p, 'width').replace('px', '')const elementHeight = getStyle(p, 'height').replace('px', '')// определяем центр элементаconst elementCenter = [elementWidth / 2, elementHeight / 2]console.log(elementCenter)// позиционируем элементp.style.top = pageCenter[1] - elementCenter[1] + 'px'p.style.left = pageCenter[0] - elementCenter[0] + 'px'
10. Координаты элемента в контексте документа
Метод getBoundingClientRect() возвращает размер элемента и его позицию относительно области просмотра.
// возьмем p из предыдущего примераconsole.log(p.getBoundingClientRect()) // много всегоconsole.log( `Отступ сверху => ${p.getBoundingClientRect().top.toFixed()}\nОтступ слева => ${p.getBoundingClientRect().left.toFixed()}`)/* Отступ сверху => 352 Отступ слева => 288*/// создадим два элемента// и определим, в какой части страницы находится каждый из нихconst div = document.createElement('div')div.setAttribute('style', 'width: 100px; height: 100px; background: #222; position: absolute; top: calc(50% - 50px); left: calc(25% - 50px);')document.body.append(div)const div2 = document.createElement('div')div2.setAttribute('style', 'width: 100px; height: 100px; background: #222; position: absolute; top: calc(50% - 50px); left: calc(75% - 50px);')document.body.append(div2)document.querySelectorAll('div').forEach(div => div.addEventListener('click', event => { const x = event.target.getBoundingClientRect().x const width = event.target.getBoundingClientRect().width // расчеты приблизительные x + width < innerWidth / 2 ? console.log('Элемент находится в левой части страницы.') : console.log('Элемент находится в правой части страницы.')}))div.click() // Элемент находится в левой части страницы.div2.click() // Элемент находится в правой части страницы.// определим расстояние между нимиconst distanceBetweenDivs = (div, div2) =>console.log((div2.getBoundingClientRect().x - div.getBoundingClientRect().x + div.getBoundingClientRect().width).toFixed())distanceBetweenDivs(div, div2) // 477
11. Координаты курсора
Как нам получить координаты курсора? Очень просто.
// document.addEventListener('click', ev => console.log(`X => ${ev.clientX}\nY => ${ev.clientY}`))/* X => 348 Y => 304*/// вот как мы можем это использовать// создаем холст и получаем его контекстconst canvas = document.createElement('canvas')document.body.append(canvas)const $ = canvas.getContext('2d')// размер холста - область просмотраcanvas.width = innerWidthcanvas.height = innerHeight// создаем вспомогательную функцию для получения случайного целого числа в заданном диапазонеconst randomInt = (min, max) => Math.floor(min + Math.random() * (max + 1 - min))// создаем вспомогательную функцию для получения случайного цветаconst randomColor = () => `#${((Math.random()*0xfff)<<0).toString(16)}`// давайте порисуем// рисование фигур осуществляется по клику// центр фигуры - место клика// форма фигуры - круг или квадратlet i = 0canvas.addEventListener('click', ev => { $.beginPath() // если i - четное число, то рисуем круг // если нечетное - квадрат if (i % 2 === 0) { // $.arc(x, y, радиус, угол) $.arc(ev.clientX, ev.clientY, randomInt(10, 30), 0, 2 * Math.PI) $.fillStyle = randomColor() $.fill() } else { let randomSize = randomInt(20, 60) $.fillStyle = randomColor() // $.fillRect(x, y, ширина, высота) $.fillRect(ev.clientX - randomSize / 2, ev.clientY - randomSize / 2, randomSize, randomSize) } $.closePath() i++})
Напоследок реализуем функцию рисования определенного количества фигур.
const manyShapes = number => { // очищаем холст $.clearRect(0, 0, canvas.width, canvas.height) for (let i = 0; i < number; i++) { let randomX = randomInt(0, innerWidth) let randomY = randomInt(0, innerHeight) if (i % 2 === 0) { $.beginPath() $.arc(randomX, randomY, randomInt(10, 30), 0, 2 * Math.PI) $.fillStyle = randomColor() $.fill() } else { let randomSize = randomInt(20, 60) $.beginPath() $.rect(randomX, randomY, randomSize, randomSize) $.fillStyle = randomColor() $.fill() } }}manyShapes(100)

Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.
Продолжение следует