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);
};
相关推荐
Nejosi_念旧2 分钟前
使用Webpack构建NPM Library
前端·webpack·npm
冰红茶-Tea21 分钟前
typescript数据类型(二)
前端·typescript
slongzhang_25 分钟前
elementPlus消息组件多按钮案例
前端·javascript·vue.js
会发光的猪。1 小时前
vue中el-select选择框带搜索和输入,根据用户输入的值显示下拉列表
前端·javascript·vue.js·elementui
旺旺大力包1 小时前
【 Git 】git 的安装和使用
前端·笔记·git
PP东1 小时前
ES学习class类用法(十一)
javascript·学习
海威的技术博客1 小时前
JS中的原型与原型链
开发语言·javascript·原型模式
雪落满地香1 小时前
前端:改变鼠标点击物体的颜色
前端
余生H2 小时前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
outstanding木槿2 小时前
JS中for循环里的ajax请求不数据
前端·javascript·react.js·ajax