`
yiminghe
  • 浏览: 1465560 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

XHR与浏览器导航冲突解决方案

阅读更多

研究 gmail 有感

 

理论:

 

历史:

最早没有 xhr 的时候,要想得到无刷新的用户体验,唯一的方法就是隐藏帧技术(frame) ,发展到现在的 iframe,这个技术仍然有它的使用场景,即在文件上传以及 简单情况下浏览器的前进后退导航功能 上。

 

使用:

当一个页面嵌入一个iframe时,当javascript变动iframe的src(或者操作document open 与 close),会在浏览器上生成一条历史记录,点击后退的话,主页面没有变化,但是iframe会加载历史记录中的上一条src(或者文档),因此可以解决传统用户体验的浏览器导航部分。

 

适用范围:

一般用于界面切换,当界面有大的变化,且没有修改或删除操作时 ,可以由用户点击浏览器的返回操作来达到上一个操作界面。

 

技术描述:(firefox 适用,ie不适用)


主页面 javascript 设置里面的 iframe 的 src (向服务器传递信息),当iframe 加载完毕后,在iframe的页面调用主页面的回调函数,达到更新主页面的作用,并向浏览器添加一条历史记录。当用户点击后退后,iframe会加载历史记录的上一条页面,重新调用上一个页面所应该的主页面callback,修改主页面到上一个功能界面,达到是主页面回退的效果. iframe 一般是设置样式 display:none,排除在文档流中,不参与用户界面。

 

示例 (firefox 适用):

 

主页面 :index.html

 

<iframe id='i' style='display:none'></iframe>
<div id='d'></div>
<div id='d2'></div>
<input type='button' onclick='bclick();' value='change'/>
<script>
	var ii=0;
	function callback(str){
		//alert(ii);
		document.getElementById('d').innerHTML='iframe call back :'+str;
	}
	
	function bclick() {
		document.getElementById('d2').innerHTML='mimic ajax '+ii;
		document.getElementById('i').src='iframe.html?i='+(ii++);
	}
	
	window.onload=function(){
		document.getElementById('i').src='iframe.html';
	}
	</script>
 

 

隐藏帧页面 :iframe.html

 

 

<script>
	window.onload=function(){
		parent.callback(window.location);
		
	}	
</script>
 

 

实战(多浏览器解决方案)

 

根据 advanced dom scripting 以及 YUI YAHOO.util.History 提出的方案,可以解决浏览器导航问题以及书签功能。



对于 firefox,ie8 可以直接给url添加 hash ,则firefox,ie8会把变动的 url加到浏览器history中,而ie6,7 则不会。


 firefox 


   每次操作添加 hash 到 url,并后台 setInterval 监控 url hash 的变化,根据当前的hash 进行 ajax 操作,( 用户点击后退只会改变hash值。

 

updated 2010-12-29 :

firefox chrome 已经支持 hashchange 事件,不再需要定时器监控了,监听事件即可。



 ie 6,7


   设置隐藏的iframe,每次操作用脚本设置iframe的内容 (注意:如果仅仅设置 src 参数 ?x=xx 不同,ie6,7 并不会产生历史纪录,必须src不同,直接脚本产生 iframe 新document(open,write,close)也可以产生历史纪录),将当前hash 插入到生成的iframe内容中,后台监控 setInterval  iframe 内容中 hash 的变化,如果变化( 用户点击后退会使当前页面iframe的内容变化 ),则提取hash值,添加到主页面url,执行相关ajax 操作。

 

YUI BHM 相关操作:

 

/**
     * Update the IFrame with our new state.
     *
     * @method _updateIFrame
     * @private
     * @return {boolean} true if successful. false otherwise.
     */
    function _updateIFrame (fqstate) {

        var html, doc;

        html = '<html><body><div id="state">' + fqstate + '</div></body></html>';

        try {
            doc = _histFrame.contentWindow.document;
            doc.open();
            doc.write(html);
            doc.close();
            return true;
        } catch (e) {
            return false;
        }
    }

 

关键是 open() ,close() 会增加历史 ,之后可以将数据附在 doc 上,后退的话数据就会回来,但是注意 close() 后会触发 iframe load 事件,yui3 采用 hash 来存储数据:

 

 

HistoryHash._updateIframe = function (hash, replace) {
        var iframeDoc      = iframe.contentWindow.document,
            iframeLocation = iframeDoc.location;


        iframeDoc.open().close();

        if (replace) {
            iframeLocation.replace(hash.charAt(0) === '#' ? hash : '#' + hash);
        } else {
            iframeLocation.hash = hash;
        }
    };
 

 

ie8


很简单,由于有相关事件直接监控 Hash 变动即可 ,不用像firefox一样轮循查看 :

 

if (YAHOO.env.ua.ie) {

            if (typeof document.documentMode === "undefined" || document.documentMode < 8) {

                // IE < 8 or IE8 in quirks mode or IE7 standards mode
                //利用 iframe 来生成历史纪录
                _checkIframeLoaded();

            } else {

                // IE8 in IE8 standards mode
                //直接利用特有事件
                YAHOO.util.Event.on(top, "hashchange",
                    function () {
                        var hash = _getHash();
                        _handleFQStateChange(hash);
                        _storeStates();
                    });

                _initialized = true;
                YAHOO.util.History.onLoadEvent.fire();

            }

        } else {
            //其他浏览器,轮训hash值变化
            // Start the thread that will have the responsibility to
            // periodically check whether a navigate operation has been
            // requested on the main window. This will happen when
            // YAHOO.util.History.navigate has been called or after
            // the user has hit the back/forward button.

            // On Safari 1.x and 2.0, the only way to catch a back/forward
            // operation is to watch history.length... We basically exploit
            // what I consider to be a bug (history.length is not supposed
            // to change when going back/forward in the history...) This is
            // why, in the following thread, we first compare the hash,
            // because the hash thing will be fixed in the next major
            // version of Safari. So even if they fix the history.length
            // bug, all this will still work!
            counter = history.length;

            // On Gecko and Opera, we just need to watch the hash...
            hash = _getHash();

            setInterval(function () {

                var state, newHash, newCounter;

                newHash = _getHash();
                newCounter = history.length;
                if (newHash !== hash) {
                    hash = newHash;
                    counter = newCounter;
                    _handleFQStateChange(hash);
                    _storeStates();
                } else if (newCounter !== counter && YAHOO.env.ua.webkit) {
                    hash = newHash;
                    counter = newCounter;
                    state = _fqstates[counter - 1];
                    _handleFQStateChange(state);
                    _storeStates();
                }

            }, 50);
 

书签问题:


    多个浏览器都可以通过,添加书签附带了当前页面的hash值。载入书签时,首先读取Hash值进入相应的ajax操作。

demo:

 

updated : 2010-12-29

 

由于 ie>7 以及 firefox ,chrome 都已经支持 hashchange 事件以及历史存储,那么实际上难点就是 ie6,7 下使用 iframe 来记录导航历史 :

 

simple hashchange for ie6,7 @ google code

 

kissy 采用先进的事件补丁技术优雅地解决了这个问题 ,在任何浏览器下都可以直接

 

function t() {
        alert("current hash :" + window.location.hash);
    }
    KISSY.Event.on(window, "hashchange", t);

 

即可 !

 

PS:html5 提出了新的标准 ,目前 chrome 下已经实现:

 

session history and navigation

 

github 也做了尝试:

 

how to rewrite url without refresh like github

 

PS2: 如果不想使得修改 hash 而引起浏览器增加历史记录,可使用 location.replace('#xx') ,对于 ie6,7 模拟的iframe,情况则只需要只修改 body 的 innerHtml :

 

iframe.contentWindow.document.body.innerHTML='#xx'
 

 

 

 

 

 

0
0
分享到:
评论

相关推荐

    解决ecshop中使用jquery冲突问题

    描述中提到的解决方案是通过修改 JS 文件,不改变 ECShop 的源代码,而是采用 jQuery 的方法来实现 AJAX 功能。 首先,要解决冲突,我们需要理解 Prototype 和 jQuery 的冲突是如何发生的。通常,jQuery 提供了一个...

    ThickBox关闭层自动刷新和页面数据提交冲突问题

    ### ThickBox关闭层自动刷新与页面数据提交冲突问题解析 #### 问题背景及现象 在进行Web开发过程中,经常会遇到需要使用弹出层的情况。ThickBox作为一个常用的弹出层插件,因其简单易用而受到许多开发者的青睐。...

    IE浏览器经典故障大全[归类].pdf

    本文主要讨论的是关于IE浏览器的经典故障及其解决方案,这些故障通常会影响用户的浏览体验。首先,故障一涉及到“发送错误报告”的问题。当IE浏览器遇到问题并提示用户发送错误报告时,用户可以选择关闭这个功能。...

    Error:in ./node-modules/axios/lib/platform/index.js

    此外,查阅Axios的官方文档和GitHub仓库中的issue,看看是否有人遇到过类似问题并找到了解决方案。如果问题仍然无法解决,考虑创建一个新的问题,提供详尽的错误信息和复现步骤,以便社区成员能够帮助你。 总的来说...

    FormData:FormData支持其中window.FormData未定义

    在前端开发中,FormData对象是HTML5引入的一个重要特性,用于构建和发送数据,通常与...在遇到“window.FormData未定义”的问题时,记得检查浏览器兼容性、执行环境以及代码本身,通常能快速找到解决方案。

    javascript跨域请求包装函数与用法示例.docx

    ### JavaScript 跨域请求包装函数与用法详解 在现代Web开发中,跨域问题是一个常见的挑战。由于浏览器出于安全考虑实施了同源策略(Same-Origin Policy),这...在实际开发中,应根据项目需求选择合适的跨域解决方案。

    OfficeServer2007的服务器角色[归纳].pdf

    OfficeServer2007是微软在2007年推出的一款重要的商业服务器产品,它标志着Office系列从传统的桌面应用向服务器解决方案的转变。这一重大变革是微软商业策略的重要组成部分,旨在为企业提供更高效、协作的工具。...

    0x7c84c3e3指令引用的“0x”内存[借鉴].pdf

    “0x7c84c3e3指令引用的“0x”内存”错误虽然看似复杂,但通过合理的诊断步骤和针对性的解决方案,大多数情况下都能够得到有效解决。无论是从硬件还是软件层面出发,关键在于准确识别问题的根本原因,并采取相应的...

    CypressZeptoIssue:赛普拉斯与Zepto问题

    解决这个问题可能需要一些调试和实验,但通过深入了解Cypress的工作原理和Zepto的API,以及充分利用Cypress提供的工具,你应该能找到合适的解决方案。在实践中,了解如何在现代前端测试环境中处理第三方库的挑战是至...

    asp.net2.0 Ajax 上传进度条

    ASP.NET 2.0 是微软推出的用于构建动态网站的Web应用程序框架,它极大地简化了Web开发...总的来说,这个解决方案展示了如何结合Ajax和C#来实现一个实用且可定制的文件上传进度条,提高了用户体验并增强了网站的功能性。

    疯狂ajax源代码第16-17章

    Ajax框架和库提供了一套完整的解决方案,包括DOM操作、事件处理、动画效果以及Ajax请求的封装,使开发者能够更快速、更稳定地实现Ajax功能。此外,还可能涉及到如何选择合适的框架,以及如何避免不同框架间的冲突。 ...

    java的常见问题及解决方法定义.pdf

    以下是一些常见问题及其解决方案: 1. **类签名不匹配**: 当出现“'org.apache.commons.collections.SequencedHashMap'的签名信息与同一包中的其他类的签名信息不匹配”这样的错误时,通常是因为不同库提供的相同...

    路由当交换机图文教程汇编.pdf

    这时,利用现有无线路由器充当无线交换机使用便成为了一种既经济又有效的解决方案。本文将详细介绍如何将无线路由器转变为无线交换机,并扩展网络覆盖范围,同时确保网络安全。 首先,要实现无线路由器到无线交换机...

    web+lvs+piranha负载均衡[收集].pdf

    Web + LVS + Piranha 负载均衡是一种高效且灵活的数据中心解决方案,用于分发网络流量到多台服务器,提高服务可用性和性能。LVS(Linux Virtual Server)是基于Linux内核的负载均衡器,它能实现四层负载均衡,而...

    Joomla搭建网站培训教程[整理].pdf

    XAMPP是一款免费且开源的跨平台Web服务器解决方案,包括Apache、MySQL、PHP等组件,非常适合用于搭建本地开发环境。安装xampp前,请确保您的计算机满足以下最低硬件要求: - 操作系统:Windows、macOS或Linux。 - ...

    路由器连接上网步骤汇编.pdf

    【路由器连接上网步骤详解】 路由器是现代家庭和办公室网络的核心设备,它允许多台设备共享一个互联网连接。这里我们将详细讲解如何使用...如果遇到问题,参照路由器的用户手册或在线帮助文档,通常都能找到解决方案。

    asp.net下PageMethods使用技巧

    在ASP.NET开发中,...在遇到问题时,不要忽视文档、示例以及社区资源,它们通常能提供有效的解决方案。同时,熟悉ASP.NET AJAX的其他功能,如UpdatePanel和AjaxControlToolkit,也能进一步提升开发效率和用户体验。

    路由器设置方法整理.pdf

    路由器设置是网络连接中的基础步骤,...在遇到问题时,参照路由器的说明书或在线帮助文档,通常都能找到解决方案。此外,不同型号的TP-LINK路由器虽然大致设置相似,但具体选项可能会有所不同,根据实际情况进行调整。

    S2SH用户重复登录问题[文].pdf

    在本文中,我们将探讨如何解决...不过,随着技术的发展,现代Web应用可能会使用更高级的解决方案,例如JWT(JSON Web Tokens)进行身份验证,它可以更好地处理会话管理,减少服务器资源的占用,并提供更好的可扩展性。

    DNS的基础知识借鉴.pdf

    ### DNS基础知识详解 #### 一、DNS的概念与历史背景...它解决了早期IP地址难记的问题,同时也为互联网的发展提供了灵活高效的域名管理方案。通过对DNS的理解,我们可以更好地利用这项技术,保障网络通信的安全与顺畅。

Global site tag (gtag.js) - Google Analytics