0


vue3的组件事件和defineEmits

文章目录

1. 事件基础

  • 子组件有时候需要与父组件进行交互,子组件需要通知父组件做一些事(比如:prop是单向数据量,子组件不应该直接修改prop绑定的值,而是应该抛出一个事件来通知父组件做出改变
  • 为了解决这个问题,组件实例提供了一个自定义事件系统,父组件可以通过v-on@ 来选择性地监听子组件上抛的事件,就像监听原生 DOM 事件那样,当监听到子组件上抛出的事件时,就会执行对应事件绑定的监听函数 - 子组件可以通过调用内置的 $emit 方法,通过传入事件名称来抛出一个事件- 子组件使用内置的 $emit 方法中,可以使用 $event作为事件参数- 我们可以通过 emits 选项来声明需要抛出的事件(emits声明选项不是必须的) - 这声明了一个组件可能触发的所有事件,还可以对事件的参数进行验证- 还可以让 Vue 避免将它们作为原生事件监听器隐式地应用于子组件的根元素。 - 如果子组件中声明了emits:[‘click’]选项,然后在某个按钮下使用了$emit(‘click’)去触发click事件,则父组件中使用该子组件时,使用@click=‘handleClick’去监听click事件时,不会认为这是原生dom的点击事件,只有当子组件使用$emit(‘click’)触发click事件时,才会触发hanleClick函数。如果不加emits:[‘click’]选项,则只要点击就会触发handleClick事件。

示例

在这里插入图片描述

Blog.vue
<template><div:style="{ fontSize: postFontSize + 'em' }"><BlogPostv-for="post in posts":key="post.id":title="post.title"@enlarge-text="postFontSize += 0.1"/></div></template><script>import BlogPost from'./BlogPost.vue'exportdefault{name:'Blog',components:{
        BlogPost
    },data(){return{posts:[{id:1,title:'My journey with Vue'},{id:2,title:'Blogging with Vue'},{id:3,title:'Why Vue is so fun'}],postFontSize:1}}}</script><stylelang="scss"></style>
BlogPost.vue
<template><divclass="blog-post"><h4>{{ title }}</h4><button@click="$emit('enlarge-text')">Enlarge text</button></div></template><script>exportdefault{name:'BlogPost',props:['title'],// 这个emits声明选项不是必须的emits:['enlarge-text']}</script><stylelang="scss"></style>

2. 触发与监听事件

2.1 触发事件

  • 在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件
  • $emit() 方法在组件实例上也同样以 this.$emit() 的形式可用:<templte><button@click="$emit('someEvent')">click me</button></template><script>exportdefault{methods:{submit(){this.$emit('someEvent')}}}</script>

2.2 监听事件

  • 父组件可以通过 v-on (缩写为 @) 来监听事件
  • 组件的事件监听器也支持 .once 修饰符 - 触发事件时建议使用camelCase 形式(驼峰命名,首字母小写),父组件监听是可以使用kebab-case 形式(短横线分隔,推荐)
  • 组件触发的事件没有冒泡机制,你只能监听直接子组件触发的事件。- 平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线- 或者使用一个全局状态管理方案<MyComponent@some-event="callback"/><[email protected]="callback"/>

3. 事件参数

  • 有时候会需要在触发事件时附带一个特定的值(事件参数)
  • 可以写一个内联的箭头函数作为监听器,此函数会接收到事件附带的参数
  • 也可以用一个组件方法来作为事件处理函数,该方法也会接收到事件所传递的参数
  • 所有传入 $emit() 的额外参数都会被直接传向监听器。 - 举例来说,$emit(‘foo’, 1, 2, 3) 触发后,监听器函数将会收到这三个参数值。

3.1 示例1

在这里插入图片描述

Blog.vue
<template>
    {{ count }}
    <BlogPost@increase-by="(n) => count += n"/><BlogPost@increase-by="increaseCount"/></template><script>import BlogPost from'./BlogPost.vue'exportdefault{name:'Blog',components:{
        BlogPost
    },data(){return{count:0}},methods:{increaseCount(n,m,e){
            console.log(n,m,e);// 1, 2, PointerEvent {isTrusted: true, _vts: 1682821628803, pointerId: 1, width: 1, height: 1, …}this.count += n
        }}}</script><stylelang="scss"></style>
BlogPost.vue
<template><divclass="blog-post"><button@click="$emit('increaseBy', 1, 2, $event)">
            Increase by 1
        </button></div></template><script>exportdefault{name:'BlogPost',}</script><stylelang="scss"></style>

3.2 示例2(defineEmits)

  • 子组件可以触发自定义事件,
  • 父组件使用该子组件时,可以监听该组件的事件,并为监听的事件绑定事件处理函数, - 当该子组件触发了该事件时,父组件对应的事件处理函数就会执行。

在这里插入图片描述

MyComponent.vue
<template><!-- 在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件 --><!-- 可以通过 v-on (缩写为 @) 来监听事件, 即:@click --><!-- 这里可以使用驼峰命名形式触发的事件名称, 而在父组件中使用短横线命名形式监听 --><!-- 传入3个参数, 则在父组件中监听函数中, 也应至少有3个参数, 
         否则按参数个数赋值,也可以在这里传个对象过去,就只需要一个参数了,
         并且可以使用$event, 将当前事件传过去 --><!-- 参数也可以使用模板中拿到的参数, 比如v-for循环里拿到的每一项数据 --><buttonv-on:click="$emit('doUpdate',$event,1,2)">触发doUpdate事件</button><br/><buttonv-on:click="$emit('refresh', {name:'zzhua',age:Math.floor(Math.random() * 20)})">触发refresh事件</button>
    子组件中person: {{ person }}<br/><!-- 可以使用事件修饰符, once表示该事件只会触发1次 --><buttonv-on:click.once="handleClick()">触发click事件</button></template><scriptlang="ts"setup>import{ ref,reactive,onUpdated }from'vue'/* 1. defineEmits() 宏不能在子函数中使用。它必须直接放置在 <script setup> 的顶级作用域下 *//* 2. 显式地使用了 setup 函数而不是 <script setup>,则事件需要通过 emits 选项来定义,emit 函数也被暴露在 setup() 的上下文对象上 */const emit =defineEmits(['doUpdate'])/* 可以不需要定义doUpdate, 但建议定义doUpdate, 以此来声明此组件可以被触发的事件 */functionhandleClick(){
        console.log('click');emit('doUpdate',e,3,4)/* 使用emit,手动触发doUpdate事件 */}const props =defineProps(['person'])onUpdated(()=>{
        console.log('---组件渲染更新了---')/* 当通过触发子组件事件, 父组件监听到该组件的该事件, 修改了person的ref值, 从而组件会更新 */})</script><stylelang="scss">button{margin: 5px;}</style>
Test.vue
<template><!-- 可以使用短横线形式监听当前这个组件的事件,并指定事件处理函数 --><my-component:person="person"v-on:do-update="handleUpdate"@refresh="handleRefresh"></my-component><br/>

    父组件中person: {{ person }}

</template><scriptlang="ts"setup>import{ ref,reactive,computed }from'vue'import MyComponent from'./MyComponent.vue';const person =ref({name:'demoName',age:NaN})functionhandleUpdate(event,payload1,payload2){
        console.log(event);// PointerEvent {isTrusted: true, _vts: 1678062697219, pointerId: 1, width: 1, height: 1, …}
        console.log(payload1, payload2);}functionhandleRefresh(p){
        console.log(p);// {name: 'zzhua', age: 18}
        person.value = p
    }</script><stylelang="scss"></style>

4. 声明触发的事件

  • 组件可以显式地通过 emits 选项来声明它要触发的事件
  • 这个 emits 选项还支持对象语法,它允许我们对触发事件的参数进行验证
  • 尽管事件声明是可选的,我们还是推荐完整地声明所有要触发的事件。同时,事件声明能让 Vue 更好地将事件和透传 attribute 作出区分,从而避免一些由第三方代码触发的自定义 DOM 事件所导致的边界情况。 - 如果一个原生事件的名字 (例如 click) 被定义在 emits 选项中,则监听器只会监听组件触发的 click 事件而不会再响应原生的 click 事件。

5. 事件校验

  • 和对 props 添加类型校验的方式类似,所有触发的事件可以使用字符串,也可以使用对象形式
  • 要为事件添加校验,那么事件可以被赋值为一个函数,接受的参数就是抛出事件时传入 this.$emit 的内容,返回一个布尔值来表明事件是否合法

示例1

在这里插入图片描述

Blog.vue
<template>
    {{ count }}
    <BlogPost@submit="handleSubmit"/></template><script>import BlogPost from'./BlogPost.vue'exportdefault{name:'Blog',components:{
        BlogPost
    },data(){return{count:0}},handleSubmit(payload){
        console.log(payload);}}</script><stylelang="scss"></style>
BlogPost.vue
<template><divclass="blog-post"><button@click="$emit('submit', {password:'123456'})">
            submit
        </button></div></template><script>exportdefault{name:'BlogPost',emits:{// 没有校验click:null,// 校验 submit 事件submit:({ email, password })=>{if(email && password){returntrue}else{
                console.warn('Invalid submit event payload!')returnfalse}}},methods:{submitForm(email, password){this.$emit('submit',{ email, password })}}}</script><stylelang="scss"></style>

示例2(defineEmits)

MyComponent.vue
<template><button@click="submitForm(123,456)">触发submitForm事件</button></template><scriptlang="ts"setup>import{ ref, reactive }from'vue'const emit =defineEmits({// 没有校验click:null,// 校验 submit 事件submit:({ email, password })=>{if(email && password){
            console.log(email, password);returntrue}else{
            console.warn('Invalid submit event payload!')returnfalse}}})functionsubmitForm(email, password){emit('submit',{ email, password })}</script><stylelang="scss">button{margin: 5px;}</style>
Test.vue
<template><MyComponent></MyComponent></template><scriptlang="ts"setup>import{ ref,reactive,computed }from'vue'import MyComponent from'./MyComponent.vue';</script><stylelang="scss"></style>

本文转载自: https://blog.csdn.net/qq_16992475/article/details/129354204
版权归原作者 ps酷教程 所有, 如有侵权,请联系我们删除。

“vue3的组件事件和defineEmits”的评论:

还没有评论