写点什么

你以为 Vue3 封装一个弹框组件很简单?

  • 2021 年 12 月 09 日
  • 本文字数:2043 字

    阅读完需:约 7 分钟

你以为Vue3封装一个弹框组件很简单?

总结放前面:


Tipes: 封装弹框组件使用了 Teleport,避免了组件嵌套可能导致的定位层级的隐患,还使用了 defineProps,defineEmits,插槽增加了组件的拓展性。


🌲🌲 前言:之前一直没有自己去封装过一个弹框组件,但是觉得一个小小的弹窗组件那不是洒洒水小意思了。然后今天新项目中需要一个弹窗组件,所以我就做了一个。不做不要紧一做发现还是有很多不同的小问题,然后就把遇到的问题和大佬们分享一下。


开始先回顾一下需求,一个全局使用的公共弹框组件。那么就有几个要点:公共、全局、弹框,下面我们就针对这几个要点去一点点实现弹框组件。
复制代码


🍬🍬公共🍬🍬公共这个简单,相信在座的各位大佬肯定都是手拿把掐,轻轻松松就实现了。先实现一个主体内容,我的方法就是使用插槽和参数传递。例子只是简单的传递两个参数,一个标题内容一个控制打开和关闭的布尔值。主要涉及到 Vue3 两个 Api 的使用 defineProps,defineEmits 还有插槽的使用。


<template><Mask @click="close" /> // 蒙板层<div class="modal_all" v-if="visible"><slot name="header"> // 方便页面增加定制头部<div class="modal_header"><p class="modal_header_title">{{ title }}</p><p class="modal_header_img" @click="close"></p></div></slot><div class="modal_content"><slot></slot> // 开放弹框内容使用</div></div></template><script lang="ts" setup>defineProps({visible: {type: Boolean,default: false,},title: {type: String,},});const emit = defineEmits(['update:visible']);const close = () => {emit('update:visible', false);};</script>// 样式省略复制代码🍬🍬全局🍬🍬基本布局差不多了,下面就是全局注册,目的是为了不用每次使用每次都要引入。vue2 在注册全局组件的时候,直接 Vue.component('名称', 组件)就可以了,那么在 vue3 中怎么批量注册全局组件呐?提供一个 install 方法,使用 app.use()自动调用。


import Modal from './Modal/Modal.vue';import Mask from './Modal/Mask.vue';


// 在 script setup 不能写 name,所以在这里加一个 const coms = [{name: 'Modal', // 使用组件的名称 compent: Modal,},{name: 'Mask',compent: Mask,},];


export default {install: (app) => {coms.forEach((item) => {app.component(item.name, item.compent);});},};


// main.tsimport Common from './common/index';const app = createApp(App);app.use(Common);复制代码🍬🍬弹框🍬🍬其实弹框组件写到这里已经差不多了,那为什么要把弹框这个单独列出来说一下呐?相信各位大佬在日常工作中也遇到过定位和层级的问题,如果我们把需要定位的组件嵌套在 Vue 的某个组件内部,因为 css 各种层的原因我们在处理嵌套的定位、层级 和样式就会变得很困难,一不小心就会出现一些奇奇怪怪的问题,那么怎么去避免这个问题?下面就要使用到 Vue3 中另外一个传送门 Api:Teleport。Tipes: Teleport 就是将我们的组件挂载到属性 to 对应的 DOM 元素中,类似一个任意门。先上代码:


<teleport to="#mask_modal" v-if="visible"><div class="modal_cent"><Mask @click="close" /><div class="modal_all"><slot name="header"><div class="header"><p class="header_title">{{ title }}</p><p class="header_img" @click="close"></p></div></slot><div><slot></slot></div></div></div></teleport>复制代码我们来看一下这样写之后的层级:


通过 to 属性,指定弹框组件渲染的位置与 layput 组件同级,但是 teleport 的状态 visible 又是完全由我们调用的组件控制,就避免了我们在嵌套组件的时候定位层级样式的问题。


🌼🌼 至此,一个简单的公共弹框组件已经写的差不多了。然后在写这个组件的过程中我还是遇到了几个不算问题的问题😅。
复制代码


❗️❗️❗️1.script setup 中没法写 name 属性:如果没有用 ts 的话,可以再写一个 script 标签,在里面导出然后写 name。如果使用 ts,那么这个方法就行不通就会报错。那么就利用我上面写的方法,自己重新定义一下写一个对象那样。❗️❗️❗️2.直接给全局组件加一个 class 加样式不生效:其实我们正常写公共组件,在使用的地方想直接在外层控制内部容器的样式,我们可以直接在外面加一个类名去增加样式,但是我在写这个弹框组件的时候却一直不生效,找了半天后来才发现原来是因为我使用了 teleport,所以在解析的时候 class 不能被继承。同样要是组件内没有一个根组件同样会出现这样的问题。这样其实也没关系,我们在插槽内写内容自动撑开就可以了,相信各位大佬肯定不会像我一样搞这么傻的操作,哈哈。


🎉🎉🎉结语:其实一个弹框组件的封装还是很简单的,不过也算是积累了一点经验,把自己的项目实施落地。后面去封装更加复杂的组件也会比较有思路。不积硅步无以至千里,加油各位大佬!


最后如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163 相互学习,我们会有专业的技术答疑解惑


如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点 star: https://gitee.com/ZhongBangKeJi/CRMEB不胜感激 !

用户头像

还未添加个人签名 2021.11.02 加入

CRMEB就是客户关系管理+营销电商系统实现公众号端、微信小程序端、H5端、APP、PC端用户账号同步,能够快速积累客户、会员数据分析、智能转化客户、有效提高销售、会员维护、网络营销的一款企业应用

评论

发布
暂无评论
你以为Vue3封装一个弹框组件很简单?