javascript - Diferența dintre evenimentul "change" și "input" pentru un element `input`


Poate cineva să-mi spună care este diferența dintre evenimentele change și input?

Folosesc jQuery pentru a le adăuga:

$('input[type="text"]').on('change', function() {
    alert($(this).val());
})

Funcționează și cu input în loc de change.

Poate o diferență în ordonarea evenimentelor în raport cu focalizarea?

Răspuns #1

Conform acestei postări:

  • Evenimentul oninput apare atunci când conținutul textului unui element este modificat prin intermediul interfeței utilizatorului.

  • onchange apare atunci când selecția, starea bifată sau conținutul unui element s-a schimbat. În unele cazuri, apare doar atunci când elementul își pierde focalizarea sau la apăsarea tastei return (Enter) și valoarea a fost modificată. Atributul onchange poate fi utilizat cu: <input>, <select> și <textarea>.

Rezumat:

  • oninput: orice modificare făcută în conținutul textului
  • onchange:

    • Dacă este un <input />: schimbă + pierde focusul
    • Dacă este un <select>: schimbă opțiunea

$("input, select").on("input", function () {
    $("pre").prepend("\nOn input. | " + this.tagName + " | " + this.value);
}).on("change", function () {
    $("pre").prepend("\nOn change | " + this.tagName + " | " + this.value);
}).on("focus", function () {
    $("pre").prepend("\nOn focus | " + this.tagName + " | " + this.value);
}).on("blur", function () {
    $("pre").prepend("\nOn blur | " + this.tagName + " | " + this.value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
<select>
  <option>Alice</option>
  <option>Bob</option>
  <option>Carol</option>
  <option>Dave</option>
  <option>Emma</option>
</select>
<pre></pre>

Răspunsul #2

  • Evenimentul change se declanșează în majoritatea browserelor atunci când conținutul este modificat și elementul pierde focus. Practic, este un agregat de modificări. Nu se va declanșa pentru fiecare modificare în parte, așa cum se întâmplă în cazul evenimentului input.

  • Evenimentul input se declanșează sincron la modificarea conținutului elementului. Astfel, ascultătorul de evenimente tinde să se declanșeze mai frecvent.

  • Browserele diferite nu sunt întotdeauna de acord dacă trebuie declanșat un eveniment de schimbare pentru anumite tipuri de interacțiuni

Răspunsul #3

Se pare că această întrebare a devenit una dintre acele întrebări pe care le vizitez din când în când. Nu sunt fan să citesc ziduri de text pentru lucruri simple. Așa că am decis să postez un răspuns practic.

Folosind următorul demo, se poate examina care evenimente sunt declanșate și în ce ordine.

let eventsToListen = [
    "focus",
    "blur",
    "input",
    "change",
];
let inputs = Array.from(
    document.querySelectorAll("#inputs :is(input, textarea, select)")
);
inputs.forEach(input => {
    input.eventQueue = [];
    let queueLimit = eventsToListen.length * 2;
    let queueDisplay = input.closest("td").nextElementSibling;
    eventsToListen.forEach(event => {
        input.addEventListener(event, () => {
            input.eventQueue.push(event);
            if (input.eventQueue.length > queueLimit) {
                Array(input.eventQueue.length - queueLimit).fill(null).forEach(
                    _ => input.eventQueue.shift()
                );
            }
            queueDisplay.textContent = input.eventQueue.join(", ");
        });
    });
});
* {
    margin: 0;
    padding: 0;
    box-sizing: inherit;
    color: inherit;
    font-size: inherit;
    font-family: inherit;
    line-height: inherit;
}
body {
    font-family: sans-serif;
    box-sizing: border-box;
    background-color: hsl(0, 0%, 90%);
}
#inputs {
    margin: 1em;
}
#inputs td {
    padding: 0.1em;
}
#inputs td:nth-child(2) :not(input[type=radio]):not(input[type=checkbox]) {
    width: 100%;
}
#inputs label {
    display: table;
}
#inputs td:last-child {
    font-style: italic;
    font-size: 0.8em;
    opacity: 0.7;
    padding-left: 1em;
}
#notices {
    margin: 1em;
}
#notices ul {
    padding-left: 2em;
    line-height: 2;
}
#notices > ul {
    margin-top: 0.5em;
}
input[type=radio]:focus,
input[type=checkbox]:focus {
    transform: scale(1.5);
}
<table id="inputs">
    <tr>
        <td>text</td>
        <td><input type="text" /></td>
        <td></td>
    </tr>
    <tr>
        <td>number</td>
        <td><input type="number" /></td>
        <td></td>
    </tr>
    <tr>
        <td>textarea</td>
        <td><textarea></textarea></td>
        <td></td>
    </tr>
    <tr>
        <td>select</td>
        <td>
            <select>
                <option>-</option>
                <option>Option 1</option>
                <option>Option 2</option>
                <option>Option 3</option>
            </select>
        </td>
        <td></td>
    </tr>
    <tr>
        <td rowspan="2">radio</td>
        <td>
            <label><input type="radio" name="something" /> Option 1</label>
        </td>
        <td></td>
    </tr>
    <tr>
        <td>
            <label><input type="radio" name="something" /> Option 2</label>
        </td>
        <td></td>
    </tr>
    <tr>
        <td style="padding-right: 0.5em">checkbox</td>
        <td>
            <label><input type="checkbox" name="something2" /> Option 1</label>
        </td>
        <td></td>
    </tr>
