将 html 写入带有回调的 iframe

Write html into iframe with callback

我们正在从后端获取数据,需要将其写入 iframe。我们必须将 iframe 高度设置为内容的高度。在内容实际位于 iframe 之前,我们无法获得正确的高度,这对于大量内容来说不是瞬时的。是否有回调知道写入何时完成?

现在,我们有一个计时器,但它是脆弱的代码:

//data received from backend     
//write data to iframe
//$iframe is a jQuery DOM element 
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();

setTimeout(function (){
    var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
            $iframe.css("height", scrollHeight );
}, 1000);

iframe 确实有一个 onload 事件:

$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();

$iframe.onload = function() {
  var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
  $iframe.css("height", scrollHeight);
};

您是否试过在 iframe 上监听 load 事件?

var doc = $iframe[0].contentDocument
doc.open()
doc.write(data)
doc.close()

$iframe.on('load', function () {
    this.style.height = doc.body.scrollHeight + 'px'
})

也许 postMessage 会对您有所帮助。

var testData = 'test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n';
var $iframe = document.querySelector('#test-iframe');
var $button = document.querySelector('button');

// listen the callback message from iframe
window.self.addEventListener('message', function(ev) {
    if (ev.data && ev.data.status === 'ready') {
        $iframe.style.height = ev.data.height + 'px';
    }
});


$button.addEventListener('click', function() {
    // render content
    $iframe.contentDocument.body.innerText = testData;
    // send message to the top window
    window.self.postMessage({
        status: 'ready',
        height: $iframe.contentDocument.body.scrollHeight
    }, '*');
});
`

https://jsfiddle.net/caoyy/Lb5k13bw/2/

您最好的选择是在 iFrame 中使用 mutationObserver。恐怕这不像回调那么简单。

这是 iFrame-resizer 库用来解决这个问题的代码。您需要更改调用 sendSize 的行来调用您的回调方法。

function setupBodyMutationObserver(){
    function addImageLoadListners(mutation) {
        function addImageLoadListener(element){
            if (false === element.complete) {
                console.log('Attach listeners to ' + element.src);
                element.addEventListener('load', imageLoaded, false);
                element.addEventListener('error', imageError, false);
                elements.push(element);
            }
        }

        if (mutation.type === 'attributes' && mutation.attributeName === 'src'){
            addImageLoadListener(mutation.target);
        } else if (mutation.type === 'childList'){
            Array.prototype.forEach.call(
                mutation.target.querySelectorAll('img'),
                addImageLoadListener
            );
        }
    }

    function removeFromArray(element){
        elements.splice(elements.indexOf(element),1);
    }

    function removeImageLoadListener(element){
        console.log('Remove listeners from ' + element.src);
        element.removeEventListener('load', imageLoaded, false);
        element.removeEventListener('error', imageError, false);
        removeFromArray(element);
    }

    function imageEventTriggered(event,type,typeDesc){
        removeImageLoadListener(event.target);
        sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined);
    }

    function imageLoaded(event) {
        imageEventTriggered(event,'imageLoad','Image loaded');
    }

    function imageError(event) {
        imageEventTriggered(event,'imageLoadFailed','Image load failed');
    }

    function mutationObserved(mutations) {
        sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type);

        //Deal with WebKit asyncing image loading when tags are injected into the page
        mutations.forEach(addImageLoadListners);
    }

    function createMutationObserver(){
        var
            target = document.querySelector('body'),

            config = {
                attributes            : true,
                attributeOldValue     : false,
                characterData         : true,
                characterDataOldValue : false,
                childList             : true,
                subtree               : true
            };

        observer = new MutationObserver(mutationObserved);

        console.log('Create body MutationObserver');
        observer.observe(target, config);

        return observer;
    }

    var
        elements         = [],
        MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
        observer         = createMutationObserver();

    return {
        disconnect: function (){
            if ('disconnect' in observer){
                console.log('Disconnect body MutationObserver');
                observer.disconnect();
                elements.forEach(removeImageLoadListener);
            }
        }
    };
}