<li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    首页»JavaScript»Ajax保留浏览器历史的两种解决方案(Hash&Pjax)

    Ajax保留浏览器历史的两种解决方案(Hash&Pjax)

    来源:leyteris 发布时间:2017-03-28 阅读次数:

      总是在github down点东西,github整个界面做的不错,体验也很好~对于其中的?#21019;?#30721;滑动的特效最为?#19981;读藒刚开始以为这个只是普通的ajax请求效果,但是发现这个特效能够导致浏览器地址栏跟随变化,并且再点击前进后退按钮后又可以将代码滑回滑出~~于是乎就来研究下吧~

      一、通过锚点Hash实现:

      在这方面其实国内很早就有做了,比如淘宝画报,通过的是在地址栏后面加#锚点实现的,浏览器是可以识别锚点为单位的历史记录的。但不是说页面本身有这个锚点,锚点的Hash只是起到一个引导浏览器将这次的记录推入历史记录?#27426;?#30340;作用。

      来做一个小小的demo:

        <style type="text/css">
            #tab1_header,#tab2_header{
                cursor:pointer;
                border:1px solid;
                width:50px;
            }
            #tab1,#tab2{
                width:90%;
                height:200px;
                border:1px solid;
            }
        </style>
        <div id="tab_header">
        	<span id="tab1_header">Tab1</span>
        	<span id="tab2_header">Tab2</span>
        </div>
        <div id="tab1">1</div>
        <div id="tab2">2</div>

      一个很简单的Tab切换如果一般情况下就直接:

    $("#tab1_header").click(function() {
                $("#tab2").hide();
                $("#tab1").show();
    });
    $("#tab2_header").click(function() {
                $("#tab1").hide();
                $("#tab2").show();
    });

      但假如点击到tab2时想通过后退按钮退到tab1时就不行了,假如刷新的话浏览器的行为完全不是出于用户的想法,这样的话,我们可以加入#锚点来模拟新页面,为什么要?#30340;?#25311;呢,假如直接通过js改变window.location浏览器会重?#24405;?#36733;页面,但加#就不会重?#24405;?#36733;并且能保存在历史中。JS通过window.location.hash来控制URL后面的锚点#。

      我?#21069;?#20195;码改为这样:

    $(function(){
    			showTab();
    			$(window).bind('hashchange', function(e){
    				showTab();
    			});
    			$("#tab1_header").click(showTab1);
    			$("#tab2_header").click(showTab2);
    		});
    
            function showTab() {
                if (window.location.hash == "#tab2"){
    				showTab2();
    			} else {
    				showTab1();
    			}
            }
            function showTab1() {
                $("#tab2").hide();
                $("#tab1").show();
                window.location.hash = "#tab1";
            };
            function showTab2() {
                $("#tab1").hide();
                $("#tab2").show();
                window.location.hash = "#tab2";
            };

      加上window.location.hash = "#tab1"这一段代码就行了,在点击tab后,地址栏后面就会加上#tab1,点击tab2后就会改成#tab2,当浏览器检测到url变化时就会触发hashchange这一?#24405;?#23601;是用户在点击后退时能够得到的?#24405;?#23601;能够通过window.location.hash进行判?#21916;?#36827;行ajax操作了,但是haschange这个?#24405;?#24182;不是每个浏览器都有的,只有现代高级浏览器才有,所以在低级的浏览器中需要用轮询来检测URL是否在变化,这个这里就不具体说了。

      二、通过HTML5加强型的History对象实现(类Pjax)

      可以通过window.history.pushState这个方法无刷新的更新浏览器地址栏,这个方法在更新地址栏的同时将地址压入历史记录堆栈里,而要取出这个?#27426;?#39029;面则可以用popstate这个?#24405;?#26469;捕获~

      来模拟一下github的环境,github中每个url?#23884;?#24212;一个完整的?#23548;?#39029;面的,所以在ajax请求页面时需要异?#20132;?#21462;target页面中指定id容器中的内容:

      比如有这样两个页面:

      index.html

    <!DOCTYPE HTML>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=gbk">
            <title>index</title>
        </head>
        <body>
        	<script>document.write(new Date());</script>
        	<div id="cn">
            	<a href="second.html">加载前</a>
            </div>
        </body>
    </html>

      second.html  

    <!DOCTYPE HTML>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=gbk">
            <title>second</title>
        </head>
        <body>
        	<script>document.write(new Date());</script>
            <div id="cn">
            	<a href="index.html">加载后</a>
            </div>
        </body>
    </html>

      假如用同步的http请求打开的话完全是两个页面,两个页面加入很多地方一样的话我们完全可以用这种方法来实现ajax请求变更DOM,?#20197;?#36825;里加了<script>document.write(new Date());</script>语句通过它的变化能得知是否取自两个http请求,局

      部的ajax请求是不会改变这个时间显示的。  

    $(function() {
        var state = {
            title: "index",
            url: "index.html"
        };
        $("#cn").click(function() {
            window.history.pushState(state, "index", "second.html");
            var $self = $(this);
            $.ajax({
                url: "second.html",
                dataType: "html",
                complete: function(jqXHR, status, responseText) {
                    responseText = jqXHR.responseText;
                    if (jqXHR.isResolved()) {
                        jqXHR.done(function(r) {
                            responseText = r;
                        });
                        $self.html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));
                    }
                }
            });
            document.title = "second";
            return false;
        });
        $(window).bind('popstate', function(e) {
            var st = e.state;
            //$("#cn").load(st.url + " #cn");
            $.ajax({
                url: "index.html",
                dataType: "html",
                complete: function(jqXHR, status, responseText) {
                    responseText = jqXHR.responseText;
                    if (jqXHR.isResolved()) {
                        jqXHR.done(function(r) {
                            responseText = r;
                        });
                        $("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));
                    }
                }
            });
            document.title = e.state.title;
        });
    });
    

      上面语句中当#cn元素被点击时将state通过pushState方法压入历史记录栈,并在第三个参数中将浏览器URL框中指向second页面,并通过ajax将second页面异步载入,将相应的部分加入容器中,这样就实现了异步加载并改变地址栏url了,同样用户点击后退?#20445;?#35302;发popstate,刚才pushState方法中的第一个参数state便是这里传入的形参e中的state属性,通过var st = e.state取出供开发使用。同时载入index页面中对应内容。时间有限这个js没有进行重构,直接写$.ajax了,其?#23548;?#22914;不需要任何特效单纯的异步载入在jQ中可以直接用$("#cn").load(st.url + " #cn");将请求的html对应的#cn放到本页面的#cn容器中,但加入要更加炫的特效的话就要直接操作ajax传回的数据了。

    $("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));

      先创建一个div容器在将经过script过滤过的代码装入这个容器在通过find方法?#19994;?#37324;面对应的选择器容器插入本身的页面中,这里可以不用html来填充,可以根据自己的项目需要用slideUp,show什么的特效进行内容显示~~

      另外这里要推荐一个jQuery组件叫pjax(https://github.com/defunkt/jquery-pjax),比较牛叉的一个组件,异步的部分load进来另外一个页面对应容器中的内容,实现的机理和我上面的第二种方案一致。pushState + ajax = pjax 感觉这个应用会热起来的。

      稍微总结下,两种方案其实对于想IE6或者FF3.6等比较低级的浏览器支持不是很好,前者若要兼容低端浏览器要用轮询来监听浏览器地址栏行为,而后者的话是完全的HTML5应用,对于非HTML5浏览器只能做判断跳转了。

      如pjax最后的一段无奈的兼容处理:  

    $.support.pjax = window.history && window.history.pushState
    
    
    // Fall back to normalcy for older browsers.
    if ( !$.support.pjax ) {
      $.pjax = function( options ) {
        window.location = $.isFunction(options.url) ? options.url() : options.url
      }
      $.fn.pjax = function() { return this }
    }
    QQ群:WEB开发者官方群(515171538),验证消息:10000
    微信群:?#26377;?#32534;微信 849023636 邀请您加入,验证消息:10000
    提示:更多精彩内容关注微信公众?#29275;?#20840;栈开发者中?#27169;╢sder-com)
    网友评论(共0条评论) 正在载入评论......
    理智评论文明上网,拒绝恶意谩骂 发表评论 / 共0条评论
    登录会员中心
    大乐透彩票预测
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>