代码之家  ›  专栏  ›  技术社区  ›  Gabriel Luci

将整个文档移动到iframe

  •  1
  • Gabriel Luci  · 技术社区  · 10 年前

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

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

    我用过 this answer 开始,这在视觉上效果很好。然而,后台的一些javascript中断了。

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

    一旦用户点击一个链接(一个真正的链接,而不是__doPostBack),iframe刷新,那么一切都会正常工作。

    在我看来,我有几个选择:

    1. 从窗口复制所有javascript变量。以某种方式进入iframe。希望不必知道所有变量名。我试过了 this.contentWindow.__doPostBack = window.top.__doPostBack ,这是有效的,但缺少其他变量,因此最终失败:
    2. 如果可能的话,以某种方式切换iframe的上下文以查看顶部窗口上下文?可能不是。
    3. 另一个想法是不要立即将页面移动到iframe中,而是等到页面发生变化,然后将新页面加载到新的iframe。但我不知道该如何参与这一事件并将其劫持。
    4. 还有什么?

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

    更新:

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

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

    在某些情况下,这仍然可能不起作用,例如,如果存在设置窗口的javascript。直接定位。如果我们的网站中有任何这样的东西,我必须添加一种处理方法。

    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 回复  |  直到 9 年前
        1
  •  2
  •   Asons Oliver Joseph Ash    10 年前

    我可以建议你做以下事情吗

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

    使现代化

    处理表单我现在有四种方法

    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) 覆盖原始回发事件(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进行聊天,如果用户要导航到一个新页面,聊天应用程序会重新创建正在进行的聊天窗口,其中包含所有内容。

        2
  •  1
  •   skzi    10 年前

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

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

    如果你走上你现在的道路,你将需要非常担心内容如何移动到iframe,并且可能很难根据内容在不同的页面上重复使用聊天。例如,假设您在页面上播放视频,用户单击聊天-如果您将内容加载到iframe中-用户将丢失其查看的距离等状态。

        3
  •  0
  •   Vinod Tigadi    10 年前

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

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

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

    推荐文章