在简单的spa中没有用jquery触发hashchange事件

时间:2014-03-29 08:58:04

标签: javascript jquery html5 hashchange

我正在阅读一本关于SPA的书 - 单页网页应用程序。这很有趣,但我被一段代码阻止了。到目前为止,我理解我在做什么,所以看起来很奇怪,这不是一件事。

我在聊天点击时触发了一个事件,该事件位于页面的右下角。此事件触发了URL哈希的更改,但是即使我将{+ 1}}

绑定到窗口,也不会触发hashchange事件

我需要手动刷新页面以查看聊天从打开到关闭的变化,但这不应该发生,因为我希望它由$(window).bind('hashchange', onHashchange()).trigger('hashchange');触发。 你能帮我看看发生了什么吗?

看起来我错过了一些东西,但周围的每个人都抱怨不能与其他浏览器兼容,而在这种情况下只是不起作用:S

赞赏任何提示=)

我有以下HTML代码

onhashchange

和3个脚本+ jquery清楚。第一个脚本可以在and is provided by the author of the book找到,其他两个是以下

spa.js

<html>
    <head>
        <title>SPA starter</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="css/spa.css" type="text/css">
        <link rel="stylesheet" href="css/spa.shell.css" type="text/css">
        <!-- 3rd party lib -->
        <script id="jquery_js" src="js/libs/jquery/jquery.js"></script>
        <script id="janchor_js" src="js/libs/jquery/jquery.uriAnchor.js"></script>
        <!-- my lib -->
        <script id ="spajs" src="js/spa.js"></script>
        <script id="spashelljs" src="js/spa.shell.js"></script>
        <script id="unloader" src="js/js_unloader.js"></script>

        <script id="starter">
            $(function() {
                spa.initModule($('#spa'));
            });
        </script>
    </head>
    <body>
        <div id="spa"></div>
    </body>
</html>

spa.shell.js

var spa = (function() {
    var initModule = function($container) {
        spa.shell.initModule($container);
    };
    return {initModule: initModule};
}());

spa.css

