将整个文稿移动到 iframe 中

Move entire document into iframe

本文关键字:iframe 移动 文稿      更新时间:2023-09-26

我正在为我们的几个网站添加聊天功能。聊天会将用户与我们帮助台的人员联系起来,以帮助他们使用网站。我们的帮助台人员希望聊天窗口看起来像页面侧面的选项卡并滑出,而不是在新窗口中弹出。但是,我希望允许用户在不丢失聊天的情况下浏览网站。

为此,我一直在尝试在聊天开始后将整个页面移动到 iframe 中(聊天在 iframe 之外),以便用户可以在 iframe 内浏览网站而不会丢失聊天。

我用这个答案开始了,这在视觉上效果很好。但是,后台的一些 JavaScript 会中断。

其中一个站点是 ASP.NET 网络表单。另一个是MVC。我一直在首先使用网络表单。一旦页面移动到 iframe 中,调用__doPostBack之类的东西就会中断,因为 javascript 上下文被留下了。

一旦用户单击链接(真正的链接,而不是__doPostBack)并且 iframe 刷新,那么一切都会完美运行。

我怎么看,我有几个选择:

  1. 以某种方式将所有 javascript 变量从 window.top 复制到 iframe 中。希望不必知道所有变量名称。我尝试了this.contentWindow.__doPostBack = window.top.__doPostBack,它有效,但缺少其他变量,因此最终失败:
  2. 以某种方式切换 iframe 的上下文以查看顶部窗口上下文,如果可能的话?应该不会。
  3. 另一个想法是不要立即将页面移动到 iframe 中,而是等到页面更改,然后将新页面加载到新的 iframe 中。但我不确定如何挂钩并劫持它。
  4. 别的?

这些网站仅供我们的员工使用,所以我只需要支持 IE11 和 Chrome。

更新:

感谢 LGSon 让我走上使用目标属性的轨道(所以我可以使用方法 #3)。以下是我最终所做的。当我弹出聊天时,我会打电话给loadNextPageInIframe()。我在这里使用 jQuery,因为我们已经在我们的网站上使用它,但一切都可以不用。我在所有没有指向另一个帧或_blank的目标的链接上设置目标。我省略了_parent,但我认为我们无论如何都不会使用它。

我在一个名为"聊天窗口"的全局变量中引用了我的聊天窗口div。

在某些情况下,这仍然可能不起作用,例如,如果有一些 javascript 直接设置 window.location。如果我们的网站上有任何可以做到这一点的东西,我将不得不添加一种方法来处理它。

function loadNextPageInIframe() {
    var frame = $("<iframe id='"mainframe'" name='"mainframe'" />").css({
        position: "fixed",
        top: 0,
        left: 0,
        width: "100%",
        height: "100%",
        border: "none",
        display: "none"
    }).appendTo("body");
    $("form, a:not([target]), a[target=''], a[target='_top'], a[target='_self']").attr("target", "mainframe");
    var firstload = true;
    frame.load(function () {
        //Runs every time a new page in the iframe loads
        if (firstload) {
            $(frame).show();
            //Remove all elements from the top window except the iframe and chat window
            $("body").children().not(frame).not(window.top.chatwindow).remove();
            firstload = false;
        }
        //Make the browser URL and title reflect the iframe every time it loads a new page
        if (this.contentWindow && this.contentWindow.location.href && window.top.location.hostname === this.contentWindow.location.hostname && window.top.location.href !== this.contentWindow.location.href) {
            var title = this.contentDocument.title;
            document.title = title;
            if (window.top.history.replaceState) window.top.history.replaceState(null, title, this.contentWindow.location.href);
        }
    });
}

我可以建议你执行以下操作

  1. 获取所有链接
  2. 附加事件单击处理程序,以便在有人单击链接时进行拦截
  3. 在点击事件中,检查聊天是否正在进行中,如果向 iframe 提供新链接
var links = querySelectorAll("a");
for (var i = 0; i < links.length; i++) {
  links[i].addEventListener('click', function(e) {
    if (isChatInProgress()) {
      e.preventDefault();  //stop the default action
      document.getElementById("your_iframe_id").src = e.target.href;
      // anything else here, like toggle tabs etc
    }
  });    
}

更新

处理表格,我目前看到 4 种方式

1) 在表单中添加提交处理程序

function formIsSubmitted(frm) {
    if (isChatInProgress()) {
        frm.target = "the iframe";
    }
    return true;
}
<form id="form1" runat="server" onsubmit="return formIsSubmitted(this)">

2) 向按钮添加点击处理程序

function btnClick(btn) {
    if (isChatInProgress()) {
        btn.form.target = "the iframe";
    }
    return true;
}
<asp:Button runat="server" ID="ButtonID" Text="ButtonText" 
    OnClick="Button_Click" OnClientClick="return btnClick(this);" />

3)当聊天开始时,您循环访问每个表单并更改其目标属性

function startChat() {
  var forms = querySelectorAll("form");
  for (var i = 0; i < forms.length; i++) {
    forms[i].target = "the iframe";
  });    
}

4) 覆盖原始回发事件(来源:拦截回发事件)

 // get reference to original postback method before we override it  
 var __doPostBackOriginal = __doPostBack;  
 // override  
 __doPostBack = function (eventTarget, eventArgument) {
    if (isChatInProgress()) {
        theForm.target = "the iframe";
    }
   // call original postback  
   __doPostBackOriginal.call(this, eventTarget, eventArgument);  
 }  

更新 2

处理

这个问题的绝对最佳方法当然是使用 AJAX 加载页面和聊天内容,但如果您的网站尚未使用它,这可能意味着更大的工作量。

如果您不想这样做,您仍然可以使用 AJAX 进行聊天,如果用户要导航到新页面,聊天应用程序会再次使用其所有内容重新创建正在进行的聊天窗口。

我建议不要在 iframe 中加载内容 - 将聊天构建为 iframe 并在页面上使用 jQuery 模式弹出窗口进行聊天。

您可以将 jquery 模式固定为固定位置,并且默认情况下启用页面滚动。您需要相应地修改 css 以使弹出窗口保留在同一位置。

如果您沿着当前的道路走下去 - 您将需要非常担心如何将内容移动到 iframe,并且可能很难根据内容在不同页面上重复使用聊天。例如,假设您在页面上播放视频,并且用户单击聊天 - 如果您将内容加载到 iframe - 用户将失去他查看了多远的状态,等等。

在我看来

,将整个网站添加为"I-Frame"不是一个好的设计实践,也不是解决问题的好方法。我的建议是:

  1. 确保"聊天"应用程序已加载到您网站的所有页面中
  2. 每当"聊天"启动时,要么建立"web-socket"连接,要么以某种方式维护服务器上的状态
  3. 将"聊天"配置为"最小化","打开"等,并将它们存储在您的cookie或会话存储中
  4. 在每次页面加载时,也调用"聊天"应用程序。从会话存储或cookie中读取与聊天相关的配置,并将其状态维护为"最小化"或"打开"等,包括X和Y位置,如果您想将其设置为"浮动"
  5. 每次,要么通过Ajax从
  6. 服务器获取整个对话,要么尝试从"本地存储"中存储和获取,并且仅对来自另一方的任何更新执行Ajax操作
  7. 使用基于 CSS 的"Float"相关属性使其浮动并位于某个侧面。

这将确保您的聊天可供用户使用,但他可以浏览整个网站。