J'essaie de détecter quand ma document
hauteur change. Une fois que c'est fait, je dois exécuter quelques fonctions pour aider à organiser ma mise en page.
Je ne cherche pas window.onresize
. J'ai besoin de tout le document, qui est plus grand que la fenêtre.
Comment puis-je observer ce changement?
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');
});
Vous pouvez utiliser un absolute
positionné iframe
avec une largeur nulle à l'intérieur de l'élément que vous souhaitez surveiller pour les changements de hauteur et écouter les événements resize
sur ses contentWindow
. Par exemple:
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 (utilisant jQuery mais pouvant être adapté à JS pur)
$('.height-change-listener').each(function() {
$(this.contentWindow).resize(function() {
// Do something more useful
console.log('doc height is ' + $(document).height());
});
});
Si pour une raison quelconque vous avez height:100%
mis sur body
vous aurez besoin de trouver (ou d’ajouter) un autre élément conteneur pour l’implémenter Si vous voulez ajouter le iframe
de manière dynamique, vous devrez probablement utiliser le <iframe>.load
événement pour attacher le contentWindow.resize
auditeur. Si vous voulez que cela fonctionne dans IE7 ainsi que dans les navigateurs, vous devrez ajouter le *zoom:1
hackez l'élément conteneur et écoutez également l'événement 'propriétaire' resize
sur le <iframe>
élément lui-même (qui dupliquera contentWindow.resize
dans IE8-10).
Voici un violon ...
Juste mes deux cents. Si par hasard vous utilisez angular, alors cela ferait l'affaire:
$scope.$watch(function(){
return document.height();
},function onHeightChange(newValue, oldValue){
...
});
Comme mentionné par vsync, il n'y a pas d'événement mais vous pouvez utiliser une minuterie ou attacher le gestionnaire ailleurs:
// 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);
Trouvez le jsfiddle ici .
la réponse de vsync est tout à fait correcte. Juste au cas où vous n'aimeriez pas utiliser setTimeout
et que vous puissiez utiliser requestAnimationFrame
( voir support ) et bien sûr que vous êtes toujours intéressé.
Dans l'exemple ci-dessous, le corps obtient un événement supplémentaire sizechange
. Et chaque fois que la hauteur ou la largeur du corps change, elle est déclenchée.
(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);
})();
Le code peut être beaucoup réduit si vous avez une propre fonction triggerEvent
dans votre projet. Il suffit donc de supprimer la fonction complète trigger
et de remplacer la ligne trigger(document.body, 'sizechange');
par, par exemple, dans jQuery $(document.body).trigger('sizechange');
.
J'utilise la solution de @ vsync, comme ceci. Je l'utilise pour le défilement automatique sur une page telle que 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);
Vous pouvez également ajouter un minimum de changement, et beaucoup d'autres choses ... Mais cela fonctionne pour moi