vue3父组件调用子组件el-dialog对话框

vue3父组件调用子组件el-dialog对话框

在写项目的时候,经常要使用父子组件通讯,我已经写了很多篇博客来介绍父子组件通讯了,vue中的父子组件通讯方式有差不多10来种,最常用的就那么一两种,这里我介绍其中我认为最基础的两种。因为目标是在父组件中,通过点击按钮事件来打开子组件中的el-dialog对话框,所以比传统的父传子要复杂一点。

先捋一下逻辑:

  1. 父组件中,点击按钮,给子组件传递一个打开对话框的信息

image-20231212180558769

  1. 子组件接收数据,控制对话框显示

image-20231212180714023

一、基础的props/emits父子传值

先看看父组件中的写法

<template>
    <BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
    <div class="table-wrapped">
        <div class="table-top">
            <div class="table-header">
                <div class="search-wrapped">
                    <el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search" />
                </div>
                <div class="button-wrapped">
                    <el-button type="primary" @click="create">添加产品管理员</el-button>
                </div>
            </div>
        </div>
    </div>
    <CreateAdmin :isShow="isShowDialog"></CreateAdmin>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'

const isShowDialog = ref(false)
const item = ref({
    first: '用户管理',
    second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])
const create = () => {
    isShowDialog.value = true
}
</script>

<style lang="scss" scoped>

</style>

父组件中的逻辑是,点击按钮后,将isShowDialog的值改为true,同时把isShowDialog赋值给isShow传递给子组件

再看看子组件中的写法:

<template>
    <el-dialog v-model="dialogVisible" title="创建管理员" width="30%" center>

    </el-dialog>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'

const dialogVisible = ref(false)
const props = defineProps({
    isShow: {
        type: Boolean,
        default: false
    }
})

watch(() => props.isShow, (val) => {
    console.log(val)
    dialogVisible.value = val
}, { immediate: true })

</script>
<style scoped></style>
  

子组件定义props接收父组件传递过来的值,然后赋值给dialogVisible,el-dialog根据这个dialogVisible来控制对话框是否展示

而且还使用watch深度监视了isShow的变化,当值变化时,马上把最新的值传递给dialogVisible

理论上,这样是不是可以很好的控制对话框的打开与关闭呢?实际上,根本就没法控制,也不能这么说,就第一次可以控制,然后关闭对话框后,就没法正常打开对话框了,什么原因呢,因为在关闭对话框的时候,没用通知父组件来修改对应的值,所以只能正常执行一次。来梳理一下上面代码的逻辑:

  1. 父组件传递给子组件isShow的初始值为false
  2. 父组件中点击按钮后,修改了isShow的值为true
  3. 子组件中的watch监听到isShow的变化,将最新的值(true)赋值给dialogVisible,从而控制对话框的打开
  4. 子组件关闭对话框,dialogVisible的值变为false
  5. 当再次点击父组件按钮想要打开对话框的时候,由于isShow的值仍然为true,所以子组件根本就没有监听到父组件传递过来的isShow的变化,所以对话框就再也打不开了

因此,上面的逻辑中缺少一项,就是在关闭对话框的时候,子组件给父组件传递信号,将isShow的值改为false

因此正确的写法应该是这样的:

父组件:

<template>
    <BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
    <div class="table-wrapped">
        <div class="table-top">
            <div class="table-header">
                <div class="search-wrapped">
                    <el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search" />
                </div>
                <div class="button-wrapped">
                    <el-button type="primary" @click="create">添加产品管理员</el-button>
                </div>
            </div>
            
    </div>
    <CreateAdmin :isShow="isShowDialog" @close="closeDialog"></CreateAdmin>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'

const isShowDialog = ref(false)
const item = ref({
    first: '用户管理',
    second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])
const create = () => {
    isShowDialog.value = true
}
const closeDialog = (val) => {
    isShowDialog.value = val
}
</script>

<style lang="scss" scoped>

