IE 10, 11. 如何防止带占位符的文本输入在焦点上触发输入事件?

IE 10, 11. How to prevent the triggering of input events on focus from text input with placeholder?

在 IE 11 中,如果我有一封带有 placeholder 的空电子邮件 input,然后在单击(聚焦)它时,将触发 input 事件。

有人知道为什么吗?有没有解决办法,因为 input 值并没有真正改变?

var el = document.getElementById('myEmail');
el.addEventListener("input", myFunction, true);
function myFunction()
{
    alert("changed");
}
<input id="myEmail" type="email" placeholder="Email">
    

这似乎是一个错误。 oninput 已受支持,因为 IE9 应仅在更改值时触发。另一种方法是使用 onkeyup

https://developer.mozilla.org/en-US/docs/Web/Events/input

如果你想处理输入和验证,你可以添加第二个事件监听器(假设你的 html 与上面相同)。

var el = document.getElementById('myEmail');
function myFunction() {
  console.log("changed");
}
el.addEventListener("keyup", myFunction, true);
function validation() {
  console.log("validated");
}
el.addEventListener("keyup", validation, true);

我来晚了,但我遇到了同样的问题,我想出了一个解决方法来修复 IE 上的这种行为。 事实上,有两个不同的错误(或者更确切地说,只有一个错误,但有两种行为,具体取决于目标是输入还是文本区域)。

  • For input :每次字段视觉内容改变时触发事件,包括键盘输入(自然),也包括占位符 appears/disappears(无内容时模糊),或者以编程方式更改可见占位符时。
  • 对于textarea:基本相同,只是占位符消失时不触发事件。

function onInputWraper(cb) {
    if (!window.navigator.userAgent.match(/MSIE|Trident/)) return cb;


    return function (e) {
        var t = e.target,
            active = (t == document.activeElement);
        if (!active || (t.placeholder && t.composition_started !== true)) {
            t.composition_started = active;
            if ((!active && t.tagName == 'TEXTAREA') || t.tagName == 'INPUT') {
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        }
        cb(e);
    };
}

var el = document.getElementById('myEmail');
el.addEventListener("input", onInputWraper(myFunction), true);
function myFunction() {
    alert("changed");
}
<input id="myEmail" type="email" placeholder="Email">

还有一个完整的示例,您还可以在其中更改占位符值

function onInputWraper(cb) {
  if (!window.navigator.userAgent.match(/MSIE|Trident/)) return cb;


  return function (e) {
    var t = e.target,
        active = (t == document.activeElement);
    if (!active || (t.placeholder && t.composition_started !== true)) {
      t.composition_started = active;
      if ((!active && t.tagName == 'TEXTAREA') || t.tagName == 'INPUT') {
        e.stopPropagation();
        e.preventDefault();
        return false;
      }
    }
    cb(e);
  };
}

function handle(event) {
  console.log('EVENT', event);
  document.getElementById('output')
    .insertAdjacentHTML('afterbegin', "<p>" + event.type + " triggered on " + event.target.tagName +
                        '</p>');
}

var input = document.getElementById('input'),
    textarea = document.getElementById('textarea');

input.addEventListener('input', onInputWraper(handle));
textarea.addEventListener('input', onInputWraper(handle));
// input.addEventListener('input', handle);
// textarea.addEventListener('input', handle);

// Example's settings

function removeListeners(elem) {
  var value = elem.value,
      clone = elem.cloneNode(true);
  elem.parentNode.replaceChild(clone, elem);
  clone.value = value;
  return clone;
}

document.querySelector('#settings input[type="checkbox"]').addEventListener('change', function (event) {
  if (event.target.checked) {
    document.getElementById('output').insertAdjacentHTML('afterbegin', '<p>Filter enabled !</p>');

    //input = removeListeners(input);

    console.log(input.value.length, (input == document.activeElement));

    input = removeListeners(input);
    input.addEventListener('input', onInputWraper(handle));
    input.composing = input.value.length > 0 || (input == document.activeElement);

    textarea = removeListeners(textarea);
    textarea.addEventListener('input', onInputWraper(handle));
    textarea.composing = textarea.value.length > 0 || (textarea == document.activeElement);

  } else {
    document.getElementById('output').insertAdjacentHTML('afterbegin', '<p>Filter disabled !</p>');

    input = removeListeners(input);
    input.addEventListener('input', handle);
    input.composing = void 0;

    textarea = removeListeners(textarea);
    textarea.addEventListener('input', handle);
    textarea.composing = void 0;

  }
});

document.getElementById('input_cfg').addEventListener('click', function () {
  document.getElementById('input').setAttribute('placeholder', document.getElementById(
    'input_placeholder').value);
});
document.getElementById('textarea_cfg').addEventListener('click', function () {
  document.getElementById('textarea').setAttribute('placeholder', document.getElementById(
    'textarea_placeholder').value);
});
* {
  font: 15px arial, sans-serif;
}

dd {
  background: FloralWhite;
  margin: 0;
}

dt {
  padding: 15px;
  font-size: 1.2em;
  background: steelblue;
  color: AntiqueWhite;
}

p {
  margin: 0;
}

button,
label {
  width: 300px;
  margin: 5px;
  padding: 5px;
  float: left;
  color: DarkSlateGray;
}

#settings label {
  width: 100%;
  margin: 15px;
}

