Подтвердить что ты не робот

Обнаружение изменения высоты документа

Я пытаюсь определить, когда изменяется высота document. Как только это произойдет, мне нужно запустить несколько функций, чтобы помочь организовать макет страницы.

Я не ищу window.onresize. Мне нужен весь документ, который больше окна.

Как я могу наблюдать это изменение?

4b9b3361

Ответ 1

function onElementHeightChange(elm, callback){
    var lastHeight = elm.clientHeight, newHeight;
    (function run(){
        newHeight = elm.clientHeight;
        if( lastHeight != newHeight )
            callback();
        lastHeight = newHeight;

        if( elm.onElementHeightChangeTimer )
            clearTimeout(elm.onElementHeightChangeTimer);

        elm.onElementHeightChangeTimer = setTimeout(run, 200);
    })();
}


onElementHeightChange(document.body, function(){
    alert('Body height changed');
});

LIVE DEMO

Ответ 2

Вы можете использовать absolute расположенный iframe с нулевой шириной внутри элемента, который вы хотите отслеживать для изменений высоты, и слушать resize события на своем contentWindow. Например:

HTML

<body>
  Your content...
  <iframe class="height-change-listener" tabindex="-1"></iframe>
</body>

CSS

body {
  position: relative;
}
.height-change-listener {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  height: 100%;
  width: 0;
  border: 0;
  background-color: transparent;
}

JavaScript (с использованием jQuery, но может быть адаптирован к чистому JS)

$('.height-change-listener').each(function() {
  $(this.contentWindow).resize(function() {
    // Do something more useful
    console.log('doc height is ' + $(document).height());
  });
});

Если по какой-либо причине у вас есть height:100%, установленный на body, вам понадобится найти (или добавить) другой элемент контейнера для его реализации. Если вы хотите добавить iframe динамически, вам, вероятно, понадобится использовать событие <iframe>.load для подключения слушателя contentWindow.resize. Если вы хотите, чтобы это работало в IE7, а также в браузерах, вам нужно добавить хакер *zoom:1 к элементу контейнера, а также прослушать "проприетарное" событие resize самого элемента <iframe> (который будет duplicate contentWindow.resize в IE8-10).

Здесь скрипка...

Ответ 3

Просто мои два цента. Если вы случайно используете angular, то это выполнит задание:

$scope.$watch(function(){ 
 return document.height();
},function onHeightChange(newValue, oldValue){
 ...
});

Ответ 4

Как упоминалось vsync, нет события, но вы можете использовать таймер или присоединить обработчик где-то еще:

// get the height
var refreshDocHeight = function(){
    var h = $(document).height();
    $('#result').html("Document height: " + h);
};

// update the height every 200ms
window.setInterval(refreshDocHeight, 200);

// or attach the handler to all events which are able to change 
// the document height, for example
$('div').keyup(refreshDocHeight);

Найдите jsfiddle здесь.

Ответ 5

Ответ vsync полностью прекрасен. На всякий случай вам не нравится использовать setTimeout, и вы можете использовать requestAnimationFrame (см. Поддержку), и, конечно же, вы все еще интересно.

В приведенном ниже примере тело получает дополнительное событие sizechange. И каждый раз, когда изменяется высота или ширина тела, он срабатывает.

(function checkForBodySizeChange() {
    var last_body_size = {
        width: document.body.clientWidth,
        height: document.body.clientHeight
    };

    function checkBodySizeChange()
    {
        var width_changed = last_body_size.width !== document.body.clientWidth,
            height_changed = last_body_size.height !== document.body.clientHeight;


        if(width_changed || height_changed) {
            trigger(document.body, 'sizechange');
            last_body_size = {
                width: document.body.clientWidth,
                height: document.body.clientHeight
            };
        }

        window.requestAnimationFrame(checkBodySizeChange);
    }

    function trigger(element, event_name, event_detail)
    {
        var evt;

        if(document.dispatchEvent) {
            if(typeof CustomEvent === 'undefined') {
                var CustomEvent;

                CustomEvent = function(event, params) {
                    var evt;
                    params = params || {
                        bubbles: false,
                        cancelable: false,
                        detail: undefined
                    };
                    evt = document.createEvent("CustomEvent");
                    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
                    return evt;
                };

                CustomEvent.prototype = window.Event.prototype;

                window.CustomEvent = CustomEvent;
            }

            evt = new CustomEvent(event_name, {"detail": event_detail});

            element.dispatchEvent(evt);
        }
        else {
            evt = document.createEventObject();
            evt.eventType = event_name;
            evt.eventName = event_name;
            element.fireEvent('on' + event_name, evt);
        }
    }

    window.requestAnimationFrame(checkBodySizeChange);
})();

Живая демонстрация

Код может быть значительно уменьшен, если в вашем проекте есть собственная функция triggerEvent. Поэтому просто удалите полную функцию trigger и замените строку trigger(document.body, 'sizechange'); на, например, в jQuery $(document.body).trigger('sizechange');.

Ответ 6

Я использую решение @vsync, вот так. Я использую его для автоматической прокрутки на странице, как твиттер.

const scrollInterval = (timeInterval, retry, cb) => {
    let tmpHeight = 0;
    const myInterval = setInterval(() => {
        console.log('interval');
        if (retry++ > 3) {
            clearInterval(this);
        }
        const change = document.body.clientHeight - tmpHeight;
        tmpHeight = document.body.clientHeight;
        if (change > 0) {
            cb(change, (retry * timeInterval));
            scrollBy(0, 10000);
        }
        retry = 0;
    }, timeInterval);
    return myInterval;
};

const onBodyChange = (change, timeout) => {
    console.log('document.body.clientHeight, changed: ${change}, after: ${timeout}');
}

const createdInterval = scrollInterval(500, 3, onBodyChange);

// stop the scroller on some event
setTimeout(() => {
    clearInterval(createdInterval);
}, 10000);

Вы также можете добавить минимальное изменение и многое другое... Но это работает для меня