我正在尝试为jQueryUI .draggable创建一个撤消/重做函数,目前我有一个函数,但没有像预期的那样工作,下面是我的函数:
$(document).ready(function() {
$('.editable').draggable({
stop: stopHandlerDrag,
start: startHandlerDrag
});
});
var historyApp = {
stackStyle: [],
stackId: [],
counter: -1,
add: function(style, id) {
++this.counter;
this.stackStyle[this.counter] = style;
this.stackId[this.counter] = id;
this.doSomethingWith(style, id);
// delete anything forward of the counter
this.stackStyle.splice(this.counter + 1);
},
undo: function() {
--this.counter;
this.doSomethingWith(this.stackStyle[this.counter], this.stackId[this.counter]);
},
redo: function() {
++this.counter;
this.doSomethingWith(this.stackStyle[this.counter], this.stackId[this.counter]);
},
doSomethingWith: function(style, id) {
//Check if make buttons undo/redo disabled or enabled
if (this.counter <= -1) {
$('#undo').addClass('disabled');
$('#redo').removeClass('disabled');
return;
} else {
$('#undo').removeClass('disabled');
}
if (this.counter == this.stackStyle.length) {
$('#redo').addClass('disabled');
$('#undo').removeClass('disabled');
return;
} else {
$('#redo').removeClass('disabled');
}
console.log(style + ' - ' + id);
//Apply history style
$('#' + id).attr('style', style);
console.log(this.counter + ' - ' + this.stackStyle.length);
}
};
//Stop Handler Drag
function stopHandlerDrag(event, ui) {
console.log('stop drag');
var style = $(ui.helper).attr('style');
var id = $(ui.helper).attr('id');
historyApp.add(style, id);
}
//Star Handler Drag
function startHandlerDrag(event, ui) {
console.log('start drag');
var style = $(ui.helper).attr('style');
var id = $(ui.helper).attr('id');
historyApp.add(style, id);
//Dettach all events
$('#' + id).draggable("option", "revert", false);
//reassign stop events
$('#' + id).draggable({
stop: stopHandlerDrag,
start: ''
});
}
//Click Events For Redo and Undo
$(document).on('click', '#redo', function() {
historyApp.redo();
});
$(document).on('click', '#undo', function() {
historyApp.undo();
});<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
<span id="undo" class="btn btn-sm btn-success disable">Undo</span>
<span id="redo" class="btn btn-sm btn-danger disable ">Redo</span>
<p id="P1" class="editable" style="left: auto; top:auto;">Drag #1</<p>
<p id="P2" class="editable" style="left: auto; top:auto;">Drag #2</<p>
<p id="P3" class="editable" style="left: auto; top:auto;">Drag #3</<p>
这是一个Working code demo
现在,问题是,例如,如果您运行我的代码并按以下顺序拖动元素(拖动#1,拖动#2,拖动#3),然后单击undo,有时您将不得不单击两次,然后如果您按此顺序拖动并单击undo以恢复所有元素,然后单击drag elements #1 and #2 and then click on undo,您将注意到只有#1元素将返回到他的位置,所以我的问题是我做错了什么,我如何解决这个问题?我想可能是我的计数器错了,或者我的var historyApp有问题。
发布于 2016-10-17 11:13:19
您可能需要附加一个逻辑来检查undo或redo的样式是否与上一个/下一个状态不同:
add: function (style, id) {
var preIndex = this.counter;
if (this.counter == this.stackStyle.length - 1)
{
++this.counter;
}
else
{
this.counter = this.stackStyle.length;
}
this.stackStyle[this.counter] = style;
this.stackId[this.counter] = id;
this.doSomethingWith(style, id);
},
undo: function () {
--this.counter;
while ($('#' + this.stackId[this.counter]).attr('style') == this.stackStyle[this.counter])
{
--this.counter;
}
this.doSomethingWith(this.stackStyle[this.counter], this.stackId[this.counter]);
},
redo: function () {
++this.counter;
while ($('#' + this.stackId[this.counter]).attr('style') == this.stackStyle[this.counter]) {
++this.counter;
}
this.doSomethingWith(this.stackStyle[this.counter], this.stackId[this.counter]);
},发布于 2016-10-17 11:41:42
你的逻辑有问题。这是我自己做的StateMaker。不要逐字逐句地照搬,但它会告诉你其中的逻辑。
function StateMaker(initialState){
var o = initialState;
if(o){
this.initialState = o; this.states = [o];
}
else{
this.states = [];
}
this.savedStates = []; this.canUndo = this.canRedo = false; this.undoneStates = [];
this.addState = function(state){
this.states.push(state); this.undoneStates = []; this.canUndo = true; this.canRedo = false;
return this;
}
this.undo = function(){
var sl = this.states.length;
if(this.initialState){
if(sl > 1){
this.undoneStates.push(this.states.pop()); this.canRedo = true;
if(this.states.length < 2){
this.canUndo = false;
}
}
else{
this.canUndo = false;
}
}
else if(sl > 0){
this.undoneStates.push(this.states.pop()); this.canRedo = true;
}
else{
this.canUndo = false;
}
return this;
}
this.redo = function(){
if(this.undoneStates.length > 0){
this.states.push(this.undoneStates.pop()); this.canUndo = true;
if(this.undoneStates.length < 1){
this.canRedo = false;
}
}
else{
this.canRedo = false;
}
return this;
}
this.save = function(){
this.savedStates = this.states.slice();
return this;
}
this.isSavedState = function(){
var st = this.states, l = st.length; sv = this.savedStates;
if(l !== sv.length){
return false;
}
function rec(o, c){
var x, z;
if(typeof o !== typeof c){
return false;
}
else if(o instanceof Array){
for(var n=0,q=o.length; n<q; n++){
x = o[n]; z = c[n];
if(x && typeof x === 'object'){
return rec(x, z);
}
else if(o !== c){
return false;
}
}
}
else if(o && typeof o === 'object'){
for(var n in o){
x = o[n]; z = c[n];
if(x && typeof x === 'object'){
return rec(x, z);
}
else if(o !== c){
return false;
}
}
}
else if(o !== c){
return false;
}
return true;
}
for(var i=0; i<l; i++){
if(!rec(st[i], sv[i])){
return false;
}
}
return true;
}
}使用jQuery UI实现如下所示:
var dragging;
function DragMaster(yourDraggable){
var d = yourDraggable, p = d.offset(), sm = new StateMaker({left:p.left, top:p.top})), states = sm.states, t = this;
function ls(){
if(states.length){
return states.slice(-1)[0];
}
return false;
}
this.update = function(){
var cp = d.offset();
sm.addState({left:cp.left, top:cp.top});
return this;
}
this.undo = function(){
sm.undo(); d.offset(ls());
return this;
}
this.redo = function(){
sm.redo(); d.offset(ls());
return this;
}
this.save = function(){
sm.save();
return this;
}
this.getStates = function(){
return states;
}
this.getSavedStates = function(){
return sm.savedStates;
}
this.init = function(){
return {
start: function(){
dragging = d;
},
stop: function(){
t.update();
}
}
}
}
var yd = $('#yourDraggable'), dm = new DragMaster(yd);
yd.draggable(dm.init());
$('#undo').click(function(){
if(dragging === yd)dm.undo();
});
$('#redo').click(function(){
if(dragging === yd)dm.redo();
});现在您可以创建new DragMaster()并将.init()发送到draggable。
注意:
如果您想要查看当前状态是否为已保存状态,以更改保存按钮的颜色,则可以使用StateMakerInstance.isSavedState()。
https://stackoverflow.com/questions/40077469
复制相似问题