将整个文档移至iframe

时间:2016-03-01 14:16:24

标签: javascript asp.net iframe

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

为此,我一直尝试在聊天开始后将整个页面移动到iframe(使用iframe外的聊天),这样用户就可以在iframe中浏览网站而不会丢失聊天。< / p>

我使用this answer开始,这在视觉上很有效。但是,后台的一些javascript会中断。

其中一个站点是ASP.NET Web表单。另一个是MVC。我一直在使用网络表单。一旦页面被移动到iframe中,就像调用__doPostBack一样,因为javascript上下文被遗忘了。

一旦用户点击了一个链接(一个真实的链接,而不是一个__doPostBack)并且iframe刷新,那么一切都运行良好。

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

  1. 以某种方式将所有javascript变量从window.top复制到iframe中。希望无需知道所有变量名称。我尝试了this.contentWindow.__doPostBack = window.top.__doPostBack,但是其他变量都没有了,所以最终失败了:
  2. 以某种方式切换iframe的上下文来查看顶部窗口上下文,如果可能的话?可能不会。
  3. 另一个想法是不立即将页面移动到iframe,而是等到页面更改,然后将新页面加载到新的iframe中。但我不确定如何挂钩该事件并劫持它。
  4. 别的什么?
  5. 这些网站仅供我们的员工使用,因此我只需支持IE11和Chrome。

    更新

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

    我在一个名为“chatwindow”的全局变量中引用了我的聊天窗口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);
            }
        });
    }
    

3 个答案:

答案 0 :(得分:2)

我建议您执行以下操作

  1. 获取所有链接
  2. 附加事件点击处理程序,以便在有人点击链接时拦截
  3. 点击活动,检查聊天是否正在进行,以及是否使用新链接提供iframe
  4. 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)在表单中添加一个onsubmit处理程序

    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)覆盖原始回发事件(Src:intercept-postback-event

     // 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进行聊天,如果用户要导航到新页面,聊天应用会重新创建正在进行的聊天窗口及其所有内容。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

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

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

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

相关问题