﷽ Às vezes, é necessário usar iframes ao construir alguns aplicativos da web. Freqüentemente, eles estão ocultos, mas às vezes os iframes também podem ser úteis visíveis.
Para o Node Knockout 2013, trabalhei com o Meteorhacks na caixa de comentários aberta . É como uma alternativa Disqus auto-hospedada. Mantivemos a visualização dos comentários dentro de um iframe para garantir que não colidisse com os estilos principais do site e por motivos de segurança. O sistema de comentários é em tempo real. Portanto, os comentários visíveis mudam com frequência e é necessário que o iframe que contém esses comentários seja redimensionado para evitar barras de rolagem.
Se estivermos na mesma origem, uma das coisas que podemos fazer é verificar continuamente se scrollHeight do corpo do documento do quadro filho muda e atualizar a altura do iframe.
(function (iframe) {
var prevHeight = null;
setInterval(function () {
if(prevHeight!==iframe.contentDocument.body.scrollHeight){
prevHeight = iframe.contentDocument.body.scrollHeight;
iframe.style.height = prevHeight + 'px';
}
});
})(document.getElementById('iframe'));
Por causa das abordagens de segurança adotadas por navegadores da web modernos, isso não funcionará se você tiver o iframe e a janela pai em origens diferentes. Este é um aprimoramento de segurança, não um bug, portanto, não podemos esperar que seja corrigido no futuro.
Se as páginas pertencerem a origens diferentes, a janela pai não terá permissão para acessar informações sobre o conteúdo dentro do iframe. Ficarei assustado se puder e definitivamente evitar o uso de um navegador da web .
Como uma solução de origem cruzada, o que podemos fazer é mover a função que rastreia as alterações de altura para a página carregada dentro do iframe ( assumindo que você pode controlar as páginas de quadro pai e filho ). E use postMessage para atualizar a altura da janela principal. Para manter as coisas mais interessantes, vou usar o mozilla jschannel para organizar as mensagens postMessage.
Primeiro, inclua jschannel adicionando esta tag de script a ambas as páginas (janela pai e página dentro do iframe).
<script src="//cdnjs.cloudflare.com/ajax/libs/jschannel/1.0.0-git-commit1-8c4f7eb/jschannel.min.js"></script>
E este trecho dentro dos scripts de página de quadro filho que cria o jschannel, detecta mudanças na altura do corpo e envia mensagens para a página pai via jschannel.
(function () {
function DO_NOTHING () {}
var channel = null;
var prevHeight = null;
document.addEventListener('DOMContentLoaded', function () {
channel = Channel.build({
window: window.parent
,origin: '*'
,scope: 'test_scope'
});
setInterval(watchDocumentHeight, 250);
})
function watchDocumentHeight() {
if (prevHeight !== document.body.scrollHeight) {
channel.call({
method: 'resize'
,params: document.body.scrollHeight
,success: DO_NOTHING
});
prevHeight = document.body.scrollHeight;
}
}
})();
E este dentro dos scripts da página pai para preparar o jschannel, aguardar mensagens e atualizar a altura.
(function (iframe) {
var channel = null;
document.addEventListener('DOMContentLoaded', function () {
channel = Channel.build({
window: iframe.contentWindow
,origin: '*'
,scope: 'test_scope'
,onReady: onChannelReady
});
})
function onChannelReady () {
channel.bind('resize', onResize);
}
function onResize (trans, data) {
iframe.style.height = data + 'px';
}
})(document.getElementById('iframe'));
Isso tudo é realmente necessário? Podemos tornar o código muito mais curto se usarmos window.postMessage diretamente, mas se você estiver usando iframes, muito provavelmente precisará usar if para mais do que alterar a altura. O Mozilla jschannel pode ajudá-lo quando se trata de organizar canais postMessage.