2017-06-29 101 views
0

我試圖儘快將iframe元素添加到document.body中。爲什麼document.body與我的readyState邏輯?

錯誤報告會在所有4級主要的瀏覽器(Chrome瀏覽器,Safari瀏覽器,FF,IE├57類版本)進來,我們看到的是document.bodynull。我認爲這發生在我的JS文件緩存並加載很快。

這裏是插入的邏輯iframe

private loadIFrame(): void { 
    switch (document.readyState) { 
    case 'uninitialized': 
    case 'loading': 
    case 'loaded': 
     window.addEventListener('DOMContentLoaded', 
     this.appendIFrame.bind(this) 
    ) 
     break 
    case 'interactive': 
    case 'complete': 
    default: 
     this.appendIFrame() 
    } 
} 

private appendIFrame(): void { 
    if (document.getElementById('iframeId')) { 
    return 
    } 

    let iFrame: HTMLIFrameElement = document.createElement('iframe') 
    iFrame.src = document.location.protocol + this.ORIGIN + '/iframe.html' 
    iFrame.id = 'iframeId' 

    // document.body is null here 
    document.body.appendChild(iFrame) 
} 

我有一個很難在一個乾淨的環境,這讓我猜測這是如何發生在野外再現問題。

我原本試過這個rreadyState邏輯,但是我們在loading狀態下看到document.bodyundefined

private loadIFrame(): void { 
    switch (document.readyState) { 
    case 'uninitialized': 
    case 'loading': 
     window.addEventListener('DOMContentLoaded', 
     this.appendIFrame.bind(this) 
    ) 
     break 
    case 'loaded': 
    case 'interactive': 
    case 'complete': 
    default: 
     this.appendIFrame() 
    } 
} 

我現在質疑的行....

  1. 是問題的default情況?我應該在那裏添加事件監聽器嗎?我可以修改案例的順序,以便事件偵聽器是默認的?
  2. 是否有可能bodynullDOMContentLoaded事件?
  3. 是否有可能有其他值document.readyState正在通過?
+0

添加幾個參考。我相信DOMContentLoaded是當身體是保證被定義最早的時間正確的事件:https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded 同時,認識到並不是所有的瀏覽器使用所有5個readStates。最新的標準只有3個:https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState – theUtherSide

+0

這裏是具有「未初始化」和「加載」狀態爲IE設計的參考。對我來說,這表明body在「已加載」狀態下不可用,因爲解析不完整。 https://msdn.microsoft.com/zh-cn/library/ms534359(v=vs.85).aspx – theUtherSide

回答

0

我更新的邏輯,我能幾乎消除錯誤,但我仍然看到document.bodynullreadyStateinteractive

一旦我評估導致問題的特定瀏覽器場景,我將更新此帖子。

private loadIFrame(): void { 
    switch (document.readyState) { 
    case 'uninitialized': 
    case 'loading': 
    case 'loaded': 
     document.addEventListener('DOMContentLoaded', 
     this.appendIFrame.bind(this) 
    ) 
     break 
    case 'interactive': 
    case 'complete': 
    default: 
     if(document.body) { 
     this.appendIFrame() 
     } else { 
     window.addEventListener('load', 
      this.appendIFrame.bind(this) 
     ) 
     } 
    } 
} 
1

首先,如果你已經檢查readyState並確定它是loaded,那麼你爲什麼要設置爲已經過去的時刻(DOMContentLoaded)的事件處理程序?

你可能只是做:

private loadIFrame(): void { 
    switch (document.readyState) { 
    case 'uninitialized': 
    case 'loading': 
    case 'loaded': 
     this.appendIFrame.bind(this); 
     break; 
    case 'interactive': 
    case 'complete': 
    default: 
     this.appendIFrame(); 
    } 
} 

接下來,事件處理程序的註冊是錯誤的。有3個參數.addEventListener()和第三可以是兩個值之一:

  1. 事件名稱(字符串)
  2. 回調函數(參考或內聯函數)

    3a中。是否勾選捕獲階段(布爾型 - 默認爲false

    3b。一個Options對象來配置特性(對象)

而且,addEventListener()本身被稱爲將接收事件(window在這種情況下)的對象。

它應該是:

window.addEventListener('DOMContentLoaded', function(){ 
     this.appendIFrame.bind(this); 
    }); 

而且(僅供參考),你真的應該手動插入你的聲明分號結束,而不是依賴於自動插入,因爲有特殊的情況,導致錯誤。

+0

非常感謝您的意見!我的實際代碼使用了一個跨瀏覽器的包裝方法,我剛剛加強了參數的翻譯。我試圖簡化這篇文章。 – theUtherSide

+0

同樣,我們不使用ASI,而是將TypeScript轉換成ES5,所以源代碼沒有分號,但是分佈式代碼的確如此。 – theUtherSide

+0

@theUtherSide儘管如此,你似乎是試圖在你確定該事件已經發生後對事件進行處理。我的第一個代碼示例適合你嗎? –