背景
在项目中经常需要用到自定义弹窗,类似于UI组件的Dialog、Alert等,以下为自定义的alert全局弹窗
$alert({
title: '审核未通过',
message: '审核未通审核未通审核未通审核未通审核未通',
isCloseIcon: true,
closeOnClickOverlay: false,
cancelBtnClass: 'm-red', // 取消按钮的class
callback: () => {
console.log('确定按钮')
}
})
步骤
1、在/src/components/新建global文件夹,用于存放自定义全局组件
2、在global文件夹下新建 alert.vue、alert.ts 两个文件
alert.vue
<template>
<div class="custom-alert" :class="customClass" ref="customAlert">
<div class="custom-alert-bg" @click="clickOverlay"></div>
<div class="custom-alert-content">
<div class="custom-alert-title" v-html="title" v-if="title"></div>
<img
class="custom-alert-close"
src="@/assets/img/icon-close.png"
v-if="isCloseIcon"
@click="handleCancel"
/>
<div class="custom-alert-detail">
<div v-html="message" v-if="message" class="custom-alert-message"></div>
</div>
<div class="flex-right custom-alert-btn-group">
<button
:class="['custom-alert-btn-cancel', cancelBtnClass]"
@click="handleCancel"
v-if="!hideCancel"
>
{{ cancelBtnText }}
</button>
<button class="custom-alert-btn-create" @click="handleOk">{{ ensureBtnText }}</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps({
// 弹窗自定义class,引入的页面可以定制修改弹窗样式
customClass: {
type: String,
default: ''
},
// 弹窗标题
title: {
type: String,
default: '信息提示'
},
// 弹窗内容
message: {
type: String,
default: ''
},
// 取消按钮自定义样式
cancelBtnClass: {
type: String,
default: ''
},
// 确定按钮文案
ensureBtnText: {
type: String,
default: '确定'
},
// 取消按钮文案
cancelBtnText: {
type: String,
default: '取消'
},
// 是否显示关闭按钮
isCloseIcon: {
type: Boolean,
default: false
},
// 点击确定回调
callback: {
type: Function
},
// 点击取消按钮回调
callbackCancel: {
type: Function
},
// 影藏取消按钮
hideCancel: {
type: Boolean,
default: false
},
// 点击遮罩层关闭弹窗
closeOnClickOverlay: {
type: Boolean,
default: true
}
})
const customAlert = ref(null)
// 关闭弹窗
function removeModal() {
let parent = (customAlert.value && customAlert.value['parentNode']) || null
if (customAlert.value && document.body.contains(parent) && parent) {
document.body.removeChild(parent)
}
}
// 点击取消按钮
function handleCancel() {
removeModal()
props.callbackCancel && props.callbackCancel()
}
// 点击确定按钮
function handleOk() {
removeModal()
props.callback && props.callback()
}
// 点击遮罩层
function clickOverlay() {
props.closeOnClickOverlay && removeModal()
}
</script>
<style lang="scss">
@mixin box-sizing($value) {
box-sizing: $value;
-webkit-box-sizing: $value;
-o-box-sizing: $value;
-moz-box-sizing: $value;
}
@mixin box($w, $h) {
height: $h;
width: $w;
padding: 0;
box-sizing: border-box;
@include box-sizing(border-box);
}
.custom-alert {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
@include box(100%, 100%);
top: 0;
left: 0;
z-index: 100;
.flex-right {
display: flex;
align-items: center;
justify-content: flex-end;
}
.custom-alert-close {
position: absolute;
right: 16px;
top: 16px;
cursor: pointer;
width: 28px;
}
.custom-alert-title {
font-size: 28px;
font-weight: 500;
color: #5a6371;
text-align: center;
line-height: 40px;
padding-top: 16px;
}
.custom-alert-content {
@include box(auto, auto);
min-width: 400px;
background: #fff;
border: 1px solid #ebebeb;
padding-bottom: 24px;
position: relative;
border-radius: 8px;
}
.custom-alert-bg {
position: fixed;
@include box(100%, 100%);
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
}
.custom-alert-detail {
padding-top: 20px;
}
.custom-alert-message {
font-size: 14px;
font-weight: 400;
color: #5a6371;
text-align: left;
padding: 0 30px;
max-width: 600px;
margin: auto;
}
.custom-alert-btn-group {
margin-top: 30px;
padding-right: 16px;
}
// 按钮样式
.custom-alert-btn-create,
.custom-alert-btn-cancel {
@include box(90px, 32px);
cursor: pointer;
border: none;
outline: none;
display: flex;
align-items: center;
justify-content: center;
color: #eff7ff;
font-size: 14px;
font-weight: 500;
border-radius: 4px;
}
.custom-alert-btn-create {
background: #536fff;
}
.custom-alert-btn-cancel {
background-color: #fff;
border: 1px solid;
color: #2f51ff;
border-color: #536fff;
margin-right: 20px;
margin-bottom: 0;
}
}
</style>
alert.ts
import { createVNode, render } from 'vue'
import alertComponent from './alert.vue'
const myAlert = function (options: any) {
const container = document.createElement('div')
const vm = createVNode(alertComponent, options)
render(vm, container)
document.body.appendChild(container)
}
const alert = {
install(app: any) {
// 配置此应用
app.config.globalProperties.$alert = myAlert
}
}
export default alert
3、在main.ts引入自定义全局组件
import alert from './components/global/alert'
app.use(alert)
4、在业务代码中使用,例如:App.vue
<script setup lang="ts">
import { getCurrentInstance } from 'vue'
const {
proxy: { $alert }
} = getCurrentInstance() as any
$alert({
title: '审核未通过',
message: '审核未通审核未通审核未通审核未通审核未通',
isCloseIcon: true,
closeOnClickOverlay: false,
cancelBtnClass: 'm-red', // 取消按钮的class
callback: () => {
console.log('确定按钮')
}
})
</script>