Иногда нужно отслеживать поведение блочного элемента и при изменении его размеров запускать дополнительный код. Актуально при адаптивной вёрстке или подгрузке контента через AJAX, когда размеры блочного элемента заранее не известны. Например у меня адаптивная вёрстка, нужно чтобы при уменьшении ширины окна некоторые пункты основного горизонтального меню перемещались в дополнительное вертикальное меню, которое открывается при наведении мышкой. В моём случае учитываются border, padding, scrollbar и content блочного элемента, но вы можете изменить код исходя из ваших задач.
P.S. Все браузеры, кроме IE 9 включительно.
P.S. Все браузеры, кроме IE 9 включительно.
<html>
<head>
<meta charset="UTF-8">
</head>
<body onload="javascript:res(0,0,0,0)">
<script type="text/javascript">
function res(width, height, timeout, validation) {
var item = document.getElementById('test_two');
if((width == item.offsetWidth) && (height == item.offsetHeight)) {
if(validation) {
// Сработает при изменении размеров блочного элементов, для тестирования можно раскомментировать нижнюю строку.
// document.getElementById('test').innerHTML = Date();
} else {
timeout = 500;
}
window.setTimeout(res, timeout, width, height, timeout, 0);
} else {
width = item.offsetWidth;
height = item.offsetHeight;
timeout = 200;
window.setTimeout(res, timeout, width, height, timeout, 1);
}
}
</script>
<div id="test"></div>
<div id="test_two"><p>Test JavaScript.</p></div>
</body>
</html>
Поделиться с друзьями
Комментарии (12)
AndreyNagih
13.10.2016 12:16+2На мой взгляд, лучше отслеживать глобальное событие resize, но стартовать обработчик не на каждый тик, а с ограничением количества срабатываний.
Пример: MDN resize
А уже внутри этого обработчика производить необходимые действия на всю разметку.
cyber_ua
13.10.2016 13:53+3И зачем это на хабре? До проверки через timeout даже junior сам дойдет и подобных решений в гугле куча.
Относительно нормальное решение:
let target = document.getElementById(divId); let $target = $(target); let lastHeight = $target.height(); let observer = new MutationObserver(() => { let newHeight = $target.height(); if (lastHeight !== newHeight) { // делаем что то lastHeight = newHeight; } }); observer.observe(target, { attributes: true, subtree: true });
П.с полифил для MutationObserver искать на гитхабе
AHDPEu
По таймеру проверять размеры не лучшее решение.
Можно фрейм кинуть внутрь элемента и подписаться на событие resize
https://codepen.io/AHDPEu/pen/ALvawa
vintage
Фреймы — очень тяжеловесные штуки. Как по памяти так и по времени создания.
AHDPEu
Хорошо, пусть это будет тег object
Ещё надо проверить, что тяжелее по памяти, времени создания и тд, пустой фрейм с одним событием или таймер раз в 200 / 500 мс который опрашивает размеры и тем самым запускает не менее тяжелые операции для браузера.
Так в этом коде нужно добавить проверку, что элемент существует. Получить утечку неопытному программисту проще простого.
AHDPEu
Вообще задача автора решается на чистом css, можно посмотреть примеры многих css фреймворков, где от ширины окна меню прячется под иконку с бургером. Задав каждому элементу max-width одинаковый, можно прятать нужное количество таких элементов и одновременно показывать из в меню под бургер иконкой.
Я сначала подумал, что требуется событие действительно на блочный элемент (например, с position:absolute), а не на окно браузера.
XAKPM
Событие требуется именно на блочный элемент, потому что размеры окна могут не изменится. В моём случае количество элементов меню и ширина каждого элемента заранее не известна, мне не нужно из горизонтального меню делать вертикальное. У меня имеется горизонтальное и вертикальное меню, когда в горизонтальное меню элементы больше не помещается, они перемещаются в вертикальное меню. Я низнаю решения такой задачи с адаптивной вёрсткой на CSS, поэтому предложил такое.
vintage
Если в доме ничего не менялось, то reflow происходить не будет. Браузеры не настолько тупые. А вот фрейм — это полноценное окно с полным фаршем — свой дом, свои js объекты, свои события и тп.