Skip to content

封装dialog弹窗

Vue3 + ts函数式封装

演示

解释

一、vue文件使用代码

js
// =======  依赖引入  =======
import { getCurrentInstance } from 'vue'

// =======  变量声明  =======
const { proxy }: any = getCurrentInstance()

// =======  函数声明  =======
function showDialog() {
    // 使用全局封装的弹窗
    proxy.$dialog().then(res => {
        // 确定事件
    }).catch(err => {
        // 取消事件
    })
}
二、函数封装: 源代码
ts
import { ref, createApp } from 'vue'
// @ts-ignore
import dialogModule from './dialogModule.vue'

interface OptionsType {
  title?: string // 标题
  mainText?: string // 内容
  width?: string // 宽度
  LeftText?: string // 左侧按钮文字
  LeftType?: string // 左侧按钮样式,支持elementUI组件库按钮组type
  RightText?: string // 右侧按钮文字
  RightType?: string // 右侧按钮样式,支持elementUI组件库按钮组type
}

const visible = ref(false)

export default function (options: OptionsType = {}) {
  return new Promise((resolve, reject) => {
    // 创建dom实例挂载在body上边
    const div = document.createElement('div')
    div.style.width = '0'
    div.style.height = '0'
    document.body.appendChild(div)
    const module = createApp(dialogModule, {
      modelValue: visible,
      resolve: () => {
        resolve('成功返回')
        div.remove()
      },
      reject: () => {
        reject('失败返回')
        div.remove()
      },
      ...options
    })
    module.mount(div)
    visible.value = true
  })
}
三、vue组件封装: 源代码
vue
<template>
    <a-modal v-model:open="visible" wrapClassName="dialog-box" :width="width" :closable="false" :footer="null" @cancel="closeVisible">
        <div @click="closeVisible" class="jw-dialog-close">×</div>
        <template #header>
            <div>{{ title }}</div>
        </template>
        <div class="jw-dialog-cont">
            <div>{{ mainText }}</div>
        </div>
        <div class="jw-dialog-btn">
            <a-button :type="LeftType" @click="closeVisible">{{ LeftText }}</a-button>
            <a-button :type="RightType" @click="submit">{{ RightText }}</a-button>
        </div>
    </a-modal>
</template>

<script setup lang="ts">
// =======  依赖引入  =======
import { computed, watch } from 'vue'
// =======  类型声明  =======

// =======  变量声明  =======
const props = defineProps({
    modelValue: {
        type: Boolean,
        required: true,
        default: false
    },
    resolve: {
        type: Function,
        default: undefined
    },
    reject: {
        type: Function,
        default: undefined
    },
    title: {
        type: String,
        default: '标题'
    },
    mainText: {
        type: String,
        default: '弹窗内容'
    },
    width: {
        type: String,
        default: '400px'
    },
    LeftText: {
        type: String,
        default: '取消'
    },
    LeftType: {
        type: [String, undefined],
        default: undefined
    },
    RightText: {
        type: String,
        default: '确认'
    },
    RightType: {
        type: [String, undefined],
        default: 'primary'
    }
})

const emits = defineEmits<{
    (_e: 'update:modelValue', _v: boolean): void
}>()

const visible = computed<boolean>({
    get() {
        return props.modelValue
    },
    set(val: boolean) {
        emits('update:modelValue', val)
    }
})

watch(props, (val) => {
    console.log(val.modelValue)
})

// =======  主流程  =======

// =======  函数声明  =======

// 关闭弹窗
function closeVisible() {
    emits('update:modelValue', false)
    props.reject!()
}

// 确认按钮
function submit() {
    emits('update:modelValue', false)
    props.resolve!()
}
// =======  属性返回  =======
</script>

<style lang="scss" scoped>
.dialog-box {
    .jw-dialog-cont {
        margin-top: 20px;
    }
    .jw-dialog-close {
        position: absolute;
        top: 0;
        right: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 20px;
        width: 30px;
        height: 30px;
        padding: 10px;
        box-sizing: border-box;
        cursor: pointer;
    }
    // 底部按钮组
    .jw-dialog-btn {
        margin-top: 20px;
        display: flex;
        justify-content: flex-end;
    }
    .ant-btn {
        margin-right: 12px;
        &:last-child {
            margin-right: 0;
        }
    }
}
</style>