Vue3+TypeScript二次封装Element Plus Dialog弹窗组件

目录

一、HTML标签部分

二、Script脚本部分

1、引入所需API

2、定义接收配置项

3、定义Emit方法

三、完整子组件代码

四、父组件引用 


        在没开始接触Vue3TypeScript前,本人开发工作中一直运用较多的技术框架就是Vue2和JavaScript了。在一次偶然的机会里接到一个基于Vue3+TypeScript的项目,才开始接触Vue3TypeScript。于是花了差不多两周的时间去学习Vue3及TypeScript的基本操作语法,类型校验等;其中Ts的语法校验及数据类型校验的严格让我一度抓耳挠腮,就这样不断在各大技术论坛中来回游走,研究官方文档介绍。也是在两周时间的苦熬下,基本对Vue3、TypeScript的语法及开发流程有所小掌握。下面就给大家分享一个我在Vue3+TypeScript开发学习过程中使用Element Plus 二次封装的一个Dialog弹窗组件的(小呆萌)!!!!

          话不多说,展示!!

一、HTML标签部分

将Dialog弹窗的常用属性用Props定义公共配置项便于复用更改 

<template>
    <el-dialog v-model="dialog" append-to-body :modal="props.dialogConfig.dialogModal"
        :close-on-click-modal="props.dialogConfig.dialogClickModalClose"
        :close-on-press-escape="props.dialogConfig.dialogESCModalClose" :draggable="props.dialogConfig.dialogDraggable"
        :show-close="props.dialogConfig.dialogShowClose" :title="props.dialogConfig.dialogTitle"
        :width="props.dialogConfig.dialogWidth" :align-center="props.dialogConfig.dialogAlignCenter"
        :center="props.dialogConfig.dialogContentCenter || true" @open="open" @close="close">
        <slot name="content">

        </slot>
        <template #footer v-if="props.dialogConfig.dialogFooterBtn">
            <el-button type="primary" @click="SaveSubmit">保存提交</el-button>
            <el-button type="info" @click="CloseSubmit">取消保存</el-button>
        </template>
    </el-dialog>
</template>

二、Script脚本部分

1、引入所需API

import { defineProps, withDefaults, ref, defineEmits, watch } from 'vue'

2、定义接收配置项

       这里需要注意的是Porps配置项定义的方式Ts和Js是不一样的,Ts需要Vue3中特定的API函数withDefaults方法来转化defineProps,再将定义的interface对象传入其中作为转译参数,抛给父组件以便于接收父组件传来的值。当然这只是我自己琢磨所理解的!其中还有很多方式是靠自己摸索出来的哈

interface Props {
    visible: boolean,
    dialogConfig?: {
        dialogTitle: string; //模态框标题名称
        dialogWidth: string; //模态框弹窗宽度
        dialogShowClose: any; //是否显示关闭按钮
        dialogModal: any; //是否需要模态框(遮罩层)
        dialogAlignCenter: any; //是否水平垂直对齐模态框
        dialogContentCenter: any; //模态框header和footer内容是否居中对齐
        dialogFullscreen: any; //模态框是否为全屏
        dialogClickModalClose: any; //是否可以通过点击遮罩层关闭Dialog
        dialogESCModalClose: any; //是否可以通过按下ESC关闭Dialog
        dialogDraggable: any; //是否开启模态框拖拽功能
        dialogFooterBtn: any; //是否开启底部操作按钮
    }
}
const props = withDefaults(defineProps<Props>(), {
    visible: false,
    dialogConfig: () => {
        return {
            dialogTitle: "默认标题" || "",
            dialogWidth: "40%" || "",
            dialogShowClose: "" || false,
            dialogModal: true || "",
            dialogAlignCenter: true || "",
            dialogContentCenter: "",
            dialogFullscreen: "" || false,
            dialogClickModalClose: "" || false,
            dialogESCModalClose: "" || false,
            dialogDraggable: "" || false,
            dialogFooterBtn: "" || false,
        }
    }
})
//定义默认Dialog弹窗打开状态
const dialog = ref<boolean>(props.visible)
// watch监听
watch(() => props.visible, (newValue, oldValue) => {
    dialog.value = newValue
}, { deep: true, immediate: true })

       这里我使用的是watch监听的方法来监测dialog状态的发生变化 ,从而实现弹窗的开启与关闭状态,当然目前还要最后的步骤才能完全实现弹窗的打开与关闭状态!!!

 3、定义Emit方法

// 定义Emits数据类型
interface Emits {
    (event: 'save', isShow: boolean): void
    (event: 'cancellation', isShow: boolean): void
    (event: 'open', isShow: boolean): void
    (event: 'close', isShow: boolean): void
}

const emits = defineEmits<Emits>() //将定义Emits数据类型赋值

// 保存提交回调函数
const SaveSubmit = () => {
    emits('save', false) //emit方法供父级组件调用
}
// 取消保存回调函数
const CloseSubmit = () => {
    emits('cancellation', false) //emit方法供父级组件调用
}

// 打开事件回调函数
const open = () => {
    emits('open', true) //emit方法供父级组件调用
}

