In Chrome undo does not work properly for input el

2020-02-12 10:23发布

问题:

In Chrome, I noticed that undo does not work properly for input element after the contents of the element has been changed programmatically. Although I get different behaviours for different browsers, they're not as bad as Chrome.

FF20      good
IE9       some support (undo stack cleared when input loses focus)
Safari5   some support (undo stack cleared when input loses focus)
Chrome26  unreliable

For example, a script that trims spaces (see also jsfiddle below)

  • type some spaces before "hello!",
  • click outside the input element
  • click on the input element and press Ctrl-Z

now the text is gone (in Chome)

jsfiddle here

<input type="text" id="input1" value="hello!">

document.getElementById("input1").addEventListener('blur', function(evt){elementLosesFocus(evt, this);}, false);

function elementLosesFocus(evt, caller)
{
    caller.value = caller.value.trim();
}

I think the best thing I can hope for is a method to somehow clear the undo history of the input when it loses focus (as is the case with IE and Safari).

回答1:

Chrome doesn't store the field's states, but rather a diff or set of deltas for each undo/redo. It takes less memory, but causes the bug you're dealing with.

You can effectively simulate the user pasting a value into the field by using document.execCommand("insertText", false, "text to insert");.

For your particular case:

  1. First, save the field's value to a variable. var temp = caller.value;
  2. Next, clear the field's value or set its selectionStart to 0 and selectionEnd to the field's length. This way a simulated paste replaces the field's contents.
  3. Next, make sure the field has the focus. caller.focus();
  4. Finally, simulate the user pasting in the modified value. document.execCommand("insertText", false, temp.trim());

I found this solution in another SO question, https://stackoverflow.com/a/10345596/1021426