Why does @change or @input work with custom v-model component?

Viewed 730

Let's say I've created a custom component Comp.vue that basically is an wrapped input element with a model-value prop and @update="$emit('update:modelValue', $event.target.value).

It might look like this:

<template>
  <div>
  <label :for="name" class="block relative">
    <div>
        {{ label }}
    </div>
        <input
          :name="name"
          :type="type"
          :value="modelValue"
          @input="$emit('update:modelValue', $event.target.value)"
        />
  </label>
    </div>
</template>

<script>

export default {
  props: {
    label: {
      required: true,
      type: String,
    },
    modelValue: {
      required: false,
      default: "",
      type: [String, Number],
    },
    type: {
      default: "text",
      type: String,
    },
    name: {
      required: false,
      type: String,
      default: "",
    },
  },
  emits: ["update:modelValue"],
};
</script>

Now I've imported that component in App.vue.

Why does this work:

<Comp @change="doSth1()" />
<Comp @input="doSth2()" />

My custom Comp.vue never emits any of those events.

I've created a custom playground that logs those events: Playground Link

2 Answers

Since input and change are native DOM events, Vue listens to them automatically.

Please check the Vue docs: Directives, v-on and HTMLElement, input events

When used on a normal element, it listens to native DOM events only. When used on a custom element component, it listens to custom events emitted on that child component.

It looks like Vue still listens to native HTML input events by custom components.

For example, there is also an beforeinput event which is also fired automatically and listened by Vue. So you can add a directive for it also.

@beforeinput="beforeinputTriggered()"

Update to answer @Thibault

The changing of modelValue themself does not fire 'input/change' events. If we remove the HTML input element in the Comp.vue, then the 'beforeinput/input/change' events will be not fired.

Here is the proof: same component with a +1 button fires only the @update:modelValue event.

enter image description here

Because you're basicly passing modelValue as a prop. And I believe that when the value of modelValue changes it triggers an input or change event.

Related