DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> 讓 innerHTML 進來的 script 代碼跑起來
讓 innerHTML 進來的 script 代碼跑起來
編輯:JavaScript基礎知識     

今天來簡單聊聊如何讓 innerHTML 進來的 script 代碼跑起來的問題。

前台請求一個接口,接口返回一些 HTML 標簽拼接成的字符串,以供前端直接 innerHTML 生成 DOM 元素,這樣的做法非常普遍。但是你是否遇到過,如果字符串中拼接的 HTML 標簽中有 script 標簽,那麼該段腳本是無法執行的,這並不是 bug,而是 w3c 的文檔規定的。

比如如下這段代碼,innerHTML 插入的腳本(alert)並不會執行:

<div id="myDiv">
</div>

<script>
  // 模擬接口返回數據
  var strVar = "";
    strVar += "<script>alert('hello world')<\/script>";

  document.getElementById('myDiv').innerHTML = strVar;
</script>

那麼問題來了,如何使得 innerHTML 進來的 script 代碼能夠跑起來?

方案一:重新構造 script 標簽

思路非常簡單,構造新的 script 標簽,然後該標簽的 innerHTML 賦值為需要渲染的腳本。偽代碼如下:

var s = document.createElement('script');
s.innerHTML = text;
document.body.appendChild(s);

當然如果要寫的完美一點,執行完 s 後還需要 remove 掉。如何獲取 text 值?兩個方法,其一可以正則匹配 strVal,提取 script 標簽內的內容,這點和 BigRender 類似,而 BigRender 除了提取 script 標簽,還需要提取 style 標簽,無疑更復雜;第二個方法是可以用 document.getElementsByTagName('script') 獲取插入 DOM 但並未執行的 script 腳本,但是這樣會把頁面所有腳本全部提取,所以還需要判斷。(可以獲取某一節點下的 script 標簽)

如果是外部的 js 文件,需要為新建的 script 元素添加 src 屬性即可。

方案二:eval 大法

事實上,如果是 inline JavaScript,方案一求得的 text,可以直接 eval 之。

但是如果是外聯 js 文件,同上,需要新建 script 標簽然後指定 src 屬性。

方案三:document.write

document.write 接收一個字符串作為參數,並且支持 script 標簽以及其他 HTML 標簽拼成的字符串,看起來似乎是完美的方案。不過鑒於 document.write 的怪屬性,只適合 strVal 在首頁輸出流中的渲染情況,如果是異步的請求,就可以放棄了。

舉個栗子:

hello world
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<div>
<script>
    $.get('data.php', function(data) {
      document.write(data);
    })
</script>
</div>

目的似乎是為了在 div 中嵌入 data,但是 hello world 字樣也消失了,很顯然,異步請求後重啟輸入流,將頁面全部覆蓋掉了。

方案四:jQuery html() 方法

使用封裝過的方法無疑是個好辦法:

<div id="myDiv"></div>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
  $.get('data.php', function(data) {
    $('#myDiv').html(data);
  })
</script>

如果已經引入了 jQuery,無疑是最佳方案,沒必要重復造輪子了。

方案五: 利用 img 標簽

黑魔法,如果後台接口可控的話。

比方說我希望 innerHTML 的內容如下:

<div></div>
<script>
  alert('hello world');
</script>

我們可以這樣構造 img:

<div id='myDiv'></div>
<script>
  var str = "<div></div>";
  str += "<img src='empty.gif' onload='alert(\"hello world\"); this.parentNode.removeChild(this);' />";
  document.getElementById('myDiv').innerHTML = str;
</script>

其他: 特殊的 IE

事實上,一定條件下,innerHTML 進來的 script 腳本,在 IE(IE9-?)下是可以觸發的。

需要滿足的條件如下:

  • 腳本有 defer 屬性
  • 腳本並不是 innerHTML 的第一個元素( script 元素必須位於 "有作用域的元素" 之後。如果通過innerHTML 插入的字符串開頭就是一個 "無作用域的元素",那麼 IE 會在解析這個字符串前先刪除該元素)

code:

<body> 
<div id='myDiv'></div>
<script type="text/javascript">
  var strVar = "";
  strVar += "<span style='display: none'>hack ie</span><script defer='true'>";
  strVar += "alert('hello world');";
  strVar += "<\/script>";

  document.getElementById("myDiv").innerHTML = strVar;
</script>
</body>

參考:

  • Have Your DOM and Script It Too
  • Can scripts be inserted with innerHTML?
  • http://w3help.org/zh-cn/causes/BX9029
  • https://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
  • https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved