• onhashchange事件--司徒正美


    onhashchange事件是针对AJAX无缝刷新导致后退键失效而产生的事件,因此属于一个够新的事件,浏览器兼容性如下:

    FeatureChromeFirefoxIEOperaSafari
    support 5.0 3.6 (1.9.2) 8.0 10.6 5.0

    由于chrome引发的版本号竞赛,现在chrome20+,firefox16+,opera12了,因此对于标准浏览器我们不必顾虑支持问题,精力集中在IE678上。IE8在兼容模式下虽然有此事件,但不生效。这个检测也很简单。至于如何产生历史,这也很简单,直接在隐藏iframe中调用document.write方法就行。hash的变化,是通过定时器检测,不十分及时,但对于坚持IE67的操蛋用户就不应该给好脸色他们看!

    如何观察hash的变化呢?这其实有三个hash值,一个是主窗口之前的hash值(last_hash),主窗口当前的hash值,一个是iframe中的hash值(history_hash),我们可以比较前两者得知hashchange,但当用户点击后退按钮后,AJAX引发的效果是作用于iframe中的,因此这时是比较last_hash与history_hash。发生变化后,我们再手动修改主窗口的hash,触发onhashchange回调。

    最后提一提hash值的提取,这里存在两个兼容性问题:

    IE6直接用location.hash取hash,可能会取少一部分内容:

    比如 http://www.cnblogs.com/rubylouvre#stream/xxxxx?lang=zh_c

    ie6 => location.hash = #stream/xxxxx

    其他浏览器 => location.hash = #stream/xxxxx?lang=zh_c

    firefox 会自作多情对hash进行decodeURIComponent

    比如 http://www.cnblogs.com/rubylouvre/#!/home/q={%22thedate%22:%2220121010~20121010%22}

    firefox 15 => #!/home/q={"thedate":"20121010~20121010"}

    其他浏览器 => #!/home/q={%22thedate%22:%2220121010~20121010%22}

    下面是mass Framework中的实现

    define("hashchange", ["$event"], function(){
        $.log("已加载hashchange模块 by 司徒正美")
     
        var hashchange = 'hashchange',  DOC = document,  documentMode = DOC.documentMode,
        supportHashChange = ('on' + hashchange in window) && ( documentMode === void 0 || documentMode > 7 );
        
        $.fn[ hashchange ] = function(callback){
            return callback?  this.bind(hashchange, callback ) : this.fire( hashchange);
        }
        $.fn[ hashchange ].delay = 50;
        if(!supportHashChange){
            $.log("不支持hashchange,使用iframe加定时器模拟")
            var iframe, timeoutID, html = '<!doctype html><html><body>#{0}</body></html>'
             
            if( $.fn[ hashchange ].domain){
                html = html.replace("<body>","<script>document.domain ="+
                    $.fn[ hashchange ].domain +"</script><body>" )
            }
     
            function getHash ( url) {//用于取得当前窗口或iframe窗口的hash值
                url = url || DOC.URL
                return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
            }
            function getHistory(){
                return getHash(iframe.location);
            }
            function setHistory(hash, history_hash){
                var doc = iframe.document;
                if (  hash !== history_hash ) {//只有当新hash不等于iframe中的hash才重写
                    //用于产生历史
                        doc.open();
                        doc.write($.format(html, hash));
                        doc.close();
                }
            }
            var last_hash = getHash(), history_hash, hash = "#";
            $.eventAdapter[ hashchange ] = {
                setup: function(desc) {
                    $.require("ready", function(){
                        if (!iframe) {
                            //创建一个隐藏的iframe,使用这博文提供的技术 http://www.paciellogroup.com/blog/?p=604.
                            //iframe是直接加载父页面,为了防止死循环,在DOM树未建完之前就擦入新的内容
                            var el = $('<iframe tabindex="-1" style="display:none" widht=0 height=0 title="empty" />').appendTo( document.body )[0], fn
                            iframe = el.contentWindow
                            $.bind(el, "load",fn = function(){
                                $.unbind(el, "load", fn)
                                var doc = iframe.document
                                doc.open();
                                doc.write($.format(html, hash))
                                doc.close();
                                timeoutID = setInterval(poll,  $.fn[ hashchange ].delay)
                            });
                            function poll() {
                                var hash = getHash(),//取得主窗口中的hash
                                history_hash = iframe.document.body.innerText;//取得现在iframe中的hash
                                if(hash !== last_hash){//如果是主窗口的hash发生变化
                                    setHistory(last_hash = hash, history_hash )
                                    $(desc.currentTarget).fire(hashchange)
                                }else if(history_hash !== last_hash){//如果按下回退键,
                                    location.href = location.href.replace( /#.*/, '' ) + history_hash;
                                }
                            }
                        }
                        
                    });
                },
                teardown: function(){
                    if(!iframe){
                        clearTimeout(timeoutID);
                        $(iframe).remove();
                        iframe = 0;
                    }
                }
            };
        }
     
    })

    具体例子可见这里

    打开后点击“运行代码”,然后点击页面触发hashchange,它的回调会在页面添加一行红字,然后再点击后退按钮就看到效果了。

  • 相关阅读:
    flv mime IIS设置
    正则表达式
    MATLAB out of memory
    Cyclic prefix
    Windows Live Writer Test
    zz排序算法的稳定性
    MATLAB的分数和小数
    young矩阵学习
    Python初体验(二)
    利用VS2010调用Excel的宏
  • 原文地址:https://www.cnblogs.com/goodbeypeterpan/p/4268235.html
Copyright © 2020-2023  润新知