在简单 SPA 中,使用 jQuery 未触发哈希更改事件



我正在关注一本关于SPA - 单页Web应用程序的书。这很有趣,但我被一段代码阻止了。到目前为止,我明白我在做什么,所以看起来很奇怪,这没有醒来。

我有一个在聊天点击时触发的事件,该点击位于页面右下角。此事件触发 URL 哈希的更改,但是..即使我用$(window).bind('hashchange', onHashchange()).trigger('hashchange');将其绑定到窗口,也不会触发哈希更改事件

我需要手动刷新页面以查看聊天从打开到关闭的变化,但这不应该发生,因为我希望它由onhashchange触发。你能帮我找出发生了什么吗?

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

任何提示都值得赞赏=)

我有以下 html 代码

<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>

和 3 个脚本 + jquery 清晰。第一个脚本可以在这里找到,由本书的作者提供,另外两个如下

温泉.js

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

斯帕壳.js

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

水疗.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;
}
/** */

斯帕壳.css

.spa-shell-head, .spa-shell-head-logo, .spa-shell-head-acct, .spa-shell-head-search,
.spa-shell-main, .spa-shell-main-content, .spa-shell-main-nav, .spa-shell-foot,
.spa-shell-chat, .spa-shell-modal {
    position: absolute;
}
.spa-shell-head{
    top:0;
    left:0;
    right:0;
    height: 40px;
    background-color: red;
}
.spa-shell-head-logo{
    top: 4px;
    left: 4px;
    height: 32px;
    width: 128px;
    background: orange;
}
.spa-shell-head-acct{
    top:4px;
    right:0;
    width: 64px;
    height: 32px;
    background: green;
}
.spa-shell-head-search{
    top:4px;
    right:64px;
    width: 248px;
    height: 32px;
    background: blue;
}
.spa-shell-main{
    top:40px;
    left:0;
    bottom:40px;
    right:0;
    background-color: #993300;
}
.spa-shell-main-content, .spa-shell-main-nav{
    top:0;
    bottom:0;
}
.spa-shell-main-nav{
    width:250px;
    background: #eee;
}
.spa-x-closed, .spa-shell-main-nav{
    width:0;
}
.spa-shell-main-content{
    left:250px;
    right:0;
    background: #ddd;
}
.spa-x-closed .spa-shell-main-content{
    left:0;
}
.spa-shell-foot{
    bottom:0;
    left:0;
    right:0;
    height:40px;
    background-color: #99ffff;
}
.spa-shell-chat{
    bottom:0;
    right:0;
    width: 300px;
    height: 15px;
    background: burlywood;
    z-index: 1;
    cursor:pointer;
    border-radius: 5px 0 0 0;
}
.spa-shell-modal{
    margin-top:-200px;
    margin-left:-200px;
    top:50%;
    left:50%;
    width:400px;
    height:400px;
    background: #fff;
    border-radius: 3px;
    z-index: 2;
}
如果我

弄错了,请纠正我,但您正在绑定中执行该函数。你想要这样:

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

后面没有"()"。

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

摘自: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);
}

根据您的需求进行调整。

相关内容

  • 没有找到相关文章

最新更新