The event name

Like components and prop, event names provide automatic case conversion. If an event is triggered in a hump-named child, you can add a kebab-case (dash name) listener to the parent component.

this.$emit('myEvent')
Copy the code
<my-component @my-event="doSomething"></my-component>
Copy the code

As with the props name, we recommend using the Kebab-case event listener when you use DOM templates. If you are using a string template, this restriction does not apply.

Define custom events

Vue 3.x

Emitted events can be defined on the component through the emits option.

app.component('custom-form', {
  emits: ['inFocus'.'submit']})Copy the code

When a native event (such as click) is defined in the emits option, the native event listener is replaced with an event in the component.

If you don’t want the component’s root element to inherit attributes, you can set inheritAttrs: false in the component’s options. For example, a common case where attribute inheritance is disabled is when the attribute needs to be applied to elements other than the root node.

By setting the inheritAttrs option to false, you can access the component’s $attrs property, which includes all properties not included in the component props and emits property (for example, Class, style, V-ON listeners, etc.).

Using the date-Picker component example, if you need to apply all non-prop attributes to the input element instead of the root div element, you can do so using the V-bind abbreviation.

app.component('base-input', {
  inheritAttrs: false.template: ` 
      
`
}) Copy the code

With this new configuration, the Data Status attribute is applied to the input element!

<! -- Date-picker components using non-prop attribute -->
<date-picker data-status="activated"></date-picker>

<! -- Render date-picker component -->
<div class="date-picker">
  <input type="datetime" data-status="activated" />
</div>
Copy the code

Vue 2.x

Bind native events to components

Many times you may want to listen for a native event directly on the root element of a component. In this case, you can use the v-ON. Native modifier:

<base-input v-on:focus.native="onFocus"></base-input>
Copy the code

This is useful sometimes, but it’s not a good idea when you’re trying to listen for a very specific element like . For example, the

component above might have been refactored as follows, so that the root element is actually a

<label>
  {{ label }}
  <input
    v-bind="$attrs"
    v-bind:value="value"
    v-on:input="$emit('input', $event.target.value)"
  >
</label>
Copy the code

At this point, the parent.native listener will silently fail. It will not generate any errors, but the onFocus handler will not be called as you expect. To solve this problem, Vue provides a $Listeners Property, which is an object that contains all listeners working on the component. Such as:

{
  focus: function (event) { / *... * / }
  input: function (value) { / *... * /}},Copy the code

With $Listeners property, you can use V-on =”$Listeners “to point all event listeners to a particular child of the component. For components like that you want to make work with the V-Model, it’s often useful to create an inputListeners’ calculation properties similar to the following:

Vue.component('base-input', {
  inheritAttrs: false.// required
  props: ['label'.'value'].computed: {
    inputListeners: function () {
      var vm = this
      // 'object. assign' merges all objects into a new Object
      return Object.assign({},
        // We add all listeners from the parent
        this.$listeners,
        // Then we add custom listeners,
        // Overwrite the behavior of some listeners
        {
          // Make sure the component works with the 'V-model'
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `  `
})
Copy the code

The

component is now a fully transparent wrapper, which means it can be used exactly like a normal
element: all the same attributes and listeners will work without the.native listener.

Validates thrown events

Similar to prop type validation, you can validate emitted events if you define them using object syntax instead of array syntax.

To add validation, the event is assigned a function that takes the parameters passed to the $emit call and returns a Boolean value indicating whether the event is valid.

app.component('custom-form', {
  emits: {
    // No validation
    click: null.// Verify the Submit event
    submit: ({ email, password }) = > {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload! ')
        return false}}},methods: {
    submitForm() {
      this.$emit('submit', { email, password })
    }
  }
})
Copy the code

V – model parameters

Vue 3.x

By default, V-models on components use modelValue as prop and Update :modelValue as events. We can modify these titles by passing the parameter (title) to the V-Model:

<my-component v-model:title="bookTitle"></my-component>
Copy the code

In this case, the child component will need a title prop and issue the event update:title to synchronize:

app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'].template: `  `
})
Copy the code
<my-component v-model:title="bookTitle"></my-component>
Copy the code

In this case, the child component is synchronized with the parent component’s property values. In addition, vue3 removes.sync

Vue 2.x

By default, a V-Model on a component makes use of a prop named Value and an event named input, but input controls of types like checkboxes, checkboxes, and so on May use value attributes for different purposes. The Model option can be used to avoid such conflicts:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked'.event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `  `
})
Copy the code

Now when using the V-Model on this component:

<base-checkbox v-model="lovingVue"></base-checkbox>
Copy the code

The value of lovingVue here will be passed to the prop named Checked. The lovingVue property will also be updated when

fires a change event with a new value.

Note that you still need to declare checked prop in the props option of the component.

Multiple V-Model bindings

By leveraging the ability to target specific prop and events, as we learned earlier in v-Model parameters, we can now create multiple V-Model bindings on a single component instance.

Each V-Model will be synchronized to a different prop without the need to add additional options in the component:

<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
Copy the code
app.component('user-name', {
  props: {
    firstName: String.lastName: String
  },
  emits: ['update:firstName'.'update:lastName'].template: `   `
})
Copy the code

Handle v-Model modifiers

In 2.x, we hardcoded support for modifiers such as.trim on the component’s V-model. However, it is more useful if the component can support custom modifiers. In 3.x, modifiers added to the component’s V-model are provided to the component via modelModifiers Prop:

When we looked at form input bindings, we saw that the V-Model had built-in modifiers –.trim,.number, and.lazy. However, in some cases, you may also need to add your own custom modifiers.

Let’s create a sample custom capitalize modifier that capitalizes the first letter of the string supplied by the V-Model binding.

Modifiers added to the component’s V-model are provided to the component through the modelModifiers Prop. In the example below, we create a component that contains a modelModifiers Prop that defaults to empty objects.

Note that when the component’s Created lifecycle hook fires, the modelModifiers Prop contains capitalize, And the value is true — because capitalize is set on the V-Model binding written v-Model. Capitalize =”myText”.

<my-component v-model.capitalize="myText"></my-component>
Copy the code
app.component('my-component', {
  props: {
    modelValue: String.modelModifiers: {
      default: () = >({})}},emits: ['update:modelValue'].template: `  `.created() {
    console.log(this.modelModifiers) // { capitalize: true }}})Copy the code

Now that we have a prop set up, we can examine the modelModifiers object key and write a handler to change the emitted values. In the code below, we capitalize the string each time an element triggers an input event.

<div id="app">
  <my-component v-model.capitalize="myText"></my-component>
  {{ myText }}
</div>
Copy the code
const app = Vue.createApp({
  data() {
    return {
      myText: ' '
    }
  }
})

app.component('my-component', {
  props: {
    modelValue: String.modelModifiers: {
      default: () = >({})}},emits: ['update:modelValue'].methods: {
    emitValue(e) {
      let value = e.target.value
      if (this.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)}this.$emit('update:modelValue', value)
    }
  },
  template: ``
})

app.mount('#app')
Copy the code

For V-Model bindings with parameters, the generated prop names will be arG + “Modifiers” :

<my-component v-model:description.capitalize="myText"></my-component>
Copy the code
app.component('my-component', {
  props: ['description'.'descriptionModifiers'].emits: ['update:description'].template: `  `.created() {
    console.log(this.descriptionModifiers) // { capitalize: true }}})Copy the code