В таких ситуациях я всегда находил, что государственные машины - это путь. Создайте свою страницу/JavaScript, чтобы в любой момент времени вы могли указать набор входов, и вы всегда будете получать одинаковый результат на всей странице. Самое приятное в этом подходе - вы не знаете , как вы попали туда, где находитесь в своей программе, вам просто нужно знать, какие данные привели к текущему состоянию.
В вашем случае, вы можете создать базовый объект, описывающий ваше состояние:
var state = { user: 'Tomasz', ajaxSent: false, otherState: 123 };
function updateFromState(state){
// Set all dependent UI visibilities, etc. based on state object
}
Тогда, прежде чем делать какие-либо изменения, нажмите текущее состояние на массив так, если это необходимо вы можете вернуться:
var stateList = [];
stateList.push({ user: 'Tomasz', ajaxSent: false, otherState: 123 });
// Do something that changes your state
var newState = {user: 'Tomasz', ajaxSent: true, otherState: 123 };
updateFromState(newState);
// Now, if you need to revert
var previousState = stateList.pop();
updateFromState(previousState);
Недостатком этого подхода является то, что вы фактически не «уничтожаете» любые побочные эффекты, которые вы могли бы вызвать. Если, например, вы сделали сообщение AJAX, которое изменило данные на сервере, вам нужно было бы понять, как «отменить» эту запись AJAX. Это выходит за рамки простого изменения локального состояния страницы. Но, если вам не нужно отменять побочные эффекты на стороне сервера, но просто иметь возможность точно отражать правильное состояние страницы, это может сработать для вас.
Вот что я бы, вероятно, использовать, чтобы начать работу, если я делал что-то вроде этого:
var StateHelper = function(){
var stateList = [];
var callbacks = [];
this.onChange = function(callback){
callbacks.push(callback);
};
this.set = function(opts){
stateList.push(opts);
apply(opts);
};
this.undo = function(){
if(stateList.length <= 1){
return; // nothing to undo
}
// To undo, we go back 2, since top of stack is current
stateList.pop();
var last = stateList[stateList.length - 1];
apply(last);
};
var apply = function(opts){
var length = callbacks.length;
for(var i = 0; i < length; i++){
callbacks[i](opts);
}
};
};
Тогда, если моя страница выглядит следующим образом:
<div id='title' style='text-decoration: underline;'>some title</div>
<div id='state1' class='clickable'>click to set state2 (title = 'second')</div>
<div id='state2' class='clickable'>click to set state3 (title = 'third')</div>
<br/>
<div id='undo' class='clickable'>undo</div>
я мог бы использовать выше StateHelper как это (обратите внимание, я использовал прикосновение JQuery):
// A function that should be called when state changes
var updateTitle = function(opts){
// Update the pages title based on state
console.log('title updating');
$('#title').text(opts.title);
};
var myState = new StateHelper();
myState.onChange(updateTitle); // hook the state change event
// some example states
var state2 = { title: 'second' };
var state3 = { title: 'third' };
// Just some click handlers
$(document).ready(function(){
$('#state1').click(function(){
myState.set(state2);
});
$('#state2').click(function(){
myState.set(state3);
});
$('#undo').click(function(){
myState.undo();
});
// Set initial state
myState.set({title: 'some title'});
});
Для живого примера, см: http://jsfiddle.net/belorion/Hywtc/
+1 за очень хороший Ответ. Я чувствовал, что мне не хватает такого простого решения. И на самом деле я в основном обеспокоен отменой изменений DOM после неудачного запроса AJAX, поэтому никаких изменений на стороне сервера не требуется. –
@ Tomasz обновлен с кодом – Matt
Я еще не обволакиваю все это, но это похоже на решение моей проблемы, поэтому я принимаю ваш ответ сейчас. Благодаря! –