Custom events


This page assumes that you have read Component Basics. If you don’t know much about components yet, I recommend you read it first.


##Directory

  • Event Name

  • Customize the v-model of the component

  • Bind native events to the component

  • .sync modifier


## Event names

#Unlike components and props, event names do not have any automatic case conversion. Instead, the name of the triggered event needs to exactly match the name used to listen for this event. For example, if an event with a camelCase name is triggered:
this.$emit('myEvent')

, then listening to the kebab-case version of this name will have no effect:

<!-- 没有效果 -->
<my-component v-on:my-event="doSomething"></my-component>

Unlike components and props, events The name will not be used as a JavaScript variable or property name, so there is no reason to use camelCase or PascalCase. And the

v-on

event listener will be automatically converted to all lowercase in the DOM template (because HTML is case-insensitive), so v-on:myEvent will become Into v-on:myevent——Making myEvent impossible to be monitored. Therefore, we recommend that you

always use

kebab-case event names.


Custom component’s v-model


2.2.0 Added

v-model

on a component. By default, the prop named value and the named input will be used. event, but input controls such as radio buttons, check boxes, etc. may use the value attribute 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: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
Now when using

v-model

on this component:

<base-checkbox v-model="lovingVue"></base-checkbox>
here The value of

lovingVue

will be passed into this prop named checked. At the same time, when <base-checkbox> triggers a change event with a new value, the properties of this lovingVue will be updated.

Note that you still need to declare
checked

this prop in the component's props option.


Bind native events to components

You may have many This time I want to listen to a native event directly on the root element of a component. At this time, you can use the
.native

modifier of v-on:

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

This can be useful sometimes, but it's not a good idea when you're trying to listen to a very specific element like <input>. For example, the above <base-input> component may be refactored as follows, so the root element is actually a <label> element:

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

At this time , the parent's .native listener will fail silently. It will not generate any errors, but the onFocus handler will not be called as you expect.

In order to solve this problem, Vue provides a $listeners property, which is an object that contains all the listeners that act on this component. For example:

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

With this $listeners attribute, you can use v-on="$listeners" to point all event listeners to this component. a specific child element. For components like <input> that you want to also work with v-model, create a listener like the following inputListeners Computed properties of It is used exactly like a normal

<input>

element: all the same attributes and listeners work.

.sync

Modifier2.3.0 New

In some cases, we may need to perform "two-way binding" on a prop. Unfortunately, true two-way binding creates maintenance problems because child components can modify their parent components with no obvious source of change in either parent or child components.
This is why we recommend using the

update:myPropName

mode to trigger events instead. For example, in a hypothetical component that contains the
title

prop, we can express the intention to assign a new value to it using:

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 我们从父级添加所有的监听器
        this.$listeners,
        // 然后我们添加自定义监听器,
        // 或覆写一些监听器的行为
        {
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        v-bind:value="value"
        v-on="inputListeners"
      >
    </label>
  `
})

Then the parent component can listen to that event and Update a local data attribute as needed. For example:

this.$emit('update:title', newTitle)
For convenience, we provide an abbreviation for this mode, which is .sync Modifier:

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

Note the characters with

The .sync modifier v-bind

cannot

be used with expressions (for example v-bind:title.sync="doc.title '!'" it is invalid). Instead, you can only provide the name of the property you want to bind, something like v-model. When we use an object to set multiple props at the same time, we can also use this .sync modifier with v-bind

:
<text-document v-bind:title.sync="doc.title"></text-document>

This will pass each attribute (such as title) in the doc object as an independent prop, and then add v-on listeners for updates.

Use v-bind.sync on a literal object, for example v-bind.sync=”{ title: doc.title }”, will not work properly because there are many edge cases to consider when parsing a complex expression like this.