检测文档高度变化

时间:2013-02-14 02:16:19

标签: javascript domdocument

我正试图检测我的document身高何时发生变化。一旦完成,我需要运行一些函数来帮助组织我的页面布局。

我不是在寻找window.onresize。我需要整个文档,它比窗口大。

如何观察此变化?

8 个答案:

答案 0 :(得分:62)

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

答案 1 :(得分:21)

您可以在要监控的元素中使用宽度为零的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 hack添加到容器元素中,并且还要听取专有的&#39; resize元素本身的<iframe>事件(将在IE8-10中复制contentWindow.resize)。

Here's a fiddle ...

答案 2 :(得分:13)

只是我的两分钱。如果您有任何机会使用角度,那么这将完成这项工作:

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

答案 3 :(得分:12)

更新:2020年

现在有了一种使用新的ResizeObserver来完成此操作的方法。这使您可以侦听元素的完整列表,以了解它们的元素何时更改大小。基本用法非常简单:

const observer = new ResizeObserver(entries => {
  for (const entry of entries) {
    // each entry is an instance of ResizeObserverEntry
    console.log(entry.contentRect.height)
  }
})
observer.observe(document.querySelector('body'))

一个缺点是,目前仅支持Chrome / Firefox,但是您可以在其中找到一些固态填充。这是我写的一个Codepen示例:

https://codepen.io/justin-schroeder/pen/poJjGJQ?editors=1111

答案 4 :(得分: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 here

答案 5 :(得分:2)

vsync的答案完全没问题。如果您不想使用setTimeout并且可以使用requestAnimationFramesee support),当然您仍然感兴趣。

在下面的示例中,正文获得了额外的事件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);
})();

A live demo

如果项目中有自己的triggerEvent函数,代码可以减少很多。因此,只需删除完整的函数trigger,然后使用例如jQuery trigger(document.body, 'sizechange');替换行$(document.body).trigger('sizechange');

答案 6 :(得分:0)

我正在使用@vsync的解决方案,就像这样。我正在使用它在Twitter之类的页面上自动滚动。

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);

您还可以添加一个最小的变化,以及许多其他内容...但这对我有用

答案 7 :(得分:-1)

命令watch()检查属性中的任何更改。

请参阅此链接:How to detect when the height of your page changes?