Javascript “我怎么能?”;撤销;将文本以编程方式插入文本区域?

Javascript “我怎么能?”;撤销;将文本以编程方式插入文本区域?,javascript,jquery,textarea,undo,Javascript,Jquery,Textarea,Undo,我有一个文本区和一个按钮。单击按钮可将文本插入文本区域 <input type="text" class="reset actor_input" name="actor" value="add actors"></input> <input type="text" name="actors"></input> <div class="found_actors">

我有一个文本区和一个按钮。单击按钮可将文本插入文本区域

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>

是否有一种方法允许用户按Ctrl/Cmd+z撤消文本插入并将textarea恢复到以前的状态?

textarea
的原始值保存在其
数据中:

var $textarea = $('textarea');

$('button').on('click', function () {
    var val = $textarea.val();

    $textarea.data('old-val', val).val(val + ' some text');
});
            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
如果需要数据数组(如@ahren建议的),请使用以下命令:

var $textarea = $('textarea');

$('button').on('click', function () {
    var val = $textarea.val();

    if ( ! $textarea.data('old-val')) {
        $textarea.data('old-val', []);
    }

    $textarea.data('old-val').push(val);

    $textarea.val(val + ' some text');
});
            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>

您需要以特殊的方式插入文本,以便用户可以使用正常的撤消/重做行为

var textEvent = document.createEvent('TextEvent');

textEvent.initTextEvent('textInput', true, true, null, "new text");

document.getElementById("your-textarea").dispatchEvent(textEvent);
            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>

那应该是你要找的。第一次和第二次按下将需要保存为您想要的组合按下。不过,您确实需要保存一个默认文本值。

即使这个问题已经提出一年了,我也想分享一下我的方法

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
您可以这样做:

    $(function () {

  // Check to see if an array is not already defined.
  if (!$('#t').data('old-val')) {

    // If the check returns True we proceed to create an array in old-val.
    $('#t').data('old-val', []);

  }

  // Get the current content value.
  inputValue = $('#t').val();

  // Push it to the old-val array.
  $('#t').data('old-val').push(inputValue);

  // We start with a current array position of 0.
  curArrPos = 0;


  $('#c').click(function () {
    // Append a string to the #t.
    $('#t').val(' ==this is the 2nd appended text==');


    // Save the current content value.
    inputValue = $('#t').val();
    // Push it to the array.
    $('#t').data('old-val').push(inputValue);
    // Increment current array position.
    ++curArrPos;

  });


  $('#b').click(function () {
    // Append a string to the #t.
    $('#t').val(' ==this is the 1st appended text==');


    // Save the current content value.
    inputValue = $('#t').val();
    // Push it to the array.
    $('#t').data('old-val').push(inputValue);
    // Increment current array position.
    ++curArrPos;

  });

  $('#undo').click(function () {
    // First check that the old-val array length is greater than 1 (It's the initial position. No need undoing to a blank state) and current array position greater than 0 (for the same reason).
    if ($('#t').data('old-val').length > 1 && curArrPos > 0) {

      // Set current #t value to the one in the current array position, minus one.
      // Minus one gets you to the previous array position (ex. current=5; previous= current - 1 = 4).
      $('#t').val($('#t').data('old-val')[curArrPos - 1]);

      // Decrease current array position, because we effectively shifted back by 1 position.
      --curArrPos;
    }
  });

  $('#redo').click(function () {
    if (currentArrayPos < $('#c').data('old-val').length - 1) {

      $('#t').val($('#t').data('old-val')[curArrPos + 1]);

      // Increase current array position, because we effectively shifted forward by 1 position.
      ++curArrPos;

    }
  });

});
            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
