你能在js中获得以前的历史状态对象吗
Can you get the previous history state object in js?
当我按下后退或前进按钮,popstate事件触发时,我可以获得上一个状态的状态对象吗?不是e.state提供的state对象,而是我刚刚从中返回/转发的对象?
或者,我可以检测是按下了后退还是前进按钮吗?
我需要这个,因为我有多个子系统,它们都需要同时使用js历史记录,当然,我可以在推送时保存所有子系统的状态,但当我弹出时,我也必须将状态恢复到所有子系统,这是不希望的,因为它重置了我不需要的对象。例如
state 1 = {a:1, b:1, c:1}
push a = 2
state 2 = {a:2, b:1, c:1}
hit back button, popstate fires state 1 to me
restart a with 1, b with 1, c with 1 while I only need to restart a
另类幻想解决方案
....
hit back button, popstate fires state 1 to me
I also get state 2 (the one I just moved away from) through some black magic
do a differential comparison between the 2 states, find out that I only need to modify a
restart a with 1
编辑:哦,还要澄清的是,没有简单的方法可以检查页面上当前的状态a、b和c(因为它比abc和123复杂一点)
答案是修饰pushState
以记录应用程序中的当前状态。所以,类似于:
var app = {
currentState: false,
originalPushState: false,
pushState : function(state, title, href) {
app.currentState = state;
app.originalPushState.call(history, state, title, href);
},
onPopstate : function(event) {
var newState = event.state;
var oldState = app.currentState;
app.currentState = newState;
// you now have the current state and the state you came from
},
init : function() {
window.onpopstate = app.onPopstate;
app.originalPushState = history.pushState;
history.pushState = app.pushState;
}
}
app.init();
顺便说一句,popstate
相当令人困惑。当你弹出一个正则数组时,你得到的是弹出的值,而不是现在它末尾的值,所以从语义上讲,这有点奇怪。此外,history.state
总是包含当前状态,因此event.state
是冗余的。我想说,如果某个event.popped
是指向实际弹出页面状态的指针(可能只有当它与您的网站位于同一域时才可用),那么设计者的奇怪选择会更明智。
onpopstate
在状态更改后被激发,因此您无法获得原始状态,但您可以通过其他方式来实现,例如拥有状态和当前状态指示器的副本,并手动更新onpopstate
中的副本。
扩展历史对象
这是我的来源,你可以从https://gist.github.com/HasanDelibas/12050fc59d675181ea973d21f882081a
此库包含:
- history.states->获取状态列表
- history.stateIndex->当前状态指数
- "historyChange";事件->检测历史变化(从,到,side="back"|"forward")
-
重要
state
必须是history.pushState( **state**, ...)
处的对象
(function(){
let stateSymbol = "__state__index__";
history.stateIndex =-1;
history.states=[];
let pushState = history.pushState;
function add(data,title,url){
if(data==null) data={};
if(typeof data!="object") data={data:data};
data[stateSymbol] = (history.stateIndex+1);
history.states.splice(history.stateIndex+1,0,[data,title,url])
history.states.splice(history.stateIndex+2)
history.stateIndex++;
}
history.pushState =function(data,title,url=null){
add(data,title,url);
pushState.bind(history)(data,title,url);
}
addEventListener("popstate",function(e){
var eventObject= {};
var newStateIndex = e.state!=null ? e.state[stateSymbol] : -1;
eventObject.from = history.states[history.stateIndex];
eventObject.to = newStateIndex>-1 ? history.states[newStateIndex] : null;
eventObject.side = history.stateIndex>newStateIndex ? "back" : "forward";
if( newStateIndex > -1 && !(newStateIndex in history.states) ){
add(history.state,"",window.location.href);
}
window.dispatchEvent(new CustomEvent("historyChange", {detail: eventObject} ))
history.stateIndex = e.state!=null ? e.state[stateSymbol] : -1;
});
})();
现在您可以使用CCD_ 10对象获取所有状态,并用addEventListener("popstate",function(e))
检测历史变化
使用
/**
* @param e.detail.from [data,title,url]
* @param e.detail.to [data,title,url]
* @param e.detail.side "back" | "forward"
*/
addEventListener("historyChange",function(e){
var from = e.detail.from; // [ data , title , url ]
var to = e.detail.to; // [ data , title , url ]
var side = e.detail.side; // "back" | "forward"
console.log( `You changed history. Side is ${e.detail.side}.'nFrom:${e.detail.from[2]}'nTo:${e.detail.to[2]}`)
})
history.pushState("1", "DENEME-TEST" ,"?1");
history.pushState("2", "DENEME-TEST" ,"?2");
// list of history states
console.log( history.states )
/*
[
[ {...} , "DENEME-TEST" ,"?1" ]
[ {...} , "DENEME-TEST" ,"?2" ]
]
*/
// get history current state index
console.log( history.stateIndex )
/*
1
*/
我认为Richard J的代码很好。只是给你另一个示例代码,它与他的编码略有不同。
请记住,popstate
仅在";背面";被触发。您不能使用event.preventDefault()
来中断它。此事件在更改之后被称为(即event.state === history.state
)。
pushState
和replaceState
中没有事件触发。
以下代码的改进之处在于,您可以知道所有的更改,而不仅仅是popstate。请记住,历史API在单页应用程序(SPA)中很有用,但不要将其与正常的超链接导航混合使用,这将是一场灾难。
// setup a object 'stateMgr' to manage the stuff.
const stateMgr = {
currentState: null,
prevState: null,
modifyByPushState(newState){
this.prevState = this.currentState;
this.currentState = newState;
this.onStateChanged(null);
},
modifyByOnPopState(evt){
this.prevState = this.currentState;
this.currentState = evt.state;
this.onStateChanged(null);
},
modifyByReplaceState(newState){
let replacedState = this.currentState;
this.currentState = newState;
this.onStateChanged(replacedState);
},
onStateChanged(replacedState){
// here you can have this.currentState and this.prevState
window.dispatchEvent(new CustomEvent('statechanged', {detail: {
currentState:this.currentState,
prevState:this.prevState,
replacedState
}}))
}
}
// global methods for use
function pushState(state, title, href){
window.history.pushState(state, title, href);
stateMgr.modifyByPushState(state);
}
function replaceState(state, title, href){
window.history.replaceState(state, title, href);
stateMgr.modifyByReplaceState(state);
}
// notify the popstate using modifyByOnPopState(event) in the event handling
window.addEventListener('popstate', function(evt){
stateMgr.modifyByOnPopState(evt);
}, false);
// this is a customized event you can obtain all changes of state
window.addEventListener('statechanged', function(evt){
const {currentState, prevState, replacedState} = evt.detail;
console.log(currentState, prevState, replacedState);
}, false);
// Implement the click hanlders
function addRow(t){
let li = document.createElement('li');
li.append(t);
document.querySelector('ul').append(li);
}
var uid = 0;
var dateOffset = Date.now() - 0x24000;
function a(){
pushState({uid: ++uid, d: Math.random().toFixed(2), v: Date.now()-dateOffset}, '', location.href);
addRow('Push');
}
function b(){
replaceState({uid: ++uid, d: Math.random().toFixed(2), v: Date.now()-dateOffset}, '', location.href);
addRow('Replace');
}
function c(){
addRow('Go Back');
window.history.go(-1);
}
<button onclick="a()">push</button>
<button onclick="b()">replace</button>
<button onclick="c()">back</button>
<ul></ul>
- redux 中状态对象的结构
- 如何将状态对象/数据传递给(异步)ajax 回调
- 你能在js中获得以前的历史状态对象吗
- 更新HTML5历史中以前的状态对象
- stampit.js“状态”对象不是实例安全的
- 相位器.js获取给定的无效相位器状态对象
- 使用 React 创建的表单不会更新支持状态对象
- AngularJs :将 stateParams 值附加到状态对象中的自定义数据
- Redux 的 .getState() 不应该返回状态对象的副本
- 历史状态推送和谷歌分析
- Nodejs使用回调函数缓存有状态对象
- 我可以只返回状态对象的一部分而不是整个状态对象的新副本吗
- 历史状态和更改url栏上的url
- JavaScript获取浏览器特定的历史记录对象
- 处理一个巨大的状态对象
- 访问pushState状态对象内容
- Ajax / HTML5历史状态(popState, pushState等)-后退按钮行为
- 当用户单击'back'时,访问上一页的历史状态
- 调用mapStateToProps似乎传递了错误的状态对象
- HTML5历史API-状态对象的最大大小是多少