在 web 开发中,出于跨域同步、远程调用等目的,经常需要在网页中通过 script 加载另一段远程 script。
最常用最简单的方法就是直接用 document.write 输出加载脚本的 HTML,如下:
document.write('<script src="http://somehost/path/to/script.js" type="text/script"></' + 'script>');
通常来说用这个方法是没有什么问题的,但是最近在帮人分析整合 phpcms 与 discuzx 同步登录时,发现在 discuzx 登录后无论如何也没能让 phpcms 同步登录。
原因是 dz 的登录采用的是 ajax 方式,ucenter 返回的同步代码就是用上面方法向所有 APP 发起一次 JS 请求模拟登录。phpcms 自身又有一套 phpsso 的单点登录体系,它收到请求后又需要分发给更多采用 phpsso 的 APP,于是它又生成一堆如上方法的 script 输出给最终用户。
但到了最终用户这儿,由于是 ajax 异步加载的,大概算是 BUG,再次输出的 document.write(‘<script..></script>’) 不执行,造成无法同步。
目前的解决方法是在第二次需要加载 js 请求时,换用以下方式:
var s = document.createElement('script');
s.setAttribute("type","text/javascript");
s.setAttribute("src", "http://somehost/path/to/script.js");
document.body.appendChild(s);
顺便提一下,曾经看到过文章说用 document.body.appendChild 在 IE 下有时会卡死,建议改用:
document.getElementsByTagName("head")[0].appendChild(s);
//解决二次<script>不执行的问题
function format_dom($urls) {
$output = 'var s = document.createElement("script");s.setAttribute("type","text/javascript");';
foreach($urls AS $url) {
$output .= 's.setAttribute("src", "'.addslashes(str_replace(array("\r", "\n"), array('', ''), $url)).'");document.getElementsByTagName("head")[0].appendChild(s);';
}
return $output;
}
OK.