vue3的组件事件和defineEmits

文章目录

    • 1. 事件基础
      • 示例
        • Blog.vue
        • BlogPost.vue
    • 2. 触发与监听事件
      • 2.1 触发事件
      • 2.2 监听事件
    • 3. 事件参数
      • 3.1 示例1
        • Blog.vue
        • BlogPost.vue
      • 3.2 示例2(defineEmits)
        • MyComponent.vue
        • Test.vue
    • 4. 声明触发的事件
    • 5. 事件校验
      • 示例1
        • Blog.vue
        • BlogPost.vue
      • 示例2(defineEmits)
        • MyComponent.vue
        • Test.vue

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' }">
        <BlogPost 
            v-for="post in posts" 
            :key="post.id" 
            :title="post.title"
            @enlarge-text="postFontSize += 0.1"/>
    </div>
</template>

<script >
import BlogPost from './BlogPost.vue'
export default {
    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>

<style lang="scss"></style>
BlogPost.vue
<template>

    <div class="blog-post">
        <h4>{{ title }}</h4>
        <button @click="$emit('enlarge-text')">Enlarge text</button>
    </div>

</template>

<script>

export default {
    name: 'BlogPost',
    props: ['title'],
    // 这个emits声明选项不是必须的
    emits: ['enlarge-text']
}

</script>

<style lang="scss"></style>

2. 触发与监听事件

2.1 触发事件

  • 在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件

  • $emit() 方法在组件实例上也同样以 this.$emit() 的形式可用:

    <templte>
    	<button @click="$emit('someEvent')">click me</button>
    </template>
    
    <script>
    	export default {
    	  methods: {
    	    submit() {
    	      this.$emit('someEvent')
    	    }
    	  }
    	}
    </script>
    

2.2 监听事件

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

  • 组件的事件监听器也支持 .once 修饰符
    - 触发事件时建议使用camelCase 形式(驼峰命名,首字母小写),父组件监听是可以使用kebab-case 形式(短横线分隔,推荐)

  • 组件触发的事件没有冒泡机制,你只能监听直接子组件触发的事件

    • 平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线
    • 或者使用一个全局状态管理方案
    <MyComponent @some-event="callback" />
    
    <MyComponent @some-event.once="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'
export default {
    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>

<style lang="scss"></style>
BlogPost.vue
<template>

    <div class="blog-post">
        <button @click="$emit('increaseBy', 1, 2, $event)">
            Increase by 1
        </button>
    </div>

</template>

<script>

export default {
    name: 'BlogPost',
}

</script>

<style lang="scss"></style>

3.2 示例2(defineEmits)

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

在这里插入图片描述

MyComponent.vue
<template>

    <!-- 在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件 -->
    <!-- 可以通过 v-on (缩写为 @) 来监听事件, 即:@click -->
    <!-- 这里可以使用驼峰命名形式触发的事件名称, 而在父组件中使用短横线命名形式监听 -->
    <!-- 传入3个参数, 则在父组件中监听函数中, 也应至少有3个参数, 
         否则按参数个数赋值,也可以在这里传个对象过去,就只需要一个参数了,
         并且可以使用$event, 将当前事件传过去 -->
    <!-- 参数也可以使用模板中拿到的参数, 比如v-for循环里拿到的每一项数据 -->
    <button v-on:click="$emit('doUpdate',$event,1,2)">触发doUpdate事件</button> <br/>

    <button v-on:click="$emit('refresh', {name:'zzhua',age:Math.floor(Math.random() * 20)})">触发refresh事件</button>
    子组件中person: {{ person }}<br/>

    <!-- 可以使用事件修饰符, once表示该事件只会触发1次 -->
    <button v-on:click.once="handleClick()">触发click事件</button>
    
</template>

<script lang="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, 以此来声明此组件可以被触发的事件 */

     function handleClick () {
        console.log('click');
        emit('doUpdate',e,3,4) /* 使用emit,手动触发doUpdate事件 */
    }

    const props = defineProps(['person'])

    onUpdated(()=>{
        console.log('---组件渲染更新了---') /* 当通过触发子组件事件, 父组件监听到该组件的该事件, 修改了person的ref值, 从而组件会更新 */
    })
</script>

<style lang="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>

<script lang="ts" setup>
    import { ref,reactive,computed } from 'vue'
    import MyComponent from './MyComponent.vue';

    const person = ref({ name: 'demoName', age: NaN})


    function handleUpdate(event,payload1,payload2) {
        console.log(event); // PointerEvent {isTrusted: true, _vts: 1678062697219, pointerId: 1, width: 1, height: 1, …}
        console.log(payload1, payload2);
    }

    function handleRefresh( p) {
        console.log(p); // {name: 'zzhua', age: 18}
        person.value = p
    }

</script>

<style lang="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'
export default {
    name: 'Blog',
    components: {
        BlogPost
    },
    data() {
        return {
            count: 0
        }
    },
    handleSubmit(payload) {
        console.log(payload);
    }
}

</script>

<style lang="scss"></style>
BlogPost.vue
<template>
    <div class="blog-post">
        <button @click="$emit('submit', {password:'123456'})">
            submit
        </button>
    </div>
</template>

<script>

export default {
    name: 'BlogPost',
    emits: {
        // 没有校验
        click: null,

        // 校验 submit 事件
        submit: ({ email, password }) => {
            if (email && password) {
                return true
            } else {
                console.warn('Invalid submit event payload!')
                return false
            }
        }
    },
    methods: {
        submitForm(email, password) {
            this.$emit('submit', { email, password })
        }
    }
}

</script>

<style lang="scss"></style>

示例2(defineEmits)

MyComponent.vue
<template>

    <button @click="submitForm(123,456)">触发submitForm事件</button>

</template>

<script lang="ts" setup>

import { ref, reactive } from 'vue'

const emit = defineEmits({
    // 没有校验
    click: null,

    // 校验 submit 事件
    submit: ({ email, password }) => {
        if (email && password) {
            console.log(email, password);
            return true
        } else {
            console.warn('Invalid submit event payload!')
            return false
        }
    }
})

function submitForm(email, password) {
    emit('submit', { email, password })
}

</script>

<style lang="scss">
button {
    margin: 5px;
}
</style>
Test.vue
<template>
    
    <MyComponent></MyComponent>

</template>

<script lang="ts" setup>
    import { ref,reactive,computed } from 'vue'
    import MyComponent from './MyComponent.vue';

</script>

<style lang="scss">
    
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/238677.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ChatGLM3-6B】Docker下快速部署

【ChatGLM2-6B】小白入门及Docker下部署 前提下载安装包网盘地址 开始安装加载镜像启动镜像进入容器启动模型交互页面访问页面地址 前提 安装好了docker安装好了NVIDIA显卡16G 下载安装包 网盘地址 ​ 这里因为网盘上传文件有大小限制&#xff0c;所以使用了分卷压缩的方式…

Adobe的3D建模工具Substance 3D Painter 9.1.1 版本下载与安装

目录 前言一、Substance 3D Painter 9.1.1安装二、使用配置总结 前言 Adobe的Substance 3D Painter是一款强大的3D建模和纹理创建工具&#xff0c;专为数字艺术家设计&#xff0c;尤其是3D画家、游戏设计师和视觉特效艺术家。注&#xff1a;文末附有下载链接&#xff01; 这款…

【gerrit上放弃提交代码】

在gerrit上点击abandon 项目文件夹下打开git USER871058FHA-W4300461 MINGW64 /d/Users/USER871058/IdeaProjects/cda_cem (feature_fix_point_1208) $ git reset --soft HEAD^回到idea即可

电子签测评!审批流程电子签章的代表产品

随着大家对电子文件法律效力的愈发重视&#xff0c;这两年&#xff0c;市面上各种各样的电子签名产品是层出不穷啊。 法大大、E签宝、微签、契约锁各树一帜&#xff0c;腾讯、阿里、字节三巨头也纷纷入局。 几家头部厂家陷入了同质化的竞争&#xff0c;在各个领域使出浑身解数…

Sci Transl Med

今天给同学们分享一篇实验文章“Radiation-induced circulating myeloid-derived suppressor cells induce systemic lymphopenia after chemoradiotherapy in patients with glioblastoma”&#xff0c;这篇文章发表在Sci Transl Med期刊上&#xff0c;影响因子为17.1。 结果解…

windows下安装git中文版客户端

下载git Windows客户端 git客户端下载地址&#xff1a;Git - Downloads 我这里下载的是Git-2.14.0-64-bit.exe版本 下载TortoiseGit TortoiseGit客户端下载地址&#xff1a;Download – TortoiseGit – Windows Shell Interface to Git TortoiseGit客户端要下载两个&#…

用Sketch for Mac轻松创作无限可能的矢量绘图

在如今的数码时代&#xff0c;矢量绘图软件成为了许多设计师和创意爱好者的必备工具。而在众多的矢量绘图软件中&#xff0c;Sketch for Mac无疑是最受欢迎的一款。它以其简洁易用的界面和强大的功能&#xff0c;让用户能够轻松创作出无限可能的矢量图形。 首先&#xff0c;Sk…

vue2-使用axios获取外网ip

1.安装axios>npm i axios 或者yarn add axios 或者pnpm i axios */ 报错&#xff1a;一直info There appears to be trouble with your network connection. Retrying... 原因&#xff1a;网络不好 2.引入axios&#xff1a;import axios from axios 3.使用axios调用接口ht…

基于ssm四六级报名与成绩查询系统论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对四六级报名信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性…

uniapp uview实现u-popup左侧弹起时铺满屏幕

效果如图: 代码如下: <u-popup :show="sign.signParams.show" mode="left" width="100%" height="100%" border-radius="0":mask-close-able="false">XXXXXXX内容xxxxx</u-popup>使用了 mode=“left”…

Nature | 中国陆地的碳汇量有多少?

文献信息 题目&#xff1a; The size of the land carbon sink in China 来源&#xff1a; Nature 时间&#xff1a;2022DOI&#xff1a; https://doi.org/10.1038/s41586-021-04255-y 主要内容 中国人为排放的很大一部分已经被其土地碳汇抵消&#xff0c;这是到2060年实现…

深度学习 Day11——T11优化器对比实验

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文章目录 前言一、我的环境二、代码实现与执行结果1.引入库2.设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;3.导入数据4.查…

绝地求生:追寻枪王之路,为什么PUBG老玩家要进行训练?

作为一款全球热门的射击游戏&#xff0c;《绝地求生&#xff1a;大逃杀》&#xff08;PUBG&#xff09;吸引了大批热衷于挑战极限的玩家。在这个枪战沙盒中&#xff0c;角逐者们需要不断提升自己的战术、枪法和反应速度&#xff0c;才能在百人对战中脱颖而出。那么为什么PUBG老…

如何将CAD图纸导入Revit软件?

在Revit软件中&#xff0c;将CAD图纸导入的过程非常简单。下面将为您详细介绍如何将CAD图纸成功导入Revit软件。 步骤一&#xff1a;准备工作 在导入CAD图纸之前&#xff0c;首先需要确保您已经准备好了需要导入的CAD图纸文件。通常&#xff0c;CAD文件的扩展名为.DWG或.DXF&a…

JVM虚拟机系统性学习-运行时数据区(虚拟机栈、本地方法栈)

虚拟机栈 虚拟机栈为每个线程所私有的&#xff0c;如下图&#xff1a; 栈帧是什么&#xff1f; 栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息 栈内存为线程私有的空间&#xff0c;每个方法在执行时都会创建一个栈帧&#xff0c;执行该方法时&…

11--常用类和基础API--01

1、API概述 1.1 什么是API API(Application Programming Interface)&#xff0c;应用程序编程接口。 Java API是一本程序员的字典 &#xff0c;是JDK中提供给我们使用的类的说明文档。这些类将底层的代码实现封装了起来&#xff0c;我们不需要关心这些类是如何实现的&#x…

文件系统理解

先前的博客我写了关于缓冲区的理解&#xff0c;顺便提及了在内存的文件是怎样管理的&#xff0c;本文就来描述在磁盘上的文件是怎么样。但要先了解了解磁盘。 在笔记本上机械磁盘被固态硬盘代替&#xff0c;因为固态硬盘更快&#xff0c;而且方便携带&#xff0c;机械硬盘若是受…

C++STL的list(超详解)

文章目录 前言构造函数capacitylist的访问insertswapsort 前言 看一下list, 在任意位置可以进行O(1)插入删除的操作。 它怎么实现这个东西&#xff1f;它其实就是一个带头双向循环链表。 #成员函数 构造函数 这里面的构造函数学完string和vector之后已经相当熟悉了。 capaci…

AI大模型报告:2023大模型可信赖研究报告

今天分享的AI系列深度研究报告&#xff1a;《AI大模型报告&#xff1a;2023大模型可信赖研究报告》。 &#xff08;报告出品方&#xff1a;中国信通院&#xff09; 报告共计&#xff1a;48页 大模型发展现状 大模型驱动新一轮科技革命 近十余年间&#xff0c;人工智能技术泛…

源码级详解Spring的三级缓存,循环依赖的处理流程

一.什么是三级缓存 1.一级缓存&#xff1a;存放已经初始化完成的Bean 2.二级缓存&#xff1a;存放半成品Bean&#xff0c;既实例化完成未初始化的Bean。 3.三级缓存&#xff1a;存放bean工厂 二.为什么是三级缓存 一级缓存是必须的&#xff0c;这个我们没有什么疑问。那为…