</style>

子组件:

<template>
    <el-dialog v-model="dialogVisible" title="创建管理员" width="30%" center @close="closeDialog">

    </el-dialog>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import { creatAdminAPI } from "@/apis/userinfo";

const dialogVisible = ref(false)
const props = defineProps({
    isShow: {
        type: Boolean,
        default: false
    }
})

const emits = defineEmits(['close'])
const closeDialog = () => {
    emits('close', false)
}

watch(() => props.isShow, (val) => {
    console.log(val)
    dialogVisible.value = val
}, { immediate: true })

</script>
<style scoped></style>
  

先看子组件,在子组件的el-dialog对话框中,除了v-model="dialogVisible"这个关键属性外,还定义了它的关闭事件,当关闭对话框的时候,子组件向父组件发送一个close指令,并传递一个false值给父组件

再看父组件,父组件接收close事件,并在closeDialog中将isShowDialog的值设置为子组件传递过来的值,也就是false

这样,就可以来回控制了

也就是说,控制对话框的打开关闭,实际上要实现父传子和子传父两个过程,复杂就复杂在这里

这也是我不推荐用这种方式的原因

二、使用第三方工具mitt.js

我现在凡是涉及到父子组件传值,第一个想到的就是mitt,在vue2中,它是内置的api,叫事件总线,不知道为啥vue3移除了。mitt可以实现任意组件中的通讯,父子、兄弟、祖孙等等。

我之前写过一篇博客,专门用来解释vue3中使用第三方插件mitt实现任意组件通讯

这篇博客可能应用场景太复杂了,用在今天这个例子我觉得正合适。

使用步骤如下:

  1. 安装第三方包,并封装后导出,这个步骤我在之前的博客中已经写了详细的步骤
  2. 父组件中点击按钮后,发出打开对话框指令,代码如下,从代码中可以看出,不需要经过繁琐的传值过程,直接发送emit的openDialog指令就行了
<template>
    <BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
    <div class="table-wrapped">
        <div class="table-top">
            <div class="table-header">
                <div class="search-wrapped">
                    <el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search" />
                </div>
                <div class="button-wrapped">
                    <el-button type="primary" @click="create">添加产品管理员</el-button>
                </div>
            </div>
    </div>
    <CreateAdmin></CreateAdmin>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'
import mitt from '@/utils/mitt'
const emitter = mitt

const item = ref({
    first: '用户管理',
    second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])
const create = () => {
    emitter.emit('openDialog')
}

</script>

<style lang="scss" scoped>

</style>
  1. 子组件接收指令,代码如下,同样,子组件也不用再给父组件传递自定义事件,接收到openDialog指令后,修改dialogVisible的值为true就行了
<template>
    <el-dialog v-model="dialogVisible" title="创建管理员" width="30%" center>

    </el-dialog>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import { creatAdminAPI } from "@/apis/userinfo";
import mitt from '@/utils/mitt'
const emitter = mitt

const dialogVisible = ref(false)

emitter.on('openDialog', () => {
    dialogVisible.value = true
})
</script>
<style scoped></style>
  

两者一对比,就发现使用mitt真的会清爽多了,这也是我为啥钟情mitt的原因

如果要存储数据,可以使用mitt结合pinia或者vuex

三、使用ref控制

还有一种更简单的控制方式,不需要mitt,使用ref来实现

父组件:

<template>
    <BreadCrumb ref="breadCrumb" :item="item"></BreadCrumb>
    <div class="table-wrapped">
        <div class="table-top">
            <div class="table-header">
                <div class="search-wrapped">
                    <el-input v-model="input1" class="w-50 m-2" placeholder="输入账号搜索" :prefix-icon="Search" />
                </div>
                <div class="button-wrapped">
                    <el-button type="primary" @click="create">添加产品管理员</el-button>
                </div>
            </div>
    </div>
    <CreateAdmin ref=createRef></CreateAdmin>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import BreadCrumb from '@/components/BreadCrumb.vue';