spa.shell = (function() {
    //----------- BEGIN MODULE SCOPE VARIABLES --------- 
    var configMap = {
        main_html: String() +
                '<div class="spa-shell-head">' +
                '<div class="spa-shell-head-logo"> </div>' +
                '<div class="spa-shell-head-acct"> </div>' +
                '<div class="spa-shell-head-search"> </div>' +
                '</div>' +
                '<div class="spa-shell-main">' +
                '    <div class="spa-shell-main-nav"> </div>' +
                '    <div class="spa-shell-main-content"> </div>' +
                '</div>' +
                '<div class="spa-shell-foot"></div>' +
                '<div class="spa-shell-chat"></div>' +
                '<div class="spa-shell-modal"></div>',
        chat_extend_time: 250,
        chat_retract_time: 300,
        chat_extend_height: 450,
        chat_retract_height: 15,
        chat_extended_title: 'Click to retract',
        chat_retracted_title: 'Click to extend',
        anchor_schema_map: {
            chat: {open: true, closed: true}
        }
    },
    stateMap = {
        $container: null,
        is_chat_retracted: true,
        anchor_map: {}
    },
    jqueryMap = {},
            setJqueryMap, toogleChat, onClickChat,
            copyAnchorMap, changeAnchorPart, onHashchange,
            initModule;

    //----------- END MODULE SCOPE VARIABLES --------- 
    //----------- BEGIN UTILITY METHODS --------- 
    //Return copy of stored anchro map; minimizes overhead
    copyAnchorMap = function() {
        return $.extend(true, {}, stateMap.anchor_map);
    };

    //----------- END UTILITY METHODS --------- 

    //----------- BEGIN DOM METHODS --------- 
    //Begin DOM method /changeAnchorPart/
    changeAnchorPart = function(arg_map) {
        console.log("change anchor part");
        var
                anchor_map_revise = copyAnchorMap(),
                bool_return = true,
                key_name, key_name_dep;
        //BEGIN merge changes into anchor map
        KEYVAL:
                for (key_name in arg_map) {
            if (arg_map.hasOwnProperty(key_name)) {
                //console.log("key_name:= " + key_name);

                //skip dependet keys during iteration
                if (key_name.indexOf('_') === 0) {
                    console.log("key name starts with '_'");
                    continue KEYVAL;
                }
                //update independent key value
                anchor_map_revise[key_name] = arg_map[key_name];
                //update matching dependent key
                key_name_dep = '_' + key_name;
                //console.log("key_name_dep:= " + key_name_dep);
                if (arg_map[key_name_dep]) {
                    //console.log("if");
                    anchor_map_revise[key_name_dep] = arg_map[key_name_dep];
                }
                else {
                    //console.log("else");
                    delete anchor_map_revise[key_name_dep];
                    delete anchor_map_revise['_s' + key_name_dep];
                }
            }
        }
        //END merge changes into anchor map
        //BEGIN ateempt to update URI; revert if not successful
        try {
            console.log("setting anchor");
            $.uriAnchor.setAnchor(anchor_map_revise);
            console.log("set");
        } catch (error) {
            //replace URI with existing state
            $.uriAnchor.setAnchor(stateMap.anchor_map, null, true);
            console.log("changeAnchorPart error :=" + error);
            bool_return = false;
        }
        //END attemp to update URI
        return bool_return;
    };
    //END DOM method /changeAnchorPart/

    //begin DOM method /setJqueryMap/
    setJqueryMap = function() {
        var $container = stateMap.$container;
        jqueryMap = {$container: $container,
            $chat: $container.find('.spa-shell-chat')
        };
    };
    //end DOM method /setJqueryMap/

    //Begin DOM method /toogleChat/
    //
    toogleChat = function(do_extend, callback) {
        var px_chat_ht = jqueryMap.$chat.height(),
                is_open = px_chat_ht === configMap.chat_extend_height,
                is_closed = px_chat_ht === configMap.chat_retract_height,
                is_sliding = !is_open && !is_closed;
        //avoid race condition
        if (is_sliding) {
            console.log('avoid race condition');
            return false;
        }
        //begin chat slider
        if (do_extend) {
            jqueryMap.$chat.animate({height: configMap.chat_extend_height},
            configMap.chat_extend_time, function() {
                jqueryMap.$chat.attr('title', configMap.chat_extended_title);
                stateMap.is_chat_retracted = false;
                if (callback) {
                    callback(jqueryMap.$chat);
                }
            });
            return true;
        }
        //End extend chat slider

        //Begin retract chat slider
        jqueryMap.$chat.animate({height: configMap.chat_retract_height},
        configMap.chat_retract_time, function() {
            jqueryMap.$chat.attr('title', configMap.chat_retracted_title);
            stateMap.is_chat_retracted = true;
            if (callback) {
                callback(jqueryMap.$chat)
            }

        });
        return true;
        //End rectract chat slider  
    };
    //end DOM method /toogleChat/

    //----------- END DOM METHODS --------- 
    //
    //----------- BEGIN EVENT HANDLERS --------- 
    onClickChat = function(event) {
        // console.log(stateMap.is_chat_retracted);
        changeAnchorPart({
            chat: (stateMap.is_chat_retracted ? 'open' : 'closed')
        });
        return false;

    };
    //
    // BEGIN event handler /onHashchange/
    // 
    onHashchange = function(event) {
        console.log("on hash change");
        var
                anchor_map_previous = copyAnchorMap(),
                anchor_map_proposed,
                _s_chat_previous, _s_chat_proposed,
                s_chat_proposed;
        //Attempt to parse anchor
        try {
            anchor_map_proposed = $.uriAnchor.makeAnchorMap();
        } catch (error) {
            console.log("onHashchange error:= " + error)
            $.uriAnchor.setAnchor(anchor_map_previous, null, true);
            return false;
        }
        stateMap.anchor_map = anchor_map_proposed;
        //convenience vars
        _s_chat_previous = anchor_map_previous._s_chat;
        _s_chat_proposed = anchor_map_proposed._s_chat;
        //BEGIN adjust of component if changed
        if (!anchor_map_previous || _s_chat_previous !== _s_chat_proposed) {
            s_chat_proposed = anchor_map_proposed.chat;
            console.log("adjusting components, chat:= " + s_chat_proposed);
            switch (s_chat_proposed) {
                case 'open':
                    toogleChat(true);
                    break;
                case 'closed':
                    toogleChat(false);
                    break;
                default :
                    toogleChat(false);
                    delete anchor_map_proposed.chat;
                    $.uriAnchor.setAnchor(anchor_map_proposed, null, true);
            }
        }
        //END of the adjustment
        return false;
    };
    //END event handler /onHashchange/

    //----------- END EVENT HANDLERS --------- 

    //----------- BEGIN PUBLIC METHODS --------- 
    //Begin Public methods /initModule/
    //
    initModule = function($container) {


        //load HTML and map jQuery collections
        stateMap.$container = $container;
        $container.html(configMap.main_html);
        setJqueryMap();
        //initialize chat slider and bind click handler
        stateMap.is_chat_retracted = true;
        jqueryMap.$chat.attr('title', configMap.chat_retracted_title)
                .click(onClickChat);
        //configure uriAnchor to use our schema
        $.uriAnchor.configModule({
            schema_map: configMap.anchor_schema_map
        });

        //HANDLE URI anchor change events
        //
        if ("onhashchange" in window) {
            console.log('SUPPORTED');
        }

        $(window).bind('hashchange', onHashchange()).trigger('hashchange');


    };
    //End PUBLIC methods /initModule/
    return {initModule: initModule};
    //----------- END PUBLIC METHODS --------- 
}());

