Доброго времени суток, друзья!
В этой статье я хочу поделиться с Вами некоторыми находками, сделанными мной в процессе изучения 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. Определение браузера
Несмотря на наличие свойства userAgent объекта Navigator, получить корректную информацию о браузере пользователя не так-то просто. Решения типа
if (navigator.userAgent.indexOf())
или if (navigator.userAgent.search())
не работают. Одним из работоспособных решений является использование библиотеки Detect.js. Скачиваем detect.min.js и подключаем его в head.const ua = detect.parse(navigator.userAgent)
console.log(`${ua.os.family}\n${ua.browser.family}`)
/*
Windows 8.1
Chrome
*/
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
15°C
Overcast
*/
})
}
6. Получение элементов
Как нам получить все элементы DOM? Использовать рекурсию.
const template =
`<div>
<p> Lorem ispum
<span>dolor sit amet</span>
</p>
</div>
<a href="#">link</a>`
document.body.innerHTML = template
const 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
// с помощью конструктора URL
const url2 = new URL('https://example.com/search?query=fetch&page=2#awesome-page')
console.log(url2) // много всего
const {
origin,
protocol,
host,
pathname
} = url2
console.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'
// получаем ширину и высоту элемента, используя getStyle
const 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 = innerWidth
canvas.height = innerHeight
// создаем вспомогательную функцию для получения случайного целого числа в заданном диапазоне
const randomInt = (min, max) => Math.floor(min + Math.random() * (max + 1 - min))
// создаем вспомогательную функцию для получения случайного цвета
const randomColor = () => `#${((Math.random()*0xfff)<<0).toString(16)}`
// давайте порисуем
// рисование фигур осуществляется по клику
// центр фигуры - место клика
// форма фигуры - круг или квадрат
let i = 0
canvas.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)
Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.
Продолжение следует…
yarkov
Мда…