Événements personnalisés


Cette page suppose que vous avez lu Bases des composants. Si vous ne savez pas encore grand-chose sur les composants, je vous recommande de le lire en premier.


Répertoire


Nom de l'événement


Contrairement aux composants et aux accessoires, les noms d'événements n'ont pas de conversion automatique de casse. Au lieu de cela, le nom de l'événement déclenché doit correspondre exactement au nom utilisé pour écouter cet événement. Par exemple, si un événement avec un nom camelCase est déclenché :

this.$emit('myEvent')

alors écouter la version kebab-case de ce nom n'aura aucun effet :

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

Contrairement aux composants et aux accessoires, le nom de l'événement ne sera pas utilisé comme JavaScript. nom de variable ou nom de propriété, il n'y a donc aucune raison d'utiliser camelCase ou PascalCase. Et l'écouteur d'événement v-on sera automatiquement converti en minuscules dans le modèle DOM (car HTML n'est pas sensible à la casse), donc v-on:myEvent deviendra v-on:myevent - rendant impossible la surveillance de myEvent. v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

因此,我们推荐你始终使用 kebab-case 的事件名


自定义组件的 v-model


2.2.0+ 新增

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的model 选项可以用来避免这样的冲突:

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)"
    >
  `
})

现在在这个组件上使用 v-model 的时候:

<base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。

注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。


将原生事件绑定到组件


你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on.native

Par conséquent, nous vous recommandons de 🎜toujours utiliser les noms d'événements kebab-case🎜. 🎜🎜🎜🎜

🎜🎜v-model du composant personnalisé🎜🎜🎜🎜🎜🎜2.2.0+ Ajouté 🎜🎜🎜 sur un code de composant>v-model utilisera l'accessoire nommé value et l'événement nommé input par défaut, mais les types tels que les boutons radio et les cases à cocher Les contrôles d'entrée peuvent utiliser la value pour la Différents objectifs🎜. L'option model peut être utilisée pour éviter de tels conflits : 🎜
<base-input v-on:focus.native="onFocus"></base-input>
🎜Maintenant, lors de l'utilisation de v-model sur ce composant : 🎜
<label>
  {{ label }}
  <input
    v-bind="$attrs"
    v-bind:value="value"
    v-on:input="$emit('input', $event.target.value)"
  >
</label>
🎜ici lovingVue La valeur de code> sera transmise à l'accessoire nommé checked. En même temps, lorsque <base-checkbox> déclenche un événement change avec une nouvelle valeur, les propriétés de ce lovingVue seront mises à jour . 🎜🎜🎜Notez que vous devez toujours déclarer le prop checked dans l'option props du composant. 🎜🎜🎜🎜🎜

🎜🎜Lier des événements natifs aux composants 🎜🎜🎜🎜🎜 Il peut arriver que vous souhaitiez écouter un événement natif directement sur l'élément racine d'un composant. A ce moment, vous pouvez utiliser le modificateur .native de v-on : 🎜
{
  focus: function (event) { /* ... */ }
  input: function (value) { /* ... */ },
}

Cela peut être utile parfois, mais ce n'est pas une bonne idée lorsque vous essayez d'écouter un élément très spécifique comme <input>. Par exemple, le composant <base-input> ci-dessus peut être refactorisé comme suit, de sorte que l'élément racine est en fait un élément <label> : <input> 的非常特定的元素时,这并不是个好主意。比如上述 <base-input> 组件可能做了如下重构,所以根元素实际上是一个 <label> 元素:

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>
  `
})

这时,父级的 .native 监听器将静默失败。它不会产生任何报错,但是 onFocus 处理函数不会如你预期地被调用。

为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

this.$emit('update:title', newTitle)

有了这个 $listeners 属性,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。对于类似 <input> 的你希望它也可以配合 v-model 工作的组件来说,为这些监听器创建一个类似下述 inputListeners 的计算属性通常是非常有用的:

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

现在 <base-input> 组件是一个完全透明的包裹器了,也就是说它可以完全像一个普通的 <input> 元素一样使用了:所有跟它相同的特性和监听器的都可以工作。


.sync 修饰符


2.3.0+ 新增

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

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

然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:

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

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

rrreee

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bindrrreee

À ce stade temps, les écouteurs parents de niveau .native échoueront silencieusement. Cela ne générera aucune erreur, mais le gestionnaire onFocus ne sera pas appelé comme prévu. 🎜🎜Pour résoudre ce problème, Vue fournit un attribut $listeners, qui est un objet qui contient tous les auditeurs agissant sur ce composant. Par exemple : 🎜rrreee🎜Avec cet attribut $listeners, vous pouvez utiliser v-on="$listeners" pour pointer tous les écouteurs d'événements vers une certaine partie de ce composant A élément enfant spécifique. Pour les composants comme <input> que vous souhaitez également utiliser v-model, créez un inputListeners< comme celui-ci pour ces écouteurs. Propriétés calculées de /code > sont souvent très utiles : 🎜rrreee🎜Maintenant, le composant <base-input> est un wrapper complètement transparent, ce qui signifie qu'il peut être utilisé exactement comme un < normal élément code><input> : tous les mêmes attributs et écouteurs fonctionneront. 🎜🎜
🎜

.sync Modificateurs


🎜2.3.0+ Nouveau 🎜
🎜Dans certains Dans certains Dans certains cas, nous devrons peut-être effectuer une "liaison bidirectionnelle" sur un accessoire. Malheureusement, une véritable liaison bidirectionnelle crée des problèmes de maintenance car les composants enfants peuvent modifier leurs composants parents sans source évidente de changement dans les composants parents ou enfants. 🎜🎜C'est pourquoi nous recommandons d'utiliser plutôt le mode update:myPropName pour déclencher des événements. Par exemple, dans un composant hypothétique qui contient la prop title, nous pouvons exprimer l'intention de lui attribuer une nouvelle valeur en utilisant : 🎜rrreee🎜 Le composant parent peut alors écouter cet événement et le mettre à jour si nécessaire Un attribut de données locales. Par exemple : 🎜rrreee🎜Pour plus de commodité, nous fournissons une abréviation pour ce mode, qui est .sync Modificateur : 🎜rrreee
🎜Notez la modification avec .sync < code>v-bind ne peut pas être utilisé avec des expressions (par exemple v-bind:title.sync="doc.title + '!' " il n'est pas valide ). Au lieu de cela, vous pouvez uniquement fournir le nom de la propriété que vous souhaitez lier, quelque chose comme v-model. 🎜
🎜Lorsque nous utilisons un objet pour définir plusieurs accessoires en même temps, nous pouvons également utiliser ce modificateur .sync avec v-bind : 🎜rrreee

Cela transmettra chaque attribut (tel que le titre) dans l'objet doc en tant qu'accessoire indépendant, puis ajoutera des écouteurs v-on pour les mises à jour.

ne fonctionnera pas correctement car il y a beaucoup de cas extrêmes à prendre en compte lors de l'analyse d'une expression complexe comme celle-ci. v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”