撤消&重做功能无法正常工作

时间:2016-10-17 01:54:19

标签: javascript jquery jquery-ui

我尝试为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();
});
&#13;
<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>
&#13;
&#13;
&#13;

这是一个Working code demo

现在,问题在于,例如,如果您运行我的代码并按以下顺序拖动元素(拖动#1,拖动#2,拖动#3),然后单击undo有时您必须单击两次,然后如果按顺序拖动并单击undo以恢复te开头的所有元素,然后drag elements #1 and #2 and then click on undo,您将注意到只有#1元素正在运行回到他的位置,所以我的问题是我做错了什么,我该如何解决这个问题呢?我想也许我的计数器错了或我的var historyApp

出了问题

2 个答案:

答案 0 :(得分:0)

您可能需要附加一个逻辑来检查undoredo的样式是否与prev / next状态不同:

        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]);

        },

答案 1 :(得分:0)

你的逻辑出了问题。这是我自己制作的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()