• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 组件事件

    触发与监听事件

    在组件的模板表达式中,可以直接使用$emit()函数触发自定义事件(例如:在v-on的处理函数中):

    <!-- MyComponent -->
    <button @click="$emit('someEvent')">click me</button>
    

    父组件可以通过v-on(缩写为@)来监听事件:

    <MyComponent @some-event="callback" />
    

    同样,组件的事件监听器也支持.once修饰符:

    <MyComponent @some-event.once="callback" />
    

    组件与 prop 一样,事件的名字也提供了自动转换。请注意,我们触发了一个以camelCase形式命名的事件,但在父组件中可以使用kebab-case形式来监听。与 prop 大小写格式一样,在模板中我们也推荐使用kebab-case形式来编写监听器

    TIP:和原生 DOM 事件不太一样,组件触发的事件不会冒泡。你只能监听直接子组件触发的事件。


    事件参数

    有时候我们会需要在触发事件时附带一个特定的值。举个例子,我们想要<BlogPost>组件来管理文本会缩放得多大。在这个场景下,我们可以给$emit提供一个值作为额外的参数:

    <button @click="$emit('increaseBy', 1)">
      Increase by 1
    </button>
    

    然后我们在父组件中监听事件,我们可以先简单写一个内联的箭头函数作为监听器,此时可以访问到事件附带的参数:

    <MyButton @increase-by="(n) => count += n" />
    

    或者用一个方法函数来作为事件处理函数:

    <MyButton @increase-by="increaseCount" />
    

    然后,可以从方法的第一个参数上取到这个值:

    //js
    function increaseCount(n) {
      count.value += n
    }
    


    传入$emit()所有参数都会被直接传向监听器。

    template
    <MyButton @foo="increase" />
    
    js
    function increase(n1,n2,n3) {
      //......
    }
    
    MyButton.vue
    监听器 foo,将会收到这三个参数值
    <button @click="$emit('foo', 1, 2, 3)">
      Increase by 1
    </button> 
    
    emit()中传值的参数类型,是任意类型,可以是字符串、数字、布尔值、数组、对象等等。


    声明触发的事件

    组合式 API 中,自定义定义要触发的事件,可以显式地通过defineEmits()宏来声明。

    <script setup>
    const emit = defineEmits(['inFocus', 'submit'])
    </script>
    

    返回的emit()函数可以用来在 JavaScript 代码中触发事件。

    组合式 API中,即,你没有使用<script setup>,则事件需要通过emits 选项来定义,emit()函数也被暴露在setup()的上下文对象上:

    export default {
      emits: ['inFocus', 'submit'],
      setup(props, ctx) {
        ctx.emit('submit')
      }
    }
    

    定义触发事件的函数方法,在上两例中展示的字符串类型的数组语法。定义触发事件的函数方法,还支持对象语法,它允许我们对触发事件的参数进行验证:

    <script setup>
    const emit = defineEmits({
      submit(payload) {
        // 通过返回值为 `true` 还是为 `false` 来判断 验证是否通过
      }
    })
    </script>
    

    如果你正在搭配<script setup>使用TypeScript,也可以使用纯类型标注来声明触发的事件:

    <script setup lang="ts">
    const emit = defineEmits<{
      (e: 'change', id: number): void
      (e: 'update', value: string): void
    }>()
    </script>
    

    更多细节:如何为组件所抛出事件标注类型

    尽管是可选的,我们还是推荐你定义所有要触发的事件,以此更好地在代码中描述和呈现组件的作用。这也使得 Vue 能更好地将事件和透传 attribute 作出区分。

    如果一个原生事件的名字(例如click)被定义在 emits 选项中,则监听器只会监听组件触发的click事件,而不会再响应原生的click事件。


    事件校验

    和对prop添加类型校验的方式类似,所有触发的事件也可以使用对象形式来描述。

    要为事件添加校验,那么事件可以被赋值为一个函数,接受的参数就是emit()抛出事件时传入的内容,返回一个布尔值来表明事件是否合法。

    <script setup>
    const emit = defineEmits({
      // 没有校验
      click: null,
    
      // 校验 submit 事件
      submit: ({ email, password }) => {
        if (email && password) {
          return true
        } else {
          console.warn('Invalid submit event payload!')
          return false
        }
      }
    })
    
    function submitForm(email, password) {
      emit('submit', { email, password })
    }
    </script>
    

    上篇:props 数据

    下篇:attribute 透传