【问题标题】:textarea undo & redo button using only plain JavaScript仅使用纯 JavaScript 的 textarea 撤消和重做按钮
【发布时间】:2019-09-08 07:27:52
【问题描述】:

我了解 Chrome 已内置 CTRL Z 和 Y 用于撤消和重做功能。但是,撤消/重做按钮是否可以使用纯 JavaScript 在 textarea 上工作?

我发现这里的代码(由 Neil 回答)很有帮助,但它需要 jQuery: How do I make undo/redo in <textarea> to react on 1 word at a time, word by word or character by character?

【问题讨论】:

  • 所以你基本上是在问一个新问题,将另一个问题的答案从 JQuery 转换为普通的 JS .. 为什么不直接在你之前的问题上问这个?

标签: javascript textarea


【解决方案1】:

这是我制作的 StateMaker。它用于撤消、重做和保存。这很简单。它工作正常。

问题是 e.ctrlKey &amp;&amp; e.key === 'z' 之类的行为很奇怪,当 e.preventDefault() 在 Firefox 中时,所以我删除了该部分。下面的代码当然是不完美的,因为如果单词和状态的长度相同,它会覆盖最后一个状态。但是,如果我不这样做,它会为每个角色保存一个状态,这也是可行的。另一种解决方案是根据时间保存状态。在这个例子中我没有走那条路。

//<![CDATA[
/* external.js */
/* StateMaker created by Jason Raymond Buckley */
var doc, bod, I, StateMaker; // for use on other loads
addEventListener('load', function(){
doc = document; bod = doc.body;
I = function(id){
  return doc.getElementById(id);
}
StateMaker = function(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(){ // test to see if current state in use is a saved state
    if(JSON.stringify(this.states) !== JSON.stringify(this.savedStates)){
  return false;
}
return true;
  }
}
var text = I('text'), val, wordCount = 0, words = 0, stateMaker = new StateMaker, save = I('save');
text.onkeyup = function(e){
  save.className = undefined; val = this.value.trim(); wordCount = val.split(/\s+/).length;
  if(wordCount === words && stateMaker.states.length){
    stateMaker.states[stateMaker.states.length-1] = val;
  }
  else{
    stateMaker.addState(val); words = wordCount;
  }
}
I('undo').onclick = function(){
  stateMaker.undo(); val = text.value = (stateMaker.states[stateMaker.states.length-1] || '').trim();
  text.focus();
  save.className = stateMaker.isSavedState() ? 'saved' : undefined;
}
I('redo').onclick = function(){
  stateMaker.redo(); val = text.value = (stateMaker.states[stateMaker.states.length-1] || '').trim();
  text.focus();
  save.className = stateMaker.isSavedState() ? 'saved' : undefined;
}
save.onclick = function(){
  stateMaker.save(); text.focus(); this.className = 'saved';
}
}); // end load
//]]>
/* external.css */
*{
  padding:0; margin:0; border:0; box-sizing:border-box;
}
html,body{
  width:100%; height:100%; background:#aaa; color:#000;
}
input{
  font:22px Tahoma, Geneva, sans-serif; padding:3px;
}
#text{
  width:calc(100% - 20px); height:calc(100% - 70px); font:22px Tahoma, Geneva, sans-serif; padding:3px 5px; margin:10px;
}
#undoRedoSave{
  text-align:right;
}
input[type=button]{
  padding:0 7px; border-radius:5px; margin-right:10px; border:2px solid #ccc;
}
input[type=button].saved{
  border:2px solid #700;
}
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1' />
    <title>Test Template</title>
    <link type='text/css' rel='stylesheet' href='external.css' />
    <script type='text/javascript' src='external.js'></script>
  </head>
<body>
  <textarea id='text'></textarea>
  <div id='undoRedoSave'>
    <input id='undo' type='button' value='undo' />
    <input id='redo' type='button' value='redo' />
    <input id='save' type='button' value='save' />
  </div>
</body>
</html>

【讨论】:

    猜你喜欢
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    • 2021-04-12
    相关资源
    最近更新 更多