DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> WEB網站前端 >> 關於網頁技巧 >> 網頁技巧:三談iFrame框架自適應高度
網頁技巧:三談iFrame框架自適應高度
編輯:關於網頁技巧     

為什麼是三談

為什麼是三談呢?一是因為這真的是一個被說爛的話題,二是因為太師傅在n年前就寫過這篇再談iframe自適應高度。之所以再提該問題,是因為之前項目中確實遇到了這個問題的方方面面,有必要總結一下。希望對各位有幫助,有錯誤請指正。

同域、子頁面高度不會動態增加

這種情況最簡單,直接通過腳本獲取字頁面實際高度,修改iframe元素高度即可。但有二點必須注意:

  1. 如果頁面內有絕對定位或者沒有清浮動的元素,情況有些復雜,不同浏覽器處理結果不同,甚至包括Webkit內核的浏覽器,具體請看這個Demo。所以你要麼進行浏覽器檢測,要麼用Math.max計算一個最大值,要麼你想別的方法。
  2. iframe所包含頁面可能非常大,需要很長的加載時間,為此直接計算高度的時候,很可能頁面還沒下載完,高度計算就會有問題。所以最好在iframeonload事件中計算高度。這裡還要注意的是,IE下必須使用微軟事件模型obj.attachEvent來綁定onload事件。而別的浏覽器直接obj.onload = function(){}也可以。

(function(){
    var frame = document.getElementById("frame_content_parent"),
        setIframeHeight = function(){
            var frameContent = frame.contentWindow.document,
                frameHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);

            frame.height = frameHeight;
        };
    if(frame.addEventListener){
        frame.addEventListener("load",setIframeHeight,false);
    }else{
        frame.attachEvent("onload",setIframeHeight);
    }
})();

 

同域、子頁面高度會動態增加

原理與第一種情況一樣,多一個計時器,一直檢測字頁面高度,當子頁面高度和iframe的高度不一致時,重新設置iframe的高度。這邊也可以加一個try在js出錯時,加一個足夠的高度。

 


(function(){
    var _reSetIframe = function(){
        var frame = document.getElementById("frame_content_parent")
        try {
            var frameContent = frame.contentWindow.document,
                bodyHeight = Math.max(frameContent.body.scrollHeight,frameContent.documentElement.scrollHeight);
            if (bodyHeight != frame.height){
                frame.height = bodyHeight;
            }
        }
        catch(ex) {
            frame.height = 1800;
        }
    }
    if(frame.addEventListener){
        frame.addEventListener("load",function(){setInterval(_reSetIframe,200);},false);
    }else{
        frame.attachEvent("onload",function(){setInterval(_reSetIframe,200);});
    }
})();

 

同域、子頁面高度會動態增加、腳本可能完全失效

第二個例子中,考慮到了腳本出錯的情況,但是萬一腳本根本不執行了呢,那iframe中的內容就會因為iframe的高度不夠而顯示不了。為此我們通常事先設置一個足夠的高度,為了前端控制方便,我覺得寫在CSS文件中比較合適,需要修改時只改CSS就行了。這裡我設置了selector{ height:1800px; }。需要注意的是,寫在樣式表裡的樣式,不能直接用node.style[property]來取,對於微軟模型,要用node.currentStyle[property](題外話:悲劇的IE模型不支持CSS偽類),對於W3C模型,要用window.getComputedStyle(node,null)[property]來取。我這裡圖方便直接用了YUI。

這裡又有一個問題,設置iframe的高度大於其包含頁面的高度時,各個浏覽器的處理不一樣。例如在Firefox下,必須計算body元素的高度,而html元素的高度等於iframe的高度,然而當恰巧這個頁面又有絕對定位、未清浮動元素時,又不能通過body元素來取,顯然第一種方法缺點更小一些。具體請看這個Demo。

從上面這個Demo可以看到,除IE浏覽器外,別的浏覽器計算出來的都是iframe的高度,即CSS裡設置的#frame_content_parent{ height:1800px; }。而IE計算出來的是iframe所引用頁面的實際高度。

 


#frame_content_parent{ height:1800px; }

 


