由于我们的客户需要一个响应式(CSS)网站,并要求在他们极其基本的CMS平台内工作,我们编写了一个脚本,以配合页面价值的自定义HTML:
- 将我们的HTML保存到一个变量
- 清除整个
head
和document
, - ,然后添加我们的自定义HTML回
document.body
作为唯一的HTML内容。
这确保没有任何垃圾HTML, <style>
或<link>
项目从CMS剩余的干扰响应式布局。我们的自定义CSS要求我们一直到达body
元素。
测试页w/problem: https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=53961
然而,脚本是从document
中的嵌套表中运行的,因为这是CMS放置内容的地方(在其预设的页面模板中)。
在所有现代浏览器中,包括FF、Chrome、Safari、iOS和IE9,这似乎工作得很顺利(尽管有明显的"通道")。
在IE8中,每次页面重新加载时会发生一些不同的事情:
-
页面加载没有错误,但只有HTML元素可见(黑色背景)。所有其他元素都是完全看不见的,但在那里(例如……
-
页面加载黑色且不可见,如上所述,但状态栏显示错误927917
-
页面开始加载可见内容(背景图像等),但被操作中止927917错误弹出打断,随后重定向到空白的"无法加载页面"页面。
-
页面加载正常,没有任何错误
当尝试加载页面时,这四种情况都会在IE8中发生,我们不确定是什么导致了这种不一致。这使得排除故障变得非常困难。
对于IE7,我们得到了类似的不一致的结果,以及已知的bug 927917
这里的首要问题是,给定需求、代码和内容,执行内容交换/注入的最佳方式是什么?我们只对支持IE7+感兴趣,如果太麻烦的话,我们也愿意放弃IE7。
我们尝试了下面的一些建议,但是在IE7和IE8之间得到了不同的结果,没有一个完全解决上面列出的问题:
http://www.timvasil.com/blog14/post/2008/05/28/Fix-for-IEs-Operation-Aborted-error.aspx http://blogs.msdn.com/b/ie/archive/2008/04/23/what-happened-to-operation-aborted.aspx脚本开始前的CMS输出:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Title</title>
<!-- CMS included meta tags -->
<meta name="description" content="event title" />
<meta name="keywords" content="meta-tags" />
<!-- CMS included scripts -->
<script language="javascript" type="text/javascript" src="/include/scripts/scripts.js"></script>
<script language="javascript" type="text/javascript" src="/ehome/include/scripts.js"></script>
<style type="text/css"> /* CMS styles */ </style>
<!-- CMS JS Library inclusion - could possible use this to wait for DOM ready -->
<script type="text/javascript" src="/include/scripts/prototype.js">
</script>
</head>
<body>
<form>
<input type="hidden" id="module" value="ehome" /><input type="hidden" id="eventid" value="31648" />
</form>
<table id="shadow_table">
<tr>
<td></td>
<td>
<table id="outer_table">
<!-- Lots of CMS table HTML -->
<tr>
<td id="inner_content">
<div class="eh_outer_div">
<div id="main_section">
<div>
<div>
<!-- BEGIN OUR CUSTOM CODE - intended to replace body contents -->
<div id="wrap">
<!--[if (gte IE 6)&(lte IE 8)]>
<script src="https://www.eiseverywhere.com/docs/562/selectivizr.js"></script>
<![endif]-->
<!--[if lt IE 9]>
<script src="https://www.eiseverywhere.com/docs/562/html5.js"></script>
<script src="https://www.eiseverywhere.com/docs/562/iemq.js"></script>
<![endif]-->
<header>
<!-- header content... -->
</header>
<div id="main">
<ul>
<li data-id="home"><a href="https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=50283">Home</a></li>
<!-- Other nav items... -->
</ul>
<h1>speakers</h1>
<section id="content">
<!-- Begin Main Content Section -->
<article>
<h2>CITE <strong>2012 speakers</strong></h2>
<p><strong>Our speaker list is growing continuously, so check back often for updates. Our esteemed roster so far includes:</strong></p>
<!-- Misc main content - etc.. -->
</article>
</section>
</div><!-- End Main -->
</div><!-- End #wrap Wrapper -->
<footer>
<div>
<ul>
<li data-id="home"><a href="https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=50283">Home</a></li>
<!-- Other nav items... -->
</ul>
<!-- Misc footer content... -->
</div>
</footer> <!-- End Footer -->
<!-- Cleaning Code -->
<!-- THIS IS WHERE THE REPLACEMENT SCRIPTING IS (<SCRIPT>) -->
<!-- END CUSTOM CONTENT -->
</div>
</div>
</div>
</div>
</td>
</tr>
<!-- LOTS OF OTHER UNNECESSARY CMS TABLE MARKUP... -->
</table>
<!-- Garbage DIVs from CMS scripts -->
<div id="overlay"></div>
<div id="home_od"></div>
</body>
</html>
更新:我们的自定义替换/注入脚本DOM ready():
<script type="text/javascript">
/* Clean.js /// Switches out host HTML and replaces with clean custom HTML */
document.observe('dom:loaded', function() { // Prototype.js listener: http://www.prototypejs.org/api/document/observe
/* PAGE VARIABLES */
var pre = '<!--[if lt IE 7 ]><div id="wrap" class="ie pre9 ie6"><![endif]--><!--[if IE 7 ]><div id="wrap" class="ie pre9 ie7"><![endif]--><!--[if IE 8 ]><div id="wrap" class="ie pre9 ie8"> <![endif]--><!--[if IE 9 ]><div id="wrap" class="ie ie9"> <![endif]--><!--[if (gt IE 9)|!(IE)]><!--><div id="wrap"><!--<![endif]-->';
var wrap = document.getElementById('wrap');
var title = wrap.getElementsByTagName('h1')[0].innerHTML;
var pgid = title.replace(/[^a-zA-Z 0-9]+/g,'-').toLowerCase().replace(/[ ]/g, '-'); // clean H1 text and use as page id
var footer = "<footer>" + document.getElementsByTagName('footer')[0].innerHTML + "</footer>";
var content = pre + wrap.innerHTML + footer;
var post = '</div>';
/* HOUSE CLEANING */
// Clean out <HEAD>
emptyHead(); //remove all style blocks from head
removeLinks("js"); //remove all occurences of "somescript.js" on page
removeLinks("css"); //remove all occurences "somestyle.css" on page
// Stage <BODY>
document.body.setAttribute("id", pgid);
document.body.setAttribute("onload", "finished('"+pgid+"')");
document.title = "CITE Expo + Conference: March 4-6, 2012 | " + title;
document.body.innerHTML = content + post;
// document.body.insertAdjacentElement('afterBegin', document.getElementsByTagName('footer')[0]);
// document.body.insertAdjacentElement('afterBegin', wrap);
// document.body.removeChild(document.getElementById('shadow_table'));
// Add meta tags
addMetatag('viewport', 'head');
// Add stylesheets
addStylesheet('https://www.eiseverywhere.com/file_uploads/d1d7aeedb561585d601535bb14aa6910_cite.css', 'head');
addStylesheet('https://www.eiseverywhere.com/file_uploads/cead2f725f0acc8b4ada117d22b2e872_type.css', 'head');
addStylesheet('https://www.eiseverywhere.com/file_uploads/41062e7af46018760d01e8d9f7a7b9a9_flex.css', 'head');
addStylesheet('https://www.eiseverywhere.com/file_uploads/fff3d12e98686a02eb8e8f2ac45f7bf8_anm8.css', 'head');
addStylesheet('https://www.eiseverywhere.com/file_uploads/64388fdb8762f9232b2330f9e196f996_benton-gothic-cite.css', 'head');
addStylesheet('https://www.eiseverywhere.com/file_uploads/f92ea468d4be1013b77010d2c42fdc6f_stag-cite.css', 'head');
// Add javascript
/* addJavascript('https://www.eiseverywhere.com/file_uploads/3df3d4e3b7e57d447396fe2608c96664_jump.js', 'body'); // Not working well - need to inject a new element */
addJavascript('https://www.eiseverywhere.com/file_uploads/b8601cc668024431aae05a886084fc37_android21.js', 'body');
/* FUNCTIONS */
function emptyHead()
{
var head = document.getElementsByTagName('head')[0];
var s = head.getElementsByTagName('style');
if(s)
while(s.length >= 1)
head.removeChild(s[0]);
}
function emptyBody()
{
// document.body.removeChild(document.getElementById("overlay"));
// document.body.removeChild(document.getElementById("home_od"));
}
function addJavascript(jsname, pos)
{
var th = document.getElementsByTagName(pos)[0];
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', jsname);
th.appendChild(s);
}
function addStylesheet(cssname, pos2)
{
var th2 = document.getElementsByTagName(pos2)[0];
var s2 = document.createElement('link');
s2.setAttribute('type', 'text/css');
s2.setAttribute('href', cssname);
s2.setAttribute('media', 'screen');
s2.setAttribute('rel', 'stylesheet');
th2.appendChild(s2);
}
function addMetatag(meta, pos3)
{
var th3 = document.getElementsByTagName(pos3)[0];
var s3 = document.createElement('meta');
s3.setAttribute('name', meta);
s3.setAttribute('content', 'width=device-width, minimum-scale=1.0, maximum-scale=1.0');
th3.appendChild(s3);
}
function removeLinks(filetype)
{
var targetelement = (filetype == "js") ? "script" : (filetype == "css") ? "link" : "none" //determine element type to create nodelist from
var targetattr = (filetype == "js") ? "src" : (filetype == "css") ? "href" : "none" //determine corresponding attribute to test for
var allsuspects = document.getElementsByTagName(targetelement)
for (var i = allsuspects.length; i >= 0; i--) //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr) != null)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
document.stopObserving("dom:loaded")
});
function finished(pid) // DOM is [natively] ready
{
setMenu(pid); // set the active class on li elements that contain a link to the current page
// emptyBody(); // remove junk divs from bottom of page
setLayout(); // if <aside> is missing, set #main to .single-column class
if(pid == "home") {
var anm8 = '<object type="application/x-shockwave-flash" data="http://client.clevelanddesign.com/CD/IDG/CITE/content/intro.swf"><!-- By default, play flash video --><param name="movie" value="http://client.clevelanddesign.com/CD/IDG/CITE/content/intro.swf" /><param name="wmode" value="transparent" /><param name="scale" value="default" /><!-- Show iPad/iPhone/iPod visitors the HTML5 video --><video autoplay poster="https://www.eiseverywhere.com/file_uploads/e82b83f31bb069e818fe691ebc824cf1_mtng-locked.png"><source src="https://www.eiseverywhere.com/docs/562/intro-compressed.mp4" type="video/mp4"></source></video><!-- Backup image if all else fails --><img src="https://www.eiseverywhere.com/file_uploads/e82b83f31bb069e818fe691ebc824cf1_mtng-locked.png" alt="Meet the next generation of business" /></object>';
document.getElementById('hero').innerHTML = anm8; // if home page, add animation after page is loaded
}
window.scrollTo(0, 1); // scroll mobile address bars out of sight (iPhone, Android) - gives us more screen space
}
function setMenu(p) // compare cleaned H1 text to link IDs // requires consistent naming between H1 and li.data-id // update topnav + footer HTML snippets in eTouches to match
{
var mitems = document.getElementsByTagName('li');
for(i = 0; i < mitems.length; i++) {
if(mitems[i].getAttribute('data-id'))
if(mitems[i].getAttribute('data-id') == p)
mitems[i].setAttribute("class", "active");
}
}
function setLayout()
{
if(!document.getElementsByTagName('aside').length)
document.getElementById("main").setAttribute("class", "single-column");
}
</script>
<!--[if IE 7 ]>
<script type="text/javascript">
// alert('Please upgrade to a modern browser to enjoy this website properly.');
</script>
<![endif]-->
在所有浏览器中(特别是IE),你不能/不应该修改仍在加载过程中的元素。因此,您不能从<body>
元素中的代码修改<body>
元素的内容。尤其是IE,会崩溃。不仅仅是页面级崩溃,有时甚至是整个浏览器崩溃。
典型的解决方案是确保所有修改页面的脚本必须等待,直到修改页面是安全的。像YUI和jQuery这样的典型web框架都有内置的方法来等待整个页面被安全加载(这样就可以进行操作了),或者等待部分DOM被安全修改。如果你没有使用任何内置此功能的web框架,那么你可以通过搜索找到代码片段,让你构建自己的小函数来实现此功能。逻辑因浏览器和浏览器版本而异。
安全DOM修改的绝对最简单的版本是从放置在<body>
最末尾的javascript函数调用中启动DOM修改。如果你没有一个框架可以为你做这件事,你可以添加你自己的跨浏览器DOMReady函数在这个参考中看到,并向下滚动到哪里说"跨浏览器DOMContentLoaded处理代码"
删除"defer"属性和将操作代码封装在一个文档就绪事件中(类似Prototype.js)都解决了最初问题中描述的问题。IE 7/8不再加载失败或加载不一致。
感谢@jfriend00和@Alfabravo的提示。
我仍然有问题(所有浏览器)本地的onLoad主体事件和它的功能不触发,以及IE 7/8随机丢弃样式表的事实,但我相信这是一个单独的问题。