如何“撤消”将文本编程插入文本区?

我有一个textarea和一个按钮。 单击该按钮可将文本插入到textarea中。

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

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

var textEvent = document.createEvent('TextEvent'); textEvent.initTextEvent('textInput', true, true, null, "new text"); document.getElementById("your-textarea").dispatchEvent(textEvent); 

我认为最简单的方法是利用浏览器的撤销堆栈而不是捕获事件。

为此,您需要为不同的浏览器使用不同的代码。 幸运的是,在所有主流浏览器中,只有Firefox有不同的方法。

 // http://stackoverflow.com/a/9851769/529024 // Opera 8.0+ var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; // Firefox 1.0+ var isFirefox = typeof InstallTrigger !== 'undefined'; // Safari 3.0+ "[object HTMLElementConstructor]" var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 || (function(p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification); // Internet Explorer 6-11 var isIE = /*@cc_on!@*/ false || !!document.documentMode; // Edge 20+ var isEdge = !isIE && !!window.StyleMedia; // Chrome 1+ var isChrome = !!window.chrome && !!window.chrome.webstore; var position = 0; // text to anser var text = 'Inserted Text'; // Just for fun :) if (isFirefox) text = " __ Firefox __ "; else if (isIE) text = " __ IE __ "; else if (isEdge) text = " __ Edge __ "; else if (isSafari) text = " __ Safari __ "; else if (isOpera) text = " __ Opera __ "; else if (isChrome) text = " __ Chrome __ "; /* Adding text on click based on browser */ jQuery(".addText").on("click", function() { if (isFirefox) { // Firefox var val = jQuery(".textArea").val(); var firstText = val.substring(0, position); var secondText = val.substring(position); jQuery(".textArea").val(firstText + text + secondText); } else { jQuery(".textArea").focus(); var val = jQuery(".textArea").val(); jQuery(".textArea")[0].selectionStart = position; jQuery(".textArea")[0].selectionEnd = position; document.execCommand('insertText', false, text); } }); jQuery(".textArea").on("focusout", function(e) { position = jQuery(this)[0].selectionStart; }); 
 textarea { padding: 10px; font-family: Calibri; font-size: 18px; line-height: 1.1; resize: none; } .addText { padding: 5px 15px; transition: all 0.5s; border: 1px solid black; border-radius: 2px; background-color: #169c16; width: 70px; margin: 10px 0; color: white; cursor: pointer; } .addText:hover { background-color: #2776b9; } 
   
Add Text

textarea的原始值保存在其data

 var $textarea = $('textarea'); $('button').on('click', function () { var val = $textarea.val(); $textarea.data('old-val', val).val(val + ' some text'); }); 

如果你想要一个数据数组(如@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'); }); 
 $("#target").keypress(function(event) { if ( event.which == 'Z' && first press == 'Cmd' && second press == 'Ctrl') {//check for key press event.preventDefault(); text.value = defaultValueForTextField } }); 

这应该是你正在寻找的。 第一次和第二次按下需要保存,因为您需要组合按。 您确实需要保存默认文本值。

这是一个想法:

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

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

  var e1 = new KeyboardEvent(, 
); var b1 = .dispatchEvent(e1);

哪里:

  • 表示事件类型,例如keydownkeypresskeyup

  • 表示具有事件详细信息的对象,例如keycode

  • 表示我们想要触发事件的目标文本框

这是一个JSFiddle ,我试图模拟给定字符串中每个字符的keydown , keypress和keyup事件。 虽然它触发了相应的事件处理程序,但不知何时字符不会显示/添加到文本框中。

我注意到的是,当我在使用我的代码模拟3个事件时,在文本框中键入a时生成的事件对象存在一些差异。 不同之处(在Firefox 50.1.0中测试时):

  1. 当我模拟事件时, explicitOriginalTargetoriginalTarget不同; 当我输入文本框时,它们都具有相同的值
  2. 当我在文本框中键入时, rangeParentrangeOffset值为null / 0 ; 当我模拟事件时,他们有一些价值观
  3. 当我输入文本框时, isTrusted属性为true ; 当我模拟事件时它是false (对于使用脚本生成的任何事件,它将是false

MDN链接:

  • 创建和触发内置事件
  • 的KeyboardEvent
  • KeyboardEvent构造函数

即使这个问题是一年前的问题,我也想分享我的方式。

你可以这样做:

  $(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; } }); }); 

如果你想试验它,这是一个小提琴http://jsfiddle.net/45Jwz/1/

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

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

我可以立即想到两种通用方式。

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

这是一种快速的方法,如果您想要一个具有一次以上编辑历史记录的堆栈,则效果不佳。

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

使用redux / flux架构可以非常简单http://redux.js.org/docs/recipes/ImplementingUndoHistory.html

要捕获cmd / ctrl + z,您可以查看https://github.com/madrobby/keymaster

如果你详细说明你的堆栈/要求,我很乐意扩展这个答案。

最简单的方法似乎是这样的:

  • 在DOM textarea本身的属性中按钮单击保存以前的textarea内容。
  • 截取BODY级别的键盘(你不知道当命中Ctrl-Z时焦点在哪里)
  • (可选) 还根据需要截取来自不同对象的许多事件 :input,keyPress等,同样在BODY级别。

现在:

  • 当用户单击该按钮时,将保存旧内容并将textarea的自定义“脏”属性设置为true
  • 如果用户按Ctrl-Z或Cmd-Z,则撤销例程很简单(在jQuery中为$('#idOfTextarea').val($('#idOfTextarea').attr('prevContents'));撤消例程还会清除“脏”属性,以便不会调用两次撤消。
  • (可选)如果用户改变另一个字段,点击其他地方等,textarea的dirty属性也被清除,并且更改变为可撤消。
  • (可选)具有自己的撤消function的对象可以/必须停止事件传播以避免其他撤消具有两种效果。

您可能想要或不想在textarea上拦截onChange。 如果onChange触发并且未设置脏,则这是初始按钮单击,可能会被忽略。 否则,它可能表示用户已将其自己的一些更改添加到单击的文本中。在这种情况下,您可能希望禁用撤消以保留这些更改,或要求用户进行确认。

你可以这样做,

HTML

 

jQuery的

 var oldText = [],ctrl=false; $(function(){ $("input[name=Insert]").click(function(){ var text = oldText.length+1; oldText.push(text); var textAreaText = $('textarea').val(); textAreaText +=text; $('textarea').val(textAreaText); $("input[name=insertText]").val(''); }); $('textarea').keydown(function(e){ if(e.which == 17){ ctrl = true;} }); $('textarea').keyup(function(e){ var c = e.which; if(c == 17){ ctrl = false;} if(ctrl==true && c==90 ){ oldText.pop(); var text = ''; $.each(oldText,function(i,ele){ text += ele; }); $('textarea').val(text); } }) }) 

您还可以检查并试验小提琴 。

首先添加html,然后您可以使用按键事件进行撤消

你也可以在这里试试http://jsfiddle.net/surendra786/1v5jxaa0/

    
ADD
UNDO

**然后添加jquery **

  var items = []; $("#add").click(function() { // Push the new actor in the array items.push($("[name='actor']").val()); populate(); }); $(document).keydown(function(e){ if( e.which === 90 && e.ctrlKey ){ console.log('control + z'); if (items.length > 0) { // remove last element of the array items.splice(-1,1); populate(); } } }); populate = function() { $("[name='actors-list']").text(''); $("[name='actors-list']").append(items.join('
')); $("[name='actors']").val(items.join(',')); } 

你可以在这里试试http://jsfiddle.net/surendra786/1v5jxaa0/

这对我有用

这里有很多适用的答案可以满足您的需求。 这是我在你的环境中会做的事情。 这允许更改您最有可能使用的文本变量,您可以设置它,或者用户可以使用其他字段设置它等。

codepen在这里

它的主旨就是这样的。

 $(document).ready(function(){ function deployText(){ var textArray = []; var textToAdd = 'let\'s go ahead and add some more text'; var textarea = $('textarea'); var origValue = textarea.text(); textArray.push(origValue); $('button').on('click', function(e){ textArray.push(textToAdd); textarea.text(textArray); console.log(textArray.length); console.log(textArray); }); $(document).on('keypress', function(e){ var zKey = 26; if(e.ctrlKey && e.which === zKey){ removePreviousText(); } }) function removePreviousText(){ console.log(textArray); if(textArray.length > 1){ textArray.pop(); $('textarea').text(textArray); } } } deployText() })