import CreateAdmin from '../components/CreateAdmin.vue'

const item = ref({
    first: '用户管理',
    second: '产品管理员'
})
const input1 = ref('')
const tableData = ref([])
const createRef = ref()
const create = () => {
    createRef.value.open()
}

</script>

<style lang="scss" scoped>

</style>

子组件:

<template>
    <el-dialog v-model="dialogVisible" title="创建管理员" width="30%" center>

    </el-dialog>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import { creatAdminAPI } from "@/apis/userinfo";

const dialogVisible = ref(false)
const open = () => {
    dialogVisible.value = true
}
defineExpose({
    open
})
</script>
<style scoped></style>

可以看到,在父组件中,使用ref获取了子组件的dom,点击按钮时,调用子组件中的open方法

在子组件中,定义一个open方法,实际上就是将dialogVisible的值改为true,随后将这个open方法暴露出去

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

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

相关文章

【计算机网络】—— 详解码元,传输速率的计算|网络奇缘系列|计算机网络

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 码元 速率和波特 思考1 思考2 思考3 带宽&#xff08;Bandwidth&#xff09; &#x1f4dd;总结 码元…

【Vulnhub 靶场】【IA: Keyring (1.0.1)】【中等】【20210730】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/ia-keyring-101,718/ 靶场下载&#xff1a;https://download.vulnhub.com/ia/keyring-v1.01.ova 靶场难度&#xff1a;中等 发布日期&#xff1a;2021年07月30日 文件大小&#xff1a;1.1 GB 靶场作者&#xf…

操作系统基础知识

本文用于记录学习W3schools的操作系统教程。 操作系统基础知识 操作系统概括操作系统的8个组件1 流程管理2 I/O设备管理3 文件管理4 网络管理5 内存管理6 磁盘管理(辅助存储管理)7 安全管理8 命令解释系统 操作系统类型 操作系统概括 操作系统&#xff1a; 计算机系统可以分为…

Threejs利用着色器编写动态飞线特效

一、导语 动态飞线特效是可视化数据地图中常见的需求之一&#xff0c;鼠标点击的区块作为终点&#xff0c;从其他区块飞线至点击区块&#xff0c;附带颜色变换或者结合粒子动画 二、分析 利用创建3点来构成贝塞尔曲线&#xff0c;形成线段利用着色器材质来按照线段以及时间…

[C++] 多态(上) -- 抽象类、虚函数、虚函数表

