Javascript 检测文档高度变化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14866775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 18:11:00  来源:igfitidea点击:

Detect Document Height Change

javascriptdomdocument

提问by Steve Robbins

I'm trying to detect when my documentheight changes. Once it does, I need to run a few functions to help organize my page layout.

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

I'm not looking for window.onresize. I need the entire document, which is larger than the window.

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

How do I observe this change?

我如何观察这种变化?

回答by vsync

Although a "hack", this simple function continuously "listens" (through setTimeout) to changes in an element's height and fire a callback when a change was detected.

虽然是“hack”,但这个简单的函数会持续“监听”(通过 setTimeout)元素高度的变化,并在检测到变化时触发回调。

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

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

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


onElementHeightChange(document.body, function(h){
  console.log('Body height changed:', h)
})


// to clear the timer use:
// clearTimeout(document.body.onElementHeightChangeTimer);

// DEMO:
document.write("click anywhere")
window.addEventListener('click', function(){
    document.body.style.height = Math.floor((Math.random()*5000)+1) + 'px'
})

LIVE DEMO

现场演示

回答by Jake

You can use an absolutepositioned iframewith zero width inside the element you want to monitor for height changes, and listen to resizeevents on its contentWindow. For example:

您可以在要监视高度变化的元素内使用宽度为零的absolute定位iframe,并resize在其contentWindow. 例如:

HTML

HTML

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

CSS

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 (using jQuery but could be adapted to pure JS)

JavaScript(使用 jQuery,但可以适应纯 JS)

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

If for whatever reason you have height:100%set on bodyyou'll need find (or add) another container element to implement this on. If you want to add the iframedynamically you'll probably need to use the <iframe>.loadevent to attach the contentWindow.resizelistener. If you want this to work in IE7 as well as browsers, you'll need to add the *zoom:1hack to the container element and also listen to the 'proprietary' resizeevent on the <iframe>element itself (which will duplicate contentWindow.resizein IE8-10).

如果您出于某种原因height:100%设置了此选项,则body需要查找(或添加)另一个容器元素来实现此功能。如果您想iframe动态添加,您可能需要使用该<iframe>.load事件来附加contentWindow.resize侦听器。如果您希望它在 IE7 和浏览器中都能正常工作,您需要将*zoom:1hack添加到容器元素并监听元素本身的 'proprietary'resize事件<iframe>(这将contentWindow.resize在 IE8-10 中重复)。

Here's a fiddle...

这是一个小提琴...

回答by Dan Ochiana

Just my two cents. If by any chance you're using angular then this would do the job:

只有我的两分钱。如果您有机会使用 angular 那么这将完成这项工作:

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

回答by Marc

As mentioned by vsync there is no event but you can use a timer or attach the handler somewhere else:

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

Find the jsfiddle here.

这里找到jsfiddle

回答by Frank Eisenhardt

vsync's answer is completely fine. Just in case you don't like to use setTimeoutand you can use requestAnimationFrame(see support) and of course you are still interested.

vsync 的回答完全没问题。以防万一您不喜欢使用setTimeout并且您可以使用requestAnimationFrame请参阅支持),当然您仍然感兴趣。

In the example below the body gets an extra event sizechange. And every time the height or width of the body changes it is triggered.

在下面的示例中,主体获得了一个额外的事件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

现场演示

The code can be reduced much if you have an own triggerEventfunction in your project. Therefore just remove the complete function triggerand replace the line trigger(document.body, 'sizechange');with for example in jQuery $(document.body).trigger('sizechange');.

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

回答by jpschroeder

Update: 2020

更新:2020

There is now a way to accomplish this using the new ResizeObserver. This allows you to listen to a whole list of elements for when their element changes size. The basic usage is fairly simple:

现在有一种方法可以使用新的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'))

The one downside is that currently there is only support for Chrome/Firefox, but you can find some solid polyfills out there. Here's a codepen example I wrote up:

一个缺点是目前仅支持 Chrome/Firefox,但您可以在那里找到一些可靠的 polyfill。这是我写的一个codepen示例:

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

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

回答by Johan Hoeksma

I'm using @vsync's solution, like this. I'm using it for automatic scroll on a page like twitter.

我正在使用@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);

You can also add a minimum change, and a lot of other things... But this is working for me

您还可以添加最小更改以及许多其他内容......但这对我有用

回答by Marlos Carmo

The command watch() checks any change in a property.

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

See this link.

请参阅此链接