87

document身長がいつ変わるかを検出しようとしています。それが終わったら、ページレイアウトを整理するのに役立ついくつかの関数を実行する必要があります。

私は探していませんwindow.onresize。ウィンドウよりも大きいドキュメント全体が必要です。

この変化をどのように観察しますか?

4

8 に答える 8

115

更新(2020年10月):

resizeObserverは素晴らしいAPIです(サポートテーブル

// create an Observer instance
const resizeObserver = new ResizeObserver(entries => 
  console.log('Body height changed:', entries[0].target.clientHeight)
)

// start observing a DOM node
resizeObserver.observe(document.body)

// click anywhere to rnadomize height
window.addEventListener('click', () =>
  document.body.style.height = Math.floor((Math.random() * 5000) + 1) + 'px'
)
click anywhere to change the height


古い答え:

「ハック」ですが、この単純な関数は、要素の高さの変化を(setTimeoutを介して)継続的に「リッスン」し、変化が検出されたときにコールバックを起動します。

ユーザーが行ったアクション(サイズ変更クリックなど)に関係なく要素の高さが変化する可能性があることを考慮することが重要です。したがって、高さの変化の原因を知ることは不可能であるため、すべてを行うことができます。 100%の検出は、間隔の高さチェッカーを配置することです。

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)
  })()
}

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

// DEMO:
document.write("click anywhere to change the height")

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

window.addEventListener('click', function() {
  document.body.style.height = Math.floor((Math.random() * 5000) + 1) + 'px'
})
ライブデモ

于 2013-02-15T18:33:26.813 に答える
27

高さの変化を監視する要素内で幅がゼロのabsolute位置を使用し、その要素でイベントをリッスンできます。例えば:iframeresizecontentWindow

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イベントをリッスンする必要があります( IE8-10で複製されます)。<iframe>contentWindow.resize

これがフィドルです...

于 2017-03-28T22:53:17.503 に答える
12

ちょうど私の2セント。万が一、Angularを使用している場合は、これでうまくいきます。

$scope.$watch(function(){ 
 return document.height();
},function onHeightChange(newValue, oldValue){
 ...
});
于 2015-03-19T17:37:32.373 に答える
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'))

欠点の1つは、現在Chrome / Firefoxのみがサポートされていることですが、いくつかのソリッドポリフィルがあります。これが私が書いたcodepenの例です:

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

于 2020-02-13T02:52:44.427 に答える
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を見つけます。

于 2013-02-14T02:28:45.323 に答える
1

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プロジェクトに独自の関数がある場合は、コードを大幅に削減できます。したがって、関数全体を削除して、その行をたとえばjQueryのようにtrigger置き換えてください。trigger(document.body, 'sizechange');$(document.body).trigger('sizechange');

于 2017-09-15T11:42:39.577 に答える
-1

私はこのように@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);

最小限の変更や他の多くのものを追加することもできます...しかし、これは私のために働いています

于 2019-06-13T12:52:41.903 に答える
-2

コマンドwatch()は、プロパティの変更をチェックします。

このリンクを参照してください。

于 2013-02-14T02:50:28.437 に答える