文章目录 1、多态的概念2、多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数的重写2.4 虚函数重写的两个例外2.4.1 协变(基类与派生类虚函数返回值类型不同) 2.4.2 析构函数的重写(基类与派生类析在这里插入图片描述2.4.3 选择题测试 2.5 C11 final 和 override2.5.1 f…

web(HTML之表单练习)

使用HTML实现该界面&#xff1a; 要求如下&#xff1a; 用户名为文本框&#xff0c;名称为 UserName&#xff0c;长度为 15&#xff0c;最大字符数为 20。 密码为密码框&#xff0c;名称为 UserPass&#xff0c;长度为 15&#xff0c;最大字符数为 20。 性别为两个单选按钮&a…

Linux 下的PROC虚拟文件夹的介绍

#江南的江 #每日鸡汤&#xff1a;其一半亩方塘一鉴开,天光云影共徘徊。问渠哪得清如许?为有源头活水来 #初心和目标&#xff1a;在网络安全中崭露头角 PROC 一.proc的文件里的文件是对于计算机的基本信息的介绍。 其中数字文件是代表着进程&#xff0c;其余的例如cpuinfo…

人工智能:机器与人类的对决

一、引言 随着科技的飞速发展&#xff0c;人工智能已经逐渐渗透到我们生活的方方面面。从智能手机到自动驾驶汽车&#xff0c;从语音识别到机器翻译&#xff0c;人工智能已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着人工智能的不断演进&#xff0c;人们开始担心…

1848_emacs_org-mode代码块环境

Grey 全部学习内容汇总&#xff1a; https://github.com/greyzhang/g_org 1848_emacs_org-mode代码块环境 这一部分主要是涉及到一些代码的执行、引用以及输出处理等功能。从之前我看的资料来说&#xff0c;更加偏重于可重现研究但不一定是文学式编程的必要部分。 内容来源…

根据星历文件实现卫星的动态运行模拟matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 .................................................................................... % …

5个免费、跨平台的SQLite数据库可视化工具

前言 SQLite是一个轻量级的嵌入式关系型数据库&#xff0c;目前最新的版本是 SQLite3。今天推荐5个实用的SQLite数据库可视化工具(GUI)&#xff0c;帮助大家更好的管理SQLite数据库。 什么是SQLite&#xff1f; SQLite是一个轻量级的嵌入式关系型数据库&#xff0c;它以一个…

DevEco Studio 项目鸿蒙(HarmonyOS)多语言

DevEco Studio 项目鸿蒙&#xff08;HarmonyOS&#xff09;多语言 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、多语言 新版本IDE可以创建多语言的文件夹&#xff0c;在entry->src->main->resources下&#xff0c;修…

设计模式——访问者模式

引言 访问者模式是一种行为设计模式&#xff0c; 它能将算法与其所作用的对象隔离开来。 问题 假如你的团队开发了一款能够使用巨型图像中地理信息的应用程序。 图像中的每个节点既能代表复杂实体 &#xff08;例如一座城市&#xff09;&#xff0c; 也能代表更精细的对象 &…

智能电气柜环境监测系统

智能电气柜环境监控系统是一种基于传感器技术和物联网技术的智能化监控系统&#xff0c;用于对电气柜内的环境参数进行实时监测和管理。依托智慧电力运维工具-电易云&#xff0c;通过安装在电气柜内的多个传感器&#xff0c;实时采集电气柜内的温度、湿度、氧气浓度、烟雾等关键…

【Logback技术专题】「入门到精通系列教程」深入探索Logback日志框架的原理分析和开发实战技术指南(上篇)

深入探索Logback日志框架的原理分析和开发实战指南系列 Logback日志框架Logback基本模块logback-corelogback-classiclogback-accessLogback的核心类LoggerAppenderLayoutLayout和Appender filterlogback模块和核心所属关系 Logbackj日志级别日志输出级别日志级别介绍 Logback的…

【LangChain学习之旅】—(2) LangChain系统快速入门

【LangChain学习之旅】—&#xff08;2&#xff09; LangChain系统快速入门 LangChain 的基本安装OpenAI APIChat Model 和 Text ModelChat Model&#xff0c;聊天模型Text Model&#xff0c;文本模型 调用 Text 模型第 1 步第 2 步第 3 步第 4 步第 5 步第 6 步 调用 Chat 模型…

Oracle RAC环境下redo log 文件的扩容

环境&#xff1a; 有一个2节点RAC每一个节点2个logfile group每一个group含2个member每一个member的大小为200M 目标&#xff1a;将每一个member的大小有200M扩充到1G。 先来看下redo log的配置&#xff1a; SQL> select * from v$log;GROUP# THREAD# SEQUENCE# …

Java并发(十九)----Monitor原理及Synchronized原理

1、Java 对象头 以 32 位虚拟机为例 普通对象 |--------------------------------------------------------------| | Object Header (64 bits) | |------------------------------------|-------------------------| | Mark W…

Freemarker基本语法与案例讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《SpringBoot》。&#x1f3af;&#x1f3af; &…

二十八、目录操作

二十八、目录操作 QDir 简单的QDir小例子 #include <QCoreApplication> #include <QDir> #include <QStringList> #include <QDebug>// 定义一个函数&#xff0c;输入一个目录路径&#xff0c;返回该目录及其子目录中所有文件的大小 qint64 getDirFi…