vue3 命名式(函数式)弹窗

一、介绍

什么是命令式(也可以称为函数式)弹窗呢?通常我们在vue的开发中想要使用弹窗,会先在中定义好元素,然后利用变量来控制dialog的显示隐藏,这种属于声明式弹窗。但是在一些场景中,比如我们封装的一些工具函数、hooks、插件等中没办法像在单文件组件中一样将dialog写到template中,或者一些公共的弹窗使用声明式弹窗会比较臃肿,这个时候命名式的调起弹窗就派上用场了。

二、常规声明式弹窗使用方法

下面是最常见的弹窗使用方法,我们借用element-plus的弹窗组件来说明。其实这种常规的方式本身也是有一些缺点的。比如每个Dialog都需要为其创建单独的变量去控制它的显示隐藏,如果只是额外维护一个变量这也不是不能接受,可是当同样的Dialog组件,即需要在父组件控制它的展示与隐藏,又需要在子组件中控制,这样整个项目代码里面就会出现很多这种变量,显得很冗余。

typescript 复制代码
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'

const dialogVisible = ref(false)

</script>
<template>
  <el-button plain @click="dialogVisible = true">
    Click to open the Dialog
  </el-button>

  <el-dialog
    v-model="dialogVisible"
    :before-close="handleClose"
  >
    <span>This is a dialog content</span>
  </el-dialog>
</template>

el-dialog本身是不支持命令式调用的。

三、命令式弹窗

命令式弹窗应该是什么样的形式呢?我们拿element-plus来说明。

typescript 复制代码
<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Action } from 'element-plus'

const open = () => {
  ElMessageBox.alert('This is a message', 'Title', {
    confirmButtonText: 'OK',
    callback: (action: Action) => {
      ElMessage({
        type: 'info',
        message: `action: ${action}`,
      })
    },
  })
}
</script>

<template>
  <el-button plain @click="open">Click to open the Message Box</el-button>
</template>

ElMessageBox.alert()这种形式就是一个命令式弹窗的调用方式,但是ElMessageBox只能支持简单的内容弹窗。当我们的弹窗内容比较复杂时如何使用命令式弹窗呢?

这个时候就需要我们自己封装一些方法来比较优雅/方便的使用弹窗。

命令式弹窗理想的使用效果

typescript 复制代码
<script setup lang="ts">
import { ElButton } from 'element-plus';

import Comp from 'components/Comp.vue';
import MyDialog from 'components/MyDialog.vue';

// 不需要额外的变量控制弹窗
const handleOpenDialog = () => {
  // 处理 MyDialog
};
</script>

<template>
  <div>
    <ElButton @click="handleOpenDialog"> 打开弹窗 </ElButton>
    <div>其他内容。。。 </div>
  </div>
  // 不需要将MyDialog声明到template中
</template>

四个重点:

1、父组件使用Dialog不需要额外的变量控制;

2、不需要将Dialog声明到template中;

3、Dialog组件可以以单独的单文件组件形式(.vue)进行封装。这一点其实很重要,因为这是最简单的弹窗组件封装形式;

Dialog的处理可以直接在函数中进行。

四、可能的实现方法

命令式Dialog的实现方法有很多,先来列举一些常用的实现方法。

方法一

typescript 复制代码
// showMyDialog.ts文件
import { createApp } from 'vue'
import MyDialog from 'components/MyDialog.vue';

const showMyDialog = () => {
  const div = document.createElement('div');
  document.body.appendChild(div);
  const app = createApp(MyDialog);
  app.mount(div)
}

export default showMyDialog

MyDialog组件与showMyDialog是两个文件,增加了维护的成本。

方法二

利用.tsx文件特性,将Dialog和showDialog合并到一个文件。 同时利用@styils/vue来方便写元素的样式。

typescript 复制代码
// MyDialog.tsx文件。
import { createApp } from "vue";
import { ElButton } from "element-plus";
import { styled } from "@styils/vue";

const DivModal = styled('div', {
  position: 'fixed',
  width: '100%',
  height: '100%',
  // 其他css
});

const DivBox = styled('div', {
  display: 'flex',
  minWidth: '25%',
});

const DivText = styled('div', {
  marginBottom: '1em'
});

const DialogBox = {
  props: {
    msg: {
      type: String,
      required: true
    },
  },
  render(ctx: any) {
    const { $props, $emit } = ctx;
    return (
      <DivModal class= "modal" >
      <DivBox class="box" >
        <DivText class="text" > { $props.msg } </DivText>
        <div onClick = { $emit('onClick(e)') } >
          <ElButton type="primary" > 确 定 </ElButton>
        </div>
        </DivBox>
      </DivModal>
    );
    },
};

export function showDialog(props) {
  const div = document.createElement("div");
  document.body.appendChild(div);
  const app = createApp(DialogBox,
    {
      ...props,  
    }
  );
  app.mount(div);
};
相关推荐
Swift社区1 分钟前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus6 分钟前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花31 分钟前
Python环境安装
前端
Light6041 分钟前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy1 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴1 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里1 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路1 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭1 小时前
从Vue到Nuxt.js
前端·javascript·vue.js
前端一小卒1 小时前
从 v5 到 v6:这次 Ant Design 升级真的香
前端·javascript