Javascript 简单spa中的jquery未触发hashchange事件
我正在看一本关于SPA的书——单页web应用程序。这很有趣,但我被一段代码挡住了。到目前为止,我明白我在做什么,所以看起来很奇怪,这不是工作 我在页面右下角的聊天点击中触发了一个事件。此事件触发URL哈希的更改,但。。即使我用Javascript 简单spa中的jquery未触发hashchange事件,javascript,jquery,html,hashchange,Javascript,Jquery,Html,Hashchange,我正在看一本关于SPA的书——单页web应用程序。这很有趣,但我被一段代码挡住了。到目前为止,我明白我在做什么,所以看起来很奇怪,这不是工作 我在页面右下角的聊天点击中触发了一个事件。此事件触发URL哈希的更改,但。。即使我用$(window.bind('hashchange',onHashchange()).trigger('hashchange')将其绑定到窗口,hashchange事件也不会被触发 我需要手动刷新页面以查看聊天从打开更改为关闭,但这不应该发生,因为我希望它由onhashch
$(window.bind('hashchange',onHashchange()).trigger('hashchange')将其绑定到窗口,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>
spa.shell.js
var spa = (function() {
var initModule = function($container) {
spa.shell.initModule($container);
};
return {initModule: initModule};
}());
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 ---------
}());
*{
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;
}
/** */
.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;
}
spa.shell.css
var spa = (function() {
var initModule = function($container) {
spa.shell.initModule($container);
};
return {initModule: initModule};
}());
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 ---------
}());
*{
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;
}
/** */
.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');
没有后面的“()”
请记住,在某些浏览器中对此的支持是有限的
摘录自:
根据您的需要进行调整。正如您所见,我已经阅读了您建议的链接,实际上我正在测试“console.log('SUPPORTED');”的日志记录。。我会尽快删除额外的父母身份,并让你知道这是否是错误的。提前感谢您的帮助=)太好了!谢谢你的帮助!括号放错地方了,我不知道怎么放在那里。。谢谢你的帮助,现在一切正常!