spa.shell.css

*{
    margin : 0;
    padding : 0;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
h1,h2,h3,h4,h5,h6, p{ margin-bottom: 10px;}
o1,ul,dl{list-style-position: inside;}
/** end reset */

/** begin standard selectors */
body{
    font: 13px 'Trebuchet MS', Verdana, Helvetica, Arial, sans-serif;
    color: #444;
    background-color: #888;
}
strong{
    font-weight: 800;
    color:#000;
}

/** end standard selectors */

/** begin spa namespace selectors */
#spa{
    position: absolute;
    top:8px;
    left:8px;
    bottom:8px;
    right:8px;

    min-height: 500px;
    min-width: 500px;
    overflow: hidden;

    border-radius: 0 8px 0 8px;
    background-color: #fff;

}
/** end spa namespace selectors */

/** begin utility selectors */
.spa-x-select{}
.spa-x-clearfloat{
    height: 0 !important;
    float: none !important;
    visibility: hidden !important;
    clear: both !important;
}
/** */

1 个答案:

答案 0 :(得分:1)

如果我弄错了,请纠正我,但你正在绑定中执行该功能。你想要这样:

    $(window).bind('hashchange', onHashchange).trigger('hashchange');

没有&#39;()&#39;后。

请记住,在某些浏览器中,对此的支持是有限的。

摘自:jQuery - hashchange event

if (("onhashchange" in window) && !($.browser.msie)) { 
     window.onhashchange = function () { 
          alert(window.location.hash);             
     }            
     // Or $(window).bind( 'hashchange',function(e) {  
     //       alert(window.location.hash); 
     //   });              
}
else { 
    var prevHash = window.location.hash;
    window.setInterval(function () {
       if (window.location.hash != prevHash) {
          prevHash = window.location.hash;
          alert(window.location.hash);
       }
    }, 100);
}

根据您的需要进行调整。