Close
升级到 Vue 3 | Vue 2 EOL

自定义事件

本页假设您已经阅读了 组件基础。如果您不熟悉组件,请先阅读该页面。

事件名称

与组件和 Props 不同,事件名称不会进行任何自动大小写转换。相反,发射的事件名称必须与用于监听该事件的名称完全匹配。例如,如果发射一个驼峰式大小写事件名称

this.$emit('myEvent')

监听连字符式大小写版本将无效

<!-- Won't work -->
<my-component v-on:my-event="doSomething"></my-component>

与组件和 Props 不同,事件名称永远不会用作 JavaScript 中的变量或属性名称,因此没有理由使用驼峰式大小写或帕斯卡大小写。此外,DOM 模板中的 v-on 事件监听器将自动转换为小写(由于 HTML 的大小写不敏感),因此 v-on:myEvent 将变为 v-on:myevent - 使 myEvent 无法监听。

出于这些原因,我们建议您 **始终使用连字符式大小写作为事件名称**。

自定义组件 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 修饰符

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

这在某些情况下可能有用,但当您尝试监听非常具体的元素(如 <input>)时,这不是一个好主意。例如,上面的 <base-input> 组件可能会重构,以便根元素实际上是一个 <label> 元素

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

在这种情况下,父级中的 .native 监听器将静默地中断。不会出现错误,但当我们期望它被调用时,onFocus 处理程序不会被调用。

为了解决这个问题,Vue 提供了一个 $listeners 属性,该属性包含一个用于组件上的监听器的对象。例如

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

使用 $listeners 属性,您可以将组件上的所有事件监听器转发到特定子元素,使用 v-on="$listeners"。对于像 <input> 这样的元素,您也希望使用 v-model,创建一个新的计算属性用于监听器通常很有用,例如下面的 inputListeners

Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` merges objects together to form a new object
return Object.assign({},
// We add all the listeners from the parent
this.$listeners,
// Then we can add custom listeners or override the
// behavior of some listeners.
{
// This ensures that the component works with 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>
`
})

现在,<base-input> 组件是一个 **完全透明的包装器**,这意味着它可以像普通的 <input> 元素一样使用:所有相同的属性和监听器都将起作用,而无需 .native 修饰符。

.sync 修饰符

2.3.0+ 中的新功能

在某些情况下,我们可能需要对 Prop 进行“双向绑定”。不幸的是,真正的双向绑定会导致维护问题,因为子组件可以在父级不知情的情况下修改父级,而父级和子级都没有明显的修改来源。

这就是为什么我们建议使用 update:myPropName 模式发射事件。例如,在一个假设的具有 title Prop 的组件中,我们可以使用以下方法来传达分配新值的意图

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

然后,父级可以监听该事件并更新本地数据属性(如果需要)。例如

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

为了方便起见,我们提供了一个使用 .sync 修饰符的简写

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

请注意,使用 .sync 修饰符的 v-bind **不** 支持表达式(例如 v-bind:title.sync=”doc.title + ‘!’” 无效)。相反,您必须只提供要绑定的属性的名称,类似于 v-model

当使用对象一次设置多个 Prop 时,.sync 修饰符也可以与 v-bind 一起使用

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

这将 doc 对象中的每个属性(例如 title)作为单独的 Prop 传递,然后为每个属性添加 v-on 更新监听器。

使用 v-bind.sync 与字面量对象(例如在 v-bind.sync=”{ title: doc.title }” 中)将不起作用,因为解析像这样的复杂表达式需要考虑太多边缘情况。