#forms input,
#forms textarea,
#settings input:not([type]) {
  display: block;
  width: calc(100% - 340px);
  padding: 7px;
  margin: 0;
  margin-left: 320px;
  min-height: 25px;
  border: 1px solid gray;
  background: white;
  cursor: text;
}

::placeholder {
  /* Chrome, Firefox, Opera, Safari 10.1+ */
  color: LightBlue;
  opacity: 1;
  /* Firefox */
}

::-ms-input-placeholder {
  /* Microsoft Edge */
  color: LightBlue;
}

:-ms-input-placeholder {
  /* Internet Explorer 10-11 */
  color: LightBlue;
}
<dl>
  <dt>Forms</dt>
  <dd id="forms">
    <label for="input">Input: </label>
    <input id="input" name="input" class="testing" placeholder="Type some text" />
    <label for="texarea">Textarea: </label>
    <textarea id="textarea" name="textarea" placeholder="Type some text"></textarea>
  </dd>
  <dt>Settings</dt>
  <dd id="settings">
    <p>
      <label><input type="checkbox" checked>Enable filtering script</label>
      <button id="input_cfg">Change input's placeholder to</button><input id="input_placeholder" />
    </p>
    <p>
      <button id="textarea_cfg">Change textarea's placeholder to</button>
      <input id="textarea_placeholder" />
    </p>
  </dd>
  <dt>Output</dt>
  <dd id="output"></dd>
</dl>

or on jsfiddle

解决方案非常简短!

起初我们不需要那么多我们可以在接受的答案中看到的代码。其次你必须明白为什么会这样:

  1. Fake oninput 事件仅在输入 placeholder 获得焦点时触发,并且仅在输入值为空时触发。发生这种情况是因为 IE 的不良开发人员认为输入值从 placeholder value 变为真实的 value,但这是 IE 的不良开发人员的误解。
  2. 没有占位符的 input 没有这个问题。

第一个解决方案非常简单:如果您确实不需要,请不要使用 placeholder。在大多数情况下,您可以向元素添加 title 而不是 placeholder。您也可以在 input.

之前、下方或上方写下您的 placeholder 文本

如果你必须使用 placeholder

第二个解决方案也非常简单和简短:将之前的 value 保存在 input 对象上,并将其与新的 value 进行比较——如果没有更改,则 return 来自代码之前的函数。

生活实例

var input = document.querySelector('input[type=search]');
input.addEventListener('input', function(e)
{
    if(this.prevVal == this.value /* if the value was not changed */
        || !this.prevVal && '' == this.value) //only for the first time because we do not know the previous value
        return; //the function returns "undefined" as value in this case

    this.prevVal = this.value;

    //YOUR CODE PLACE

    console.log('log: ' + this.value)

}, false);
<input type="search" placeholder="Search..."/>

或者如果您将其用作内联 JavaScript:

function onSearch(trg)
{
    if(trg.prevVal == trg.value /* if the value was not changed */
        || !trg.prevVal && '' == trg.value) //only for the first time because we do not know the previous value
        return; //the function returns "undefined" as value in this case

    trg.prevVal = trg.value; // save the previous value on input object

    //YOUR CODE PLACE

    console.log('log: ' + trg.value);
}
<input type="search" placeholder="Search..." oninput="onSearch(this)"/>