如何在javascript中处理undo / redo事件?

我试图检测表单输入的值是否使用Javascript和JQuery更改。 不幸的是,我发现JQuery的$(elem).change()不足,因为它只会在elem失去焦点时触发更改事件。 我必须立即知道表单输入值的变化。 为此,我将与输入值的可能变化相关的事件缩小到了keyuppastecutundoredo 。 但是,javascript和JQuery似乎都没有办法处理撤消或重做。

 var onChange = function () { alert('Checking for changes...'); }; $(this).off('keyup').on('keyup', onChange); $(this).off('paste').on('paste', onChange); $(this).off('cut').on('cut', onChange); $(this).off('undo').on('undo', onChange); // undo ? $(this).off('redo').on('redo', onChange); // redo ? 

我在Google / JQuery中搜索了undo / redo事件,但没有找到任何有用的信息。 有人可以帮忙解决如何处理撤消/重做事件吗?

javascript中没有撤消或重做事件。 如果你想要这样的function,你要么必须自己在javascript中编写它,要么找到一个提供这种function的库。

如果你试图捕获所有可能改变输入控件的方法,以便你可以立即看到这样的改变,那么看一下这个示例代码: http : //jsfiddle.net/jfriend00/6qyS6/更改输入控件的回调。 此代码不是直接设计用于下拉列表,但由于它是输入控件的一种forms,因此您可以调整此代码以创建自己的下拉列表更改事件。

好吧,StackOverflow以其无限的智慧禁止我只发布对jsFiddle的引用,所以我必须在这里粘贴所有代码(出于某种原因,jsFiddles被挑出来而不是其他web引用)。 我不是将其表示为一个精确的解决方案,但作为模板,您可以使用它来检测用户对输入控件的更改:

 (function($) { var isIE = false; // conditional compilation which tells us if this is IE /*@cc_on isIE = true; @*/ // Events to monitor if 'input' event is not supported // The boolean value is whether we have to // re-check after the event with a setTimeout() var events = [ "keyup", false, "blur", false, "focus", false, "drop", true, "change", false, "input", false, "textInput", false, "paste", true, "cut", true, "copy", true, "contextmenu", true ]; // Test if the input event is supported // It's too buggy in IE so we never rely on it in IE if (!isIE) { var el = document.createElement("input"); var gotInput = ("oninput" in el); if (!gotInput) { el.setAttribute("oninput", 'return;'); gotInput = typeof el["oninput"] == 'function'; } el = null; // if 'input' event is supported, then use a smaller // set of events if (gotInput) { events = [ "input", false, "textInput", false ]; } } $.fn.userChange = function(fn, data) { function checkNotify(e, delay) { // debugging code if ($("#logAll").prop("checked")) { log('checkNotify - ' + e.type); } var self = this; var this$ = $(this); if (this.value !== this$.data("priorValue")) { this$.data("priorValue", this.value); fn.call(this, e, data); } else if (delay) { // The actual data change happens after some events // so we queue a check for after. // We need a copy of e for setTimeout() because the real e // may be overwritten before the setTimeout() fires var eCopy = $.extend({}, e); setTimeout(function() {checkNotify.call(self, eCopy, false)}, 1); } } // hook up event handlers for each item in this jQuery object // and remember initial value this.each(function() { var this$ = $(this).data("priorValue", this.value); for (var i = 0; i < events.length; i+=2) { (function(i) { this$.on(events[i], function(e) { checkNotify.call(this, e, events[i+1]); }); })(i); } }); } })(jQuery); function log(x) { jQuery("#log").append("
" + x + "
"); } // hook up our test engine $("#clear").click(function() { $("#log").html(""); }); $("#container input").userChange(function(e) { log("change - " + e.type + " (" + this.value + ")"); });

您可以使用MutationObserver监视所有更改。 这不会为每个keydown和keyup提供事件,但它会整合多个更改并将其作为单个事件提供给您。

  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // mutation.target will give you element which has been modified. // mutation.addedNodes and mutation.removedNodes will give you operations that were performed on the node // happy coding :) }); }); observer.observe(elementsToMonitor, { attributes: true, childList: true, characterData: true }); 

有关MutationObserver的更多信息, 请访问https://developer.mozilla.org/en/docs/Web/API/MutationObserver

John Resig(JQuery的创建者)的热键可能有所帮助

https://github.com/jeresig/jquery.hotkeys

从自述文件

如果你想使用多个修饰符(例如alt + ctrl + z),你应该按字母顺序定义它们,例如alt + ctrl + shift

   

基本概念是存储先前的输入值并检查新输入值是否等于先前输入值中的一个。 它并不完美(例如退格触发它)和效率稍低(见下一段),但你应该能够得到你想要的结果。

您可以查看撤消代码,而不是保留所有先前的输入,以查看它实际保留的内容(我认为它只会使大多数输入丢失,因为它们在彼此的时间范围内)。

曾经有一段时间我在我正在进行的项目中需要这样的东西。 对于我来说,标记的解决方案似乎并不优雅。 我在这里使用了几个回答的组合来做到这一点。

 function UndoListener(options){ if(!options.el instanceof HTMLElement) return; this.el = options.el; this.callback = options.callback || function(){}; this.expectedChange = false; this.init(); } UndoListener.prototype = { constructor: UndoListener, addListeners: function(){ this.el.addEventListener('keydown', (e) => this.expectedChange = this.eventChecker(e)); this.el.addEventListener('cut', (e) => this.expectedChange = true); this.el.addEventListener('paste', (e) => this.expectedChange = true); }, addObserver: function(){ this.observer = new MutationObserver((mt) => { if(!this.expectedChange){ this.expectedChange = true; this.observer.disconnect(); this.callback.call(this.el, { original: [...mt].shift().oldValue, current: this.el.innerText }); this.addObserver(); } this.expectedChange = false; }); this.observer.observe(this.el, { characterData: true, subtree: true, characterDataOldValue: true }); }, eventChecker: function(event) { return !(~['z','y'].indexOf(event.key) && (event.ctrlKey || event.metaKey)); }, init: function(){ this.addListeners(); this.addObserver(); } } 

这使用MutationObserver来“捕获”撤消事件。 这样做是因为MutationObserver在事件触发后触发。 我们检查事件是否是预期事件,如keydown或cut,并允许在没有回调触发的情况下进行更改。 如果事件是意外的,我们假设已发生撤消。 这无法区分撤销和重做; 回调将触发。 用法:

 var catcher = new UndoListener({ el: document.querySelector('.container'), callback: function(val){ console.log('callback fired', val); } }); 

我在codepen上有这个工作 。

我创建了一个状态撤消/重做快照管理器类,这对于跟踪包含子输入的整个HTML元素的更改历史记录非常有用。 如果要在更精细的级别上拍摄快照,可以绑定按键事件而不是我在示例中使用的更改事件。

  










看到这个JSFiddle: https ://jsfiddle.net/up73q4t0/56/