document
身長がいつ変わるかを検出しようとしています。それが終わったら、ページレイアウトを整理するのに役立ついくつかの関数を実行する必要があります。
私は探していませんwindow.onresize
。ウィンドウよりも大きいドキュメント全体が必要です。
この変化をどのように観察しますか?
document
身長がいつ変わるかを検出しようとしています。それが終わったら、ページレイアウトを整理するのに役立ついくつかの関数を実行する必要があります。
私は探していませんwindow.onresize
。ウィンドウよりも大きいドキュメント全体が必要です。
この変化をどのように観察しますか?
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'
})
高さの変化を監視する要素内で幅がゼロの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
イベントをリッスンする必要があります( IE8-10で複製されます)。<iframe>
contentWindow.resize
これがフィドルです...
ちょうど私の2セント。万が一、Angularを使用している場合は、これでうまくいきます。
$scope.$watch(function(){
return document.height();
},function onHeightChange(newValue, oldValue){
...
});
更新: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
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を見つけます。
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');
私はこのように@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);
最小限の変更や他の多くのものを追加することもできます...しかし、これは私のために働いています
コマンドwatch()は、プロパティの変更をチェックします。
このリンクを参照してください。