$(函数(){
//检查是否尚未定义数组。
if(!$('#t').data('old-val')){
//如果检查返回True,我们将继续在old-val中创建一个数组。
$('t')。数据('old-val',[]);
}
//获取当前内容值。
inputValue=$('#t').val();
//将其推送到旧的val数组。
$('t').data('old-val').push(inputValue);
//我们从当前数组位置0开始。
curArrPos=0;
$('#c')。单击(函数(){
//将字符串附加到#t。
$('#t').val('==这是第二个附加文本==');
//保存当前内容值。
inputValue=$('#t').val();
//将其推到阵列中。
$('t').data('old-val').push(inputValue);
//增加当前阵列位置。
++库拉尔波斯;
});
$('#b')。单击(函数(){
//将字符串附加到#t。
$('#t').val('==这是第一个附加文本==');
//保存当前内容值。
inputValue=$('#t').val();
//将其推到阵列中。
$('t').data('old-val').push(inputValue);
//增加当前阵列位置。
++库拉尔波斯;
});
$('#撤消')。单击(函数(){
//首先检查旧的val数组长度是否大于1(它是初始位置。无需撤消为空白状态),当前数组位置是否大于0(出于相同的原因)。
if($('#t').data('old-val').length>1&&curArrPos>0){
//将当前#t值设置为当前数组位置的值减去1。
//减1将返回上一个数组位置(例如,current=5;previous=current-1=4)。
$('t').val($('t').data('old-val')[curArrPos-1]);
//减少当前阵列位置,因为我们有效地向后移动了1个位置。
--库拉尔波斯;
}
});
$('#重做')。单击(函数(){
如果(currentArrayPos<$('#c')。数据('old-val')。长度-1){
$('t').val($('t').data('old-val')[curArrPos+1]);
//增加当前阵列位置,因为我们有效地向前移动了1个位置。
++库拉尔波斯;
}
});
});
这是一把小提琴,如果你想试试的话

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>

我这样写代码是为了更好地理解,但您当然应该编写比这更好、更简洁的实际代码。

具体的库和技术很大程度上取决于您的堆栈

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
我可以马上想到两种方法

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
第一: 在控制器中保存以前的状态。钩住快捷方式并将内容替换为以前的状态。如果进行了其他修改,则删除挂钩。或多或少你的2013年方法

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
这是一种快速的方法,如果您想要一个包含多个一次性编辑历史的堆栈,那么这种方法并不好用

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
第二: 观察textinput并定期将状态保存在堆栈上。钩住捷径。(接管整个过程)。 这是一种更简洁的方式,因为您的修改在概念上与用户修改相同

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
对于redux/flux架构,这可能非常简单

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
为了捕获cmd/ctrl+z,您可以查看

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
如果您能详细介绍一下您的堆栈/需求,我很乐意扩展这个答案。

以下是一个想法:

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
如果我们可以像用户在文本区域中键入一样生成keyborad事件,那么浏览器将自动处理撤销事件。因此,我们不应该只是附加/更改textarea的值,而应该尝试为要插入的文本模拟键盘事件

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
根据MDN上的文档(下面给出的链接),我们可以使用
KeyboardEvent
对象生成如下事件:

  var e1 = new KeyboardEvent(<type>, <details>);
  var b1 = <textbox>.dispatchEvent(e1);
            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
var e1=新键盘事件(,);
变量b1=.dispatchEvent(e1);
其中:

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
  • 表示事件类型,例如
    keydown
    keypress
    keypup
  • 表示具有事件详细信息的对象,例如
    代码
  • 表示要在其上触发事件的目标文本框
在这里,我尝试为给定字符串中的每个字符模拟
keydown
keypress
keyup
事件。虽然它会触发相应的事件处理程序,但不知何故,字符没有显示/添加到textbox

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
我注意到,在文本框中键入
a
时生成的事件对象与使用代码模拟
a
的3个事件时生成的事件对象存在一些差异。区别在于(在Firefox 50.1.0中测试时):

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>
  • 模拟事件时,
    explicitOriginalTarget
    originalTarget
    不同;当我在文本框中输入时,两者都有相同的值
  • rangeParent
    rangeOffset
    在文本框中键入时,值为
    null
    /
    0
    ;当我模拟这些事件时,它们有一些值
  • 当我在文本框中键入时,
    isTrusted
    属性为
    true
    ;当我模拟事件时,它的
    false
    (对于使用脚本生成的任何事件,它将具有
    false
  • MDN l