</table>

<hr>

<div id="notices">
    notice that:
    <ul>
        <li>"input" event can occur multiple times before a "change" event occurs on text/number/textarea</li>
        <li>"input" and "change" event seem to occur together/sequentially on select</li>
        <li>"input"/"change" event might occur multiple times before a "blur" event occurs on select
            <ul>
                <li>when arrow keys are used to select an option</li>
            </ul>
        </li>
    </ul>
</div>

Răspunsul #4

Rezumat: Cea mai mare diferență este ce cauzează schimbarea valorii:

  • Evenimentele input se declanșează la orice modificare de valoare
  • Evenimentele change se declanșează la modificările de valoare inițiate direct de utilizator

    • (Detaliile exacte ale acestuia variază între tipurile de intrare)

Cea mai semnificativă diferență între aceste două evenimente este ce determină schimbarea value pe <input>.

Conform MDN:

Evenimentul input se declanșează atunci când value al unui element <input>, <select> sau <textarea> a fost modificat.

Cu alte cuvinte, input se declanșează de fiecare dată când value se schimbă.

schimbare este puțin mai complicată:

Evenimentul change este declanșat pentru elementele <input>, <select> și <textarea> atunci când o modificare a value a elementului este confirmată de utilizator. Spre deosebire de evenimentul input, evenimentul change nu este neapărat declanșat pentru fiecare modificare a value a unui element.

Cu alte cuvinte, change se declanșează atunci când utilizatorul schimbă valoarea. În plus, change se declanșează, în general, doar atunci când valoarea finală este diferită de cea inițială (așa cum sugerează și numele său).

Pentru <input> în mod specific, momentul exact al evenimentului change depinde de atributul type al inputului. În general:

  • Pentru tipurile de intrare bazate pe text (de exemplu: search, text, email, password etc.):

    • Când elementul pierde focusul (la pierderea focalizării).
  • Pentru intrări care deschid un fel de meniu interactiv (de exemplu file, date, color, etc.):

    • Când elementul UI este închis.
    • Dacă tipul are un mecanism de introducere directă a textului (ca date), atunci acesta declanșează și la fiecare introducere de text (de exemplu, la fiecare cifră tastată).
  • Pentru intrările non-textuale care sunt interactive (de exemplu checkbox, radio și range):

    • Când elementul rămâne într-o stare nouă după interacțiunea cu el (de exemplu, clic, glisare, declanșarea unei scurtături de la tastatură).

Există câteva elemente cu nuanțele lor proprii, dar acestea sunt adevărate în cazul general.


Demonstrație Interactivă

new Vue({
  el: '#app',
  data: {
    inputs: [],
    changes: [],
    types: ['text', 'email', 'color', 'file', 'date', 'range'],
  },
  methods: {
    logEvent(e, index) {
      this.$set(this[e.type + 's'], index, e.target.value);
    },
  },
});
<link href="https://unpkg.com/bootstrap@4/dist/css/bootstrap.min.css" rel="stylesheet"><script src="https://unpkg.com/vue@2/dist/vue.min.js"></script>

<div id="app">
  <div class="container mw-100 py-3">
    <div v-for="(type, i) in types" class="row mb-2">
      <div class="col-2">
        <span>{{ type.charAt(0).toUpperCase() + type.slice(1) }}:</span>
      </div>
      <div class="col-5">
        <input :type="type" @input="logEvent($event, i)" @change="logEvent($event, i)" />
      </div>
      <div class="col-5">
        <div class="row">
          <div class="col-6 text-break">
            <span>Input: <span style="color: red">{{ inputs[i] }}</span></span>
          </div>
          <div class="col-6 text-break">
            <span>Change: <span style="color: blue">{{ changes[i] }}</span></span>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>