Иногда нужно отслеживать поведение блочного элемента и при изменении его размеров запускать дополнительный код. Актуально при адаптивной вёрстке или подгрузке контента через AJAX, когда размеры блочного элемента заранее не известны. Например у меня адаптивная вёрстка, нужно чтобы при уменьшении ширины окна некоторые пункты основного горизонтального меню перемещались в дополнительное вертикальное меню, которое открывается при наведении мышкой. В моём случае учитываются border, padding, scrollbar и content блочного элемента, но вы можете изменить код исходя из ваших задач.

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)


  1. AHDPEu
    13.10.2016 12:14
    +2

    По таймеру проверять размеры не лучшее решение.
    Можно фрейм кинуть внутрь элемента и подписаться на событие resize

    https://codepen.io/AHDPEu/pen/ALvawa


    1. vintage
      13.10.2016 12:18

      Фреймы — очень тяжеловесные штуки. Как по памяти так и по времени создания.


      1. AHDPEu
        13.10.2016 12:24
        +2

        Хорошо, пусть это будет тег object
        Ещё надо проверить, что тяжелее по памяти, времени создания и тд, пустой фрейм с одним событием или таймер раз в 200 / 500 мс который опрашивает размеры и тем самым запускает не менее тяжелые операции для браузера.

        Так в этом коде нужно добавить проверку, что элемент существует. Получить утечку неопытному программисту проще простого.


        1. AHDPEu
          13.10.2016 12:47

          Вообще задача автора решается на чистом css, можно посмотреть примеры многих css фреймворков, где от ширины окна меню прячется под иконку с бургером. Задав каждому элементу max-width одинаковый, можно прятать нужное количество таких элементов и одновременно показывать из в меню под бургер иконкой.

          Я сначала подумал, что требуется событие действительно на блочный элемент (например, с position:absolute), а не на окно браузера.


          1. XAKPM
            16.10.2016 05:52

            Событие требуется именно на блочный элемент, потому что размеры окна могут не изменится. В моём случае количество элементов меню и ширина каждого элемента заранее не известна, мне не нужно из горизонтального меню делать вертикальное. У меня имеется горизонтальное и вертикальное меню, когда в горизонтальное меню элементы больше не помещается, они перемещаются в вертикальное меню. Я низнаю решения такой задачи с адаптивной вёрсткой на CSS, поэтому предложил такое.


        1. vintage
          13.10.2016 13:29

          Если в доме ничего не менялось, то reflow происходить не будет. Браузеры не настолько тупые. А вот фрейм — это полноценное окно с полным фаршем — свой дом, свои js объекты, свои события и тп.


  1. AndreyNagih
    13.10.2016 12:16
    +2

    На мой взгляд, лучше отслеживать глобальное событие resize, но стартовать обработчик не на каждый тик, а с ограничением количества срабатываний.
    Пример: MDN resize
    А уже внутри этого обработчика производить необходимые действия на всю разметку.


    1. XAKPM
      13.10.2016 12:54

      https://habrahabr.ru/post/312536/#comment_9857266


  1. Methos
    13.10.2016 12:27

    window.resize нужно делать в вашем случае.


    1. XAKPM
      13.10.2016 12:49

      Я не зря сделал акцент, что отслеживаем размеры блочного элемента, потому что window.resize может не изменится.


  1. Demetros
    13.10.2016 13:00

    https://github.com/marcj/css-element-queries


  1. 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 искать на гитхабе