(function(){
    var $ = YAHOO.util.Dom,
        frame = $.get("frame_content_parent");
    function reSetIframe(){
        var frameContent = frame.contentWindow.document,
            bodyHeight = Math.max(frameContent.documentElement.scrollHeight,frameContent.body.scrollHeight);
        if (bodyHeight != $.getStyle(frame, "height")){
            $.setStyle(frame, "height", bodyHeight + "px");
        }
    }
    if(frame){
        $.setStyle(frame,"height","auto");
        setInterval(reSetIframe,300);
    }
})();

 

跨域

這裡提供一個Iframe代理的方法,簡單地說一下原理。假設有3個頁面,分別是主頁面A.html,字頁面B.html,代理頁面C.html。其中A與B是跨域的,而A和C是同域的。它們的關系:A包含B,B包含C。很顯然A和B,以及B和C,因為跨域不能相互通信,而A和C同域,可以相互通信。為此我們就想到讓C頁面告訴A頁面,B頁面到底有多少高。因為B和C也是跨域的不能相互通信,所以想在C頁面中,直接window.parent.document.body.scrollHeight這樣是行不通的,所以我們只能讓B頁面自己計算自身的高度,然後通過某種方法告訴C頁面,再由C頁面告訴A頁面。這裡的一個方法就是在B頁面生成一個Iframe節點,然後設置它的src屬性,在這個地址上附加一個參數,即B頁面計算出來的高度,然後C頁面就可以通過window.location獲取這個地址欄中的地址,提取出高度值,通過window.top找到A頁面,設置A頁面的Iframe的高度。基本的原理就是這樣,看代碼吧:

DEMO


//B頁面腳本
//任務:計算其實際高度,然後生成一個iframe節點,將高度作為代理頁面C的地址的一部分賦值給Src屬性
(function(){
    var agent_iframe = document.createElement("iframe"),
        b_height = Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
    agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe_once.html#" + b_height;
    document.body.appendChild(agent_iframe);
    agent_iframe.style.display = "none";
})();

 


//C頁面腳本
//任務:獲取請求地址中的高度值,將其賦值給A頁面的Iframe的高度
window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);

 

跨域、字頁面高度動態變化

這裡結合了第2、第4兩種方法,我的想法是在B頁面通過一個計時器,不停計算B頁面的高度,一但變化,馬上修改iframe標簽的src屬性,而C頁面也有計時器不斷監聽src的變化,改變Aiframe標簽的高度。需要注意的是僅僅修改src屬性後面的錨點值(如“#1234”),頁面並不會刷新,不會重新請求,這也是在C頁面增加計時器的原因。

DEMO


//B頁面腳本
(function(){
    var getHeight = function(){
        return Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
    };

    var preHeight = getHeight(),
        agent_iframe;

    var createIframe = function(height){
        agent_iframe = document.createElement("iframe");
        agent_iframe.style.height = "0";
        agent_iframe.style.width = "0";
        agent_iframe.style.border = "none";
        agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + height;
        document.body.appendChild(agent_iframe);
    }

    createIframe(preHeight);

    var checkHeight = function(){
        var currentHeight = getHeight();
        if(currentHeight != preHeight){
            agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html#" + currentHeight;
            preHeight = currentHeight;
        }
        setTimeout(checkHeight,500);
    }

    setTimeout(checkHeight,500);
})();

 


//C頁面腳本
(function(){
    var preHeight = parseInt(window.location.hash.substring(1),10),
        ifrmae = window.top.document.getElementById("frame_content_parent");

    ifrmae.height = preHeight;
    setInterval(function(){
        var newHeight = parseInt(window.location.hash.substring(1),10);
        if (newHeight !== preHeight){
            ifrmae.height = newHeight;
            preHeight = newHeight;
        }
    },500);
})();

 

這裡還有另一種方案,就是讓iframe每一次都重新請求,這樣C頁面就不需要計時器了,但是如果2次計算高度重復的話,就會導致src屬性的值相同,這樣浏覽器就很可能不重新請求該頁面了,那麼C頁面中的腳本也就不運行了。要修復這個問題很簡單,只要在每次計算出來的src屬性上增加一個隨機數的參數就行了。比如http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?temp=123123423712937#1563


//B頁面關鍵腳本
agent_iframe.src = "http://demo.zhouqicf.com/js/2010/iframe_height/agent_iframe.html?a=" + Math.random() + "#" + currentHeight;

 


//C頁面腳本
window.top.document.getElementById("frame_content_parent").height = parseInt(window.location.hash.substring(1),10);

 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved