artDialog組件與iframe


背景

  組件官網。 未用過的朋友可以先了解下。

  當Content參數傳遞html元素時,官方的解釋是:

備注:1、元素不是復制而是完整移動到對話框中,所以原有的事件與屬性都將會保留 2、如果隱藏元素被傳入到對話框,會設置display:block屬性顯示該元素 3、對話框關閉的時候元素將恢復到原來在頁面的位置,style display屬性也將恢復

  如果說該元素是頁面本身,最終顯示的載體也是頁面本身,那么沒有任何問題。但在使用了iframe下會有個奇怪的問題,當元素為iframe時,在chrome下,frame會重新加載一次。

問題現象

  先看top.html代碼。

    <iframe id="ff" src="child1.html"></iframe>
    <input type="button" onclick="fn()" value="彈出黃色Frame(在Chrome下frame會重新加載一次,所以值丟失了)" />
    <script>
        function fn() {
            $.dialog({
                title: '測試',
                content: document.getElementById("ff")
            });
        }
    </script>

  child1頁面上有個輸入框,每次加載時會顯示重新加載。我們可以在里面輸入,會發現點擊button后,IE(本機IE8)下正常,輸入的值未丟失。在Chrome下frame會被重新加載一次,導致輸入的值丟失了。

  這樣帶來的問題是:init事件則有問題。init是在對話框彈出后會執行的函數,我們希望在彈出一個frame后,加載frame的數據等,而此時init函數就不能發揮作用。既然是iframe重新加載了,導致了這個問題,那么init的執行時機應該是當frame加載完畢后,再調用init事件。通過一翻搜索,找到兼容各種瀏覽器監聽iframe加載完畢的代碼:

 thisFrame.onload = thisFrame.onreadystatechange = function () {
                    if (this.readyState && this.readyState != 'complete') return;
                    thisFrame.onload = _top.frames[config.content.name].onreadystatechange = null;
                    //執行方法
                };

  於是我修改init的事件則為: 

if(webkit){ //若是chrome
 thisFrame.onload = thisFrame.onreadystatechange = function () {
                    if (this.readyState && this.readyState != 'complete') return;
                    thisFrame.onload = _top.frames[config.content.name].onreadystatechange = null;
                    //執行方法
                };
}
else{
//執行方法
}

  到這里問題算是基本上解決了。

進一步處理

  首先解釋下為什么要使用frame。

  對話框需要穿越。例如主頁top.html,有個frame專門用來顯示具體的內容。某個內容頁需要彈出數據的詳情對話框,而且該對話框里面在top頂部,所以使用了artDialog提供的穿越機制,它可以直接將元素顯示top頁面的最上方。但由於artDialog的做法是將元素完整移動,所以如果是普通的div,該div又引用了很多js,穿越后會出問題,相應的事件會提示缺少js。

  當然如果把這個div需要的js或css一律拷貝到top頁面上,是沒有問題的,但這樣肯定不好。所以我使用了iframe,相關的js和css都在frame內部,故不存在穿越后缺少js或者css問題。

  這也引出了我自己的需求,希望在顯示穿越對話框並且元素為frame時,init事件能被順利加載

  上面的初步解決,雖然達到了目的,但是如果每個調用的地方都這么寫,會不會有點郁悶。所以我改寫了iframeTools.js文件下的through方法,做了這樣一個判斷,請看:

    artDialog.through = _proxyDialog = function () {
        var config = arguments[0];
        //檢測元素是否是frame,如果是,init的執行時機則必須保證在iframe加載完畢后,在chrome模式下,彈出frame元素會導致frame重新加載
        if (config.init && config.content.tagName && config.content.tagName == 'IFRAME' && webkit) {
            var tmpfn = config.init;
            arguments[0].init = function () {
                var thisFrame = _top.frames[config.content.name];
                thisFrame.onload = thisFrame.onreadystatechange = function () {
                    if (this.readyState && this.readyState != 'complete') return;
                    thisFrame.onload = _top.frames[config.content.name].onreadystatechange = null;
                    tmpfn();
                };
            }
        }
        var api = _topDialog.apply(this, arguments);
        // 緩存從當前 window(可能為iframe)調出所有跨框架對話框,
        // 以便讓當前 window 卸載前去關閉這些對話框。
        // 因為iframe注銷后也會從內存中刪除其創建的對象,這樣可以防止回調函數報錯
        if (_top !== window) artDialog.list[api.config.id] = api;
        return api;
    };

  代碼增加了一個判斷,如果through時定義了init,content是frame,並在webkit核心瀏覽器下,將init方法套一層監聽frame加載。

 

  最后一點疑惑,為什么artDialog彈出frame元素時,在chrome下會重新加載一次。希望使用artDialog的朋友告知一下,謝謝!

測試代碼

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM