自定义事件

    不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。举个例子,如果触发一个 camelCase 名字的事件:

    则监听这个名字的 kebab-case 版本是不会有任何效果的:

    1. <!-- 没有效果 -->
    2. <my-component @my-event="doSomething"></my-component>

    不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或 property 名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 @myEvent 将会变成 @myevent——导致 myEvent 不可能被监听到。

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

    可以通过 emits 选项在组件上定义已发出的事件。

    1. app.component('custom-form', {
    2. emits: ['in-focus', 'submit']
    3. })

    TIP

    建议定义所有发出的事件,以便更好地记录组件应该如何工作。

    与 prop 类型验证类似,如果使用对象语法而不是数组语法定义发出的事件,则可以验证它。

    要添加验证,将为事件分配一个函数,该函数接收传递给 $emit 调用的参数,并返回一个布尔值以指示事件是否有效。

    1. app.component('custom-form', {
    2. emits: {
    3. // 没有验证
    4. click: null,
    5. // 验证submit 事件
    6. submit: ({ email, password }) => {
    7. if (email && password) {
    8. return true
    9. } else {
    10. console.warn('Invalid submit event payload!')
    11. return false
    12. }
    13. }
    14. },
    15. methods: {
    16. submitForm() {
    17. this.$emit('submit', { email, password })
    18. }
    19. }
    20. })

    默认情况下,组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。我们可以通过向 v-model 传递参数来修改这些名称:

    1. <my-component v-model:foo="bar"></my-component>

    在本例中,子组件将需要一个 foo prop 并发出 update:foo 要同步的事件:

    1. <my-component v-model:foo="bar"></my-component>

    每个 v-model 将同步到不同的 prop,而不需要在组件中添加额外的选项:

    1. v-model:first-name="firstName"
    2. v-model:last-name="lastName"
    3. ></user-name>
    1. const app = Vue.createApp({})
    2. app.component('user-name', {
    3. props: {
    4. firstName: String,
    5. lastName: String
    6. },
    7. template: `
    8. <input
    9. type="text"
    10. :value="firstName"
    11. @input="$emit('update:firstName', $event.target.value)">
    12. <input
    13. type="text"
    14. :value="lastName"
    15. @input="$emit('update:lastName', $event.target.value)">
    16. `
    17. })

    在 2.x 中,我们对组件 v-model 上的 .trim 等修饰符提供了硬编码支持。但是,如果组件可以支持自定义修饰符,则会更有用。在 3.x 中,添加到组件 v-model 的修饰符将通过 modelModifiers prop 提供给组件:

    当我们学习表单输入绑定时,我们看到 v-model内置修饰符——.trim.number.lazy。但是,在某些情况下,你可能还需要添加自己的自定义修饰符。

    让我们创建一个示例自定义修饰符 capitalize,它将 v-model 绑定提供的字符串的第一个字母大写。

    添加到组件 v-model 的修饰符将通过 modelModifiers prop 提供给组件。在下面的示例中,我们创建了一个组件,其中包含默认为空对象的 modelModifiers prop。

    请注意,当组件的 created 生命周期钩子触发时,modelModifiers prop 包含 capitalize,其值为 true——因为它被设置在 v-model 绑定 v-model.capitalize="bar"

    1. <my-component v-model.capitalize="bar"></my-component>
    1. <div id="app">
    2. {{ myText }}
    3. </div>
    1. const app = Vue.createApp({
    2. data() {
    3. return {
    4. myText: ''
    5. }
    6. }
    7. })
    8. app.component('my-component', {
    9. props: {
    10. modelValue: String,
    11. modelModifiers: {
    12. default: () => ({})
    13. }
    14. },
    15. methods: {
    16. emitValue(e) {
    17. let value = e.target.value
    18. if (this.modelModifiers.capitalize) {
    19. value = value.charAt(0).toUpperCase() + value.slice(1)
    20. }
    21. this.$emit('update:modelValue', value)
    22. }
    23. },
    24. template: `<input
    25. type="text"
    26. :value="modelValue"
    27. @input="emitValue">`
    28. })
    29. app.mount('#app')

    对于带参数的 v-model 绑定,生成的 prop 名称将为 arg + "Modifiers"

    1. <my-component v-model:foo.capitalize="bar"></my-component>
    1. app.component('my-component', {
    2. props: ['foo', 'fooModifiers'],
    3. template: `
    4. <input type="text"
    5. :value="foo"
    6. @input="$emit('update:foo', $event.target.value)">
    7. `,
    8. created() {
    9. console.log(this.fooModifiers) // { capitalize: true }
    10. }