// 关闭事件回调函数(当显示头部关闭按钮时需调用该回调函数方法 -> dialogShowClose = true 反之)
const close = () => {
    emits('close', false) //emit方法供父级组件调用
}

        这里我定义了四个事件,当中open和close方法为Dialog组件标签本身事件,可以使用另一种ref方法去控制弹窗的开启与关闭状态,使用ref方法需配合defineExpose函数API方法将open与close抛出,才可供父组件调用。这里我多封装了两个方法是项目中弹窗多为表单控件,所以定义了表单提交与取消方法的按钮组件,需要时显示,不需要时隐藏即可。这里我是为了自己方便所以才这样写,大家可根据自己的想法自行更改和数据封装。

 三、完整子组件代码

<template>
    <el-dialog v-model="dialog" append-to-body :modal="props.dialogConfig.dialogModal"
        :close-on-click-modal="props.dialogConfig.dialogClickModalClose"
        :close-on-press-escape="props.dialogConfig.dialogESCModalClose" :draggable="props.dialogConfig.dialogDraggable"
        :show-close="props.dialogConfig.dialogShowClose" :title="props.dialogConfig.dialogTitle"
        :width="props.dialogConfig.dialogWidth" :align-center="props.dialogConfig.dialogAlignCenter"
        :center="props.dialogConfig.dialogContentCenter || true" @open="open" @close="close">
        <slot name="content">

        </slot>
        <template #footer v-if="props.dialogConfig.dialogFooterBtn">
            <el-button type="primary" @click="SaveSubmit">保存提交</el-button>
            <el-button type="info" @click="CloseSubmit">取消保存</el-button>
        </template>
    </el-dialog>
</template>

<script lang="ts" setup>
import { defineProps, withDefaults, ref, defineEmits, watch } from 'vue'



interface Props {
    visible: boolean,
    dialogConfig?: {
        dialogTitle: string; //模态框标题名称
        dialogWidth: string; //模态框弹窗宽度
        dialogShowClose: any; //是否显示关闭按钮
        dialogModal: any; //是否需要模态框(遮罩层)
        dialogAlignCenter: any; //是否水平垂直对齐模态框
        dialogContentCenter: any; //模态框header和footer内容是否居中对齐
        dialogFullscreen: any; //模态框是否为全屏
        dialogClickModalClose: any; //是否可以通过点击遮罩层关闭Dialog
        dialogESCModalClose: any; //是否可以通过按下ESC关闭Dialog
        dialogDraggable: any; //是否开启模态框拖拽功能
        dialogFooterBtn: any; //是否开启底部操作按钮
    }
}
const props = withDefaults(defineProps<Props>(), {
    visible: false,
    dialogConfig: () => {
        return {
            dialogTitle: "默认标题" || "",
            dialogWidth: "40%" || "",
            dialogShowClose: "" || false,
            dialogModal: true || "",
            dialogAlignCenter: true || "",
            dialogContentCenter: "",
            dialogFullscreen: "" || false,
            dialogClickModalClose: "" || false,
            dialogESCModalClose: "" || false,
            dialogDraggable: "" || false,
            dialogFooterBtn: "" || false,
        }
    }
})

const dialog = ref<boolean>(props.visible)

// watch监听
watch(() => props.visible, (newValue, oldValue) => {
    dialog.value = newValue
}, { deep: true, immediate: true })

// 定义Emits数据类型
interface Emits {
    (event: 'save', isShow: boolean): void
    (event: 'cancellation', isShow: boolean): void
    (event: 'open', isShow: boolean): void
    (event: 'close', isShow: boolean): void
}
const emits = defineEmits<Emits>() //将定义Emits数据类型赋值

// 保存提交回调函数
const SaveSubmit = () => {
    emits('save', false) //emit方法供父级组件调用
}
// 取消保存回调函数
const CloseSubmit = () => {
    emits('cancellation', false) //emit方法供父级组件调用
}

// 打开事件回调函数
const open = () => {
    emits('open', true) //emit方法供父级组件调用
}

// 关闭事件回调函数(当显示头部关闭按钮时需调用该回调函数方法 -> dialogShowClose = true 反之)
const close = () => {
    emits('close', false) //emit方法供父级组件调用
}

</script>

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

四、父组件引用 

<template>
    <div id="container">
        <dialog :visible="visible" :dialog-config="dialogConfig" @open="open" @close="close" />
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
import dialog from '@/components/Dialog.vue';
export default defineComponent({
    components: {
        dialog
    },
    setup() {
        const visible = ref<Boolean>(false)//弹窗默认关闭状态
        //配置项
        const dialogConfig = reactive<any>({
            dialogTitle: "封装的第一个Dialog弹窗组件"
        })
        // 打开事件回调函数
        const open = (e: Boolean) => {
            visible.value = e
        }
        // 关闭事件回调函数
        const close = (e: Boolean) => {
            visible.value = e
        }
        return {
            visible,
            dialogConfig,
            open,
            close
        }
    },
})
</script>
<style scoped lang="scss"></style>

        这里图个方便!父组件调用弹窗组件的配置项默认我就写一个,如有更改的默认配置项可自行填写dialogConfig中对应的对象即可,父组件中不向配置项中的对象传参更改默认配置则为默认配置,具体请参考Script部分中的2、定义接收配置项。

总结:上述呢只是个人在学习开发中对运用和使用到的一些API方法和自己对组件二次封装开发的一些理解和拙见,并不是很权威。个人认为使用的方法函数和封装逻辑还是一个比较笨的方法,希望大家能在阅读这篇文章中能有自己的理解和新的封装方式,也希望那位大佬在阅读本篇文章后给出更高质量的建议和方法,大家一起学习。写得不好,献丑啦!嘿嘿。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XINGZI前端程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值