脚本修改主体.innerHTML from body -有时IE8中止,有时不

Script modifying body.innerHTML from body - sometimes IE8 aborts, sometimes not?

本文关键字:中止 IE8 有时 主体 修改 innerHTML from body 脚本      更新时间:2023-09-26

由于我们的客户需要一个响应式(CSS)网站,并要求在他们极其基本的CMS平台内工作,我们编写了一个脚本,以配合页面价值的自定义HTML:

  1. 将我们的HTML保存到一个变量
  2. 清除整个headdocument
  3. ,然后添加我们的自定义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中,每次页面重新加载时会发生一些不同的事情:

  1. 页面加载没有错误,但只有HTML元素可见(黑色背景)。所有其他元素都是完全看不见的,但在那里(例如……

  2. 页面加载黑色且不可见,如上所述,但状态栏显示错误927917

  3. 页面开始加载可见内容(背景图像等),但被操作中止927917错误弹出打断,随后重定向到空白的"无法加载页面"页面。

  4. 页面加载正常,没有任何错误

当尝试加载页面时,这四种情况都会在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随机丢弃样式表的事实,但我相信这是一个单独的问题。