用替代内容替换整个网页(HTML + CSS + JS)

时间:2014-03-18 11:47:04

标签: javascript html redirect post replace

我遇到的问题我确信很常见。我找到了很多这个问题的解决方案,它们各有利弊。我发布了我在这里发现的内容(我认为这对其他人有用),我希望你能指出我正确的方向。

基本上,这是我的方案:

  1. 我有一个PHP网页:http://example.com/page_with_content_a_or_b.php
  2. 如果没有指定POST参数,此页面将返回Content A,如果有,则返回Content B
  3. 假设用户连接到我的页面,在她的浏览器中键入以前的URL(GET请求)。
  4. 我的服务器返回Content A
  5. 页面
  6. 用户的网络浏览器通过JavaScript决定将Content A替换为Content B
  7. 问题:JavaScript如何替换内容?

    好吧,正如我所说,我一直在寻找不同的解决方案,但似乎都不是完美的。

    为了讨论每个可能的解决方案,让我向您介绍每个版本的结果HTML代码:

    内容A的HTML

    <html>
      <head>
         <link rel="stylesheet" type="text/css" href="style_A.css">
         <script type="text/javascript" src="jquery.min.js"></script>
         <script type="text/javascript" src="gallery-animator.js"></script>
      </head>
      <body>
         <div class="gallery"><!-- images here --></div>
         <p>Content A</p>
         <script type="text/javascript" src="content-b-loader.js"></script>
      </body>
    </html>
    

    内容B的HTML

    <html>
      <head>
         <link rel="stylesheet" type="text/css" href="style_B.css">
         <script type="text/javascript" src="jquery.min.js"></script>
         <script type="text/javascript" src="gallery-animator.js"></script>
      </head>
      <body>
         <div class="gallery"><!-- images here --></div>
         <p>Content B</p>
      </body>
    </html>
    

    两个版本之间的差异

    如您所见,在示例中,两个版本非常相似,但不完全相同。一般来说,这些是我可能遇到的差异:

    • 全部或部分导入的样式表可能不同。
    • 全部或部分或全部导入的javascripts可能不同。
    • 内联样式表和/或javascripts可能存在差异。
    • 内容不同,但可能略有不同或完全不同。
    • Content B不包含用于加载自身的脚本(Content A中的最后一个脚本)。

    可能的解决方案

    使用document.open(),document.write()和document.close()

    替换内容

    我实施的第一个解决方案如下:

    content-b-loader.js(选项1)

    $(document).ready(function() {
        $.ajax({
            type:  'POST',
            url:   window.location.href,
            data: { load_content_b: 'true' },
            success: function( html ) {
                document.open();
                document.write(html);
                document.close();
            }
        });
    });
    

    显然,解决方案正常运行。但是,在某些情况下我会遇到问题。例如,在我的示例中,两个内容都加载了一个名为gallery-animator.js的脚本。假设此脚本如下:

    廊-animator.js

    var galleryInterval = setInterval(function() {
       // Fade out current image and fade in the next one
       $("body > div.gallery > img")...
    }, 5000);
    

    content-b-loader.js执行脚本后,有两个超时动画库。结果,动画看起来像一团糟(两个图像同时移动,或根本不工作)。

    序列document.open()document.write(html)document.close()似乎不会停止并替换原始脚本。

    使用POST数据重定向(使用表单)

    另一个解决方案是执行in this previous question描述的重定向。该解决方案就像一个魅力:一方面,我加载了我需要加载所需的POST数据的URL,这意味着我将获得Content B,另一方面,{{1}已加载到&#34;新页面&#34;,这意味着Content B加载的脚本不再存在。

    问题出在这里?如果我使用Content A刷新页面,我会收到一条警告,指出&#34; POST数据即将重新提交&#34;。这是不可取的,因为它看起来让用户感到困惑(我不想让她知道她被重定向到新页面)。

    我知道有一个名为PRG (Post-Redirect-Get)的解决方案可以避免这个特殊问题。但是,它需要使用GET请求访问Content B(使用GET参数或COOKIES,我都不能使用)。

    使用iframe

    我发现的最后一个解决方案也很有趣。基本上,它会从Content B隐藏(或清空)正文,在页面中添加 iframe ,并在其中加载Content A

    content-b-loader.js(选项3)

    Content B

    anchor.html

    此页面实现了第二个解决方案(它使用POST重定向)。

    $(document).ready(function() {
        $.ajax({
            type:  'POST',
            url:   window.location.href,
            data: { load_content_b: 'true' },
            success: function( html ) {
                $("body").css('', ''); // Remove all paddings and margins
                $("body").empty();
                $("body")append('<iframe id="content" seamless="seamless"' +
                    'src="anchor.html"></iframe>');
                // Initialize vars in anchor.html and call the redirect functions
                document.getElementById('content').contentWindow.url = window.location.href;
                document.getElementById('content').contentWindow.options = {
                    load_content_b: 'true'
                };
                document.getElementById('content').contentWindow.redirect();
            }
        });
    });
    

    通过使 iframe 与窗口视图一样大,我可以显示替代内容。如果用户刷新网页,则刷新的页面是&#34;容器&#34;页面(最初有<html> <head> <script type="text/javascript" src="jquery.min.js"></script> <script type="text/javascript" src="jquery.redirect.min.js"></script> <script type="text/javascript"> var url; var options; function redirect(){ $().redirect(url, options, 'POST'); } </script> </head> <body></body> </html> 的页面),因此根本没有警告。

    然而,我遇到的解决方案是:

    • 用户可以停用iframe。如何检测iframe是启用还是禁用?
    • 当用户点击框架中的链接(或提交表单)时,&#34;新页面&#34;在iframe内部打开。这不是我想要的:我希望它在主窗口中打开。我该怎么做呢?我知道链接有base directive但是形式怎么样?和执行重定向的JavaScript代码?
    • iframes内的一切都能正常运作吗?响应主题,javascripts,......据我所知,他们这样做,但我忽略用户是否可以限制iframe可以做什么。

    TL; DR - 结论

    我有一个页面Content A。使用GET请求访问时页面返回http://example.com/page_with_content_a_or_b.php,使用POST访问时返回Content A。当用户键入网址时,她会获得Content B,并使用JavaScript加载Content A

    所有解决方案都存在问题:

    • 使用document.open(),document.write(),document.close(),脚本搞乱了。
    • 使用POST重定向,刷新页面会弹出警告
    • 使用iframe,它们并不总是可用,而且我在某种程度上&#34;被卡住了#34;在他们里面。

    有什么想法吗?我错过了什么吗?是否有一种首选的方式来做我想做的事情?

    非常感谢!

3 个答案:

答案 0 :(得分:0)

POST请求执行更改或影响数据的操作。因此,防止用户刷新并且应该是理想的行为是有意义的,我很困惑你是在做一个实际的帖子请求还是为什么重定向到POST页面是如此有问题?

无论哪种方式,关于您的<iframe>解决方案,请允许我提出一些建议。 “禁用iframe”在某些浏览器上确实是技术上可行的,但要做到这一点,你必须潜入about:config或深入IE菜单,默认情况下在Chrome上完全不可能。所以,是的,说实话,我不会关心这一点,就像现在大多数网站都不关心禁用javascript的用户(任何禁用iframe的用户都可能禁用javascript),只是因为它也是很少关心自己,这是你必须自己面对后果的选择之一。现在,我正计划将你引导到<base>标签,现在就意识到你已经在帖子中提到了它。无论哪种方式,标签也适用于表单,但不适用于javascript'链接'。

总而言之,我建议您重新考虑页面是否应该是POST,如果是,那么您应该继续使用警告,否则将其重新设计为另一个GET页面。

答案 1 :(得分:0)

There's a hacky fix针对第一个解决方案中的杂乱脚本行为问题。假设与脚本相关的问题仅在使用超时时发生(我不知道是否存在其他可能出错的情况......),有一种简单的方法可以清除所有超时。只需添加以下代码:

var id = window.setTimeout(function() {}, 0);
while (id--)
    window.clearTimeout(id);

答案 2 :(得分:0)

我想我错过了一些东西,因为我不明白你的意思是什么用户的网页浏览器通过JavaScript决定用内容替换内容A. B&#34;,但是:

如果您事先知道您想要替换其内容的元素的参数,那么不会进行简单的个案更换工作吗?

<html>
  <head>
     <link rel="stylesheet" type="text/css" href="style_A.css">
  </head>
  <body>
     <div class="gallery"><!-- images here --></div>
     <p class="content">Content A</p>
  </body>

  <!-- This could be content-b-loader.js -->
  <script>
    var $stylesheet = document.getElementsByTagName('link')[0];
        $content = document.querySelectorAll('.content')[0];

    if ( $stylesheet && $content ) {
      if ( $stylesheet.getAttribute('href') == 'style_A.css'  ) {
        $stylesheet.setAttribute('href', 'style_B.css');
      }

      $content.innerHTML = 'Content B';
    }
  </script>
</html>