【问题标题】:Replacing a whole webpage with alternative content (HTML + CSS + JS)用替代内容替换整个网页(HTML + CSS + JS)
【发布时间】:2014-04-24 01:54:17
【问题描述】:

我面临一个我确信很常见的问题。我找到了很多解决这个问题的方法,它们各有优缺点。我将在这里发布我发现的内容(我相信这对其他人有用),我希望你能指出我正确的方向。

基本上,这是我的场景:

  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. 用户的网络浏览器通过 JavaScript 决定将 Content A 替换为 Content B

问题: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>

两个版本之间的差异

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

  • 所有或部分或没有导入的样式表可能不同。
  • 所有或部分或没有导入的 javascript 可能不同。
  • 内联样式表和/或 javascript 可能存在差异。
  • 内容不同,但可能只有一点点不同,也可能完全不同。
  • 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 的脚本。假设这个脚本如下:

gallery-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,另一方面,Content B 加载在一个“新页面”,这意味着Content A加载的脚本不再存在。

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

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

使用 iframe

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

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

$(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();
        }
    });
});

anchor.html

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

<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 与窗口视图一样大,我可以显示替代内容。如果用户刷新网页,刷新的页面就是“容器”页面(原来有Content A的那个),所以根本不会出现警告。

但是,我在使用此解决方案时面临的问题是:

  • 用户可以禁用 iframe。如何检测 iframe 是启用还是禁用?
  • 当用户单击框架中的链接(或提交表单)时,会在 iframe 中打开“新页面”。这不是我想要的:我希望它在主窗口中打开。我该怎么做呢?我知道有base directive 链接...但是表单呢?以及执行重定向的 JavaScript 代码?
  • iframe 中的所有内容都可以正常工作吗?响应式主题、javascript……据我所知,它们可以,但我忽略了用户是否可以限制 iframe 的功能。

TL;DR - 结论

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

所有解决方案都会带来问题:

  • 使用 document.open()、document.write()、document.close(),脚本会变得混乱。
  • 使用 POST 重定向,刷新页面会弹出警告
  • 对于 iframe,它们并不总是可用,而且我不知何故被“困”在其中。

有什么想法吗?我错过了什么吗?有没有首选的方法来做我想做的事情?

非常感谢!

【问题讨论】:

  • 虽然我很感激在这篇文章上付出的努力,但我觉得我并不完全理解这篇文章试图解决的问题。您在问题的开头列出了 5 个步骤,但您能否返回并编辑这些步骤以显示其中是否有任何您必须遵守的要求?我想跳到第二部分(备用 css 样式表),然后是第三部分(ajax 请求)和第四部分(哇,iframe!?)没有解决真正的问题,但我不确定我知道问题是什么.你能用“遗留代码要求”或“我希望它这样做”和“愿望清单”等标记数字 1-5 吗?
  • jsfiddle 会非常有帮助,即使它是问题的精简版。

标签: javascript html redirect post replace


【解决方案1】:

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

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

【讨论】:

  • 谢谢!对于超时问题,这看起来是一个很好的解决方法。我会调查的!尽管如此,我想知道其他人对不同可能的解决方案的看法......我只是想确保我们选择最合适的解决方案;-)
【解决方案2】:

POST 请求应该做一些改变或影响数据的事情。因此,防止用户刷新是有意义的,这应该是可取的行为,我很困惑您是否正在执行实际的发布请求,或者为什么重定向到 POST 页面会有这么大的问题?

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

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

【讨论】:

  • 感谢您的快速回复!在我的示例中,只有Content AContent B。然而,实际上,可能会有“更多内容”,我需要POST 来询问具体内容。一般来说,这可以使用COOKIES 来实现,但我不能依赖它们......因此,我必须使用POST 参数或GET 参数来发送此信息。我选择了POST 参数,因为我不希望用户知道她正在加载替代内容。
  • 哦!我忘了提:那么你会推荐使用 iframe 吗?我认为它们是我提到的三个中的最佳选择,但我不确定......而且,我不能假设它们会在任何地方工作;我需要知道 iframe 何时被禁用。
  • 如果您请求不同的内容,您只需添加一个类似?all?content=b 的标志来请求Content B。 URI 应该唯一标识内容,GET 应该请求该内容,POST 请求应该只确认操作的结果。
【解决方案3】:

我想我遗漏了一些东西,因为我不清楚您所说的“用户的网络浏览器通过 JavaScript 决定将内容 A 替换为内容 B”是什么意思,但是:

如果你事先知道要替换其内容的元素的参数,那么简单的逐个替换不就行了吗?

<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>

【讨论】:

  • 我知道我正在尝试做的事情有点奇怪......但我不知道如何更清楚地解释它!你的方法很有趣,但它并没有解决我的真正问题(它不像用另一个替换一个 .css 文件那么容易)。不过,感谢您的提示!
猜你喜欢
  • 1970-01-01
  • 2016-02-28
  • 2021-07-12
  • 2016-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
相关资源
最近更新 更多