自定义弹窗组件
封装一个自定义弹窗组件,并挂载到Vue原型链,实现多种调用,字段借鉴于Element-UI,拓展性强
虽然使用的是Vue3,但代码内容还是以选项式为主,个人主观感觉,代码上好理解一点
可以自行更具一下代码,编写为组合式
组件源码
<template>
<div class="standard-dialog" v-if="is_show_dialog">
<div class="dialog-shade" @click="handleClickClose"></div>
<div class="dialog-box" :style="{ width }">
<div class="dialog-close s_flex ai_ct jc_ct">
<em class="iconfont" v-if="showClose" @click="close"></em>
</div>
<div class="dialog-title s_flex ai_ct jc_ct" v-if="title">
<template v-if="showIcon">
<em v-if="iconType" :class="iconType" class="iconfont">{{ iconType === 'warning' || iconType === 'error' ? '' : '' }}</em>
</template>
<p>{{title}}</p>
</div>
<div class="dialog-center" :style="{ textAlign: center ? 'center' : '' }">
<div class="dialog-content">
<template v-if="dangerouslyUseHTMLString">
<slot v-if="$slots.default" name="dialog-message"></slot>
<div v-else v-html="message"></div>
</template>
<div class="s_flex ai_ct jc_ct" v-else>
<p class="dialog-message-text">{{message}}</p>
</div>
</div>
<div class="dialog-button s_flex jc_ct">
<div class="dialog-button-item s_flex ai_ct jc_ct cancel" v-if="showCancelButton" @click="cancel">{{cancelButtonText}}</div>
<div class="dialog-button-item s_flex ai_ct jc_ct" v-if="showConfirmButton" @click="confirm">{{confirmButtonText}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
width: {
type: String,
default: '400px'
},
show: {
type: Boolean,
default: false
},
title: {
type: String,
default: '提示'
},
message: {
type: String,
default: '弹窗内容'
},
center: {
type: Boolean,
default: true
},
showIcon: {
type: Boolean,
default: false
},
iconType: {
type: String,
default: 'warning'
},
showClose: {
type: Boolean,
default: true
},
showCancelButton: {
type: Boolean,
default: true
},
showConfirmButton: {
type: Boolean,
default: true
},
cancelButtonText: {
type: String,
default: '取消'
},
confirmButtonText: {
type: String,
default: '确定'
},
dangerouslyUseHTMLString: {
type: Boolean,
default: false
},
distinguishCancelAndClose: {
type: Boolean,
default: true
},
onConfirm: {
type: Function,
default: () => {}
},
onCancel: {
type: Function,
default: () => {}
}
},
data () {
return {
is_show_dialog: true
}
},
methods: {
handleClickClose () {
if (this.distinguishCancelAndClose) {
this.close()
}
},
/** 点击关闭弹窗 **/
close() {
this.is_show_dialog = false
this.$emit('close')
},
/** 点击取消按钮 **/
cancel() {
this.is_show_dialog = false
this.$emit('cancel')
},
/** 点击确定按钮 **/
confirm() {
this.is_show_dialog = false
this.$emit('confirm', this.is_show_dialog)
},
}
}
</script>
<style lang="scss" scoped>
.standard-dialog {
width: 100vw; height: 100vh; position: fixed; left: 0; top: 0; z-index: 2000;
.dialog-shade { width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); position: fixed; left: 0; top: 0; }
.dialog-box { background-color: #ffffff; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 9; }
.dialog-box .dialog-title { width: 100%; height: 40px; margin-top: 30px; text-align: center; font-size: 16px; position: relative; }
.dialog-box .dialog-title em { margin-right: 8px; font-size: 20px; }
.dialog-box .dialog-title em.warning { color: #e6a23c; }
.dialog-box .dialog-title em.error { color: #f56c6c; }
.dialog-box .dialog-title em.success { color: #67C269; }
.dialog-box .dialog-close { width: 24px; height: 24px; padding: 16px; font-size: 18px; color: #999999; cursor: pointer; position: absolute; right: 0; top: 0; z-index: 1; }
.dialog-box .dialog-center { padding: 0 30px 30px; }
.dialog-box .dialog-message-text { line-height: 20px; margin: 24px 0; text-align: center; font-size: 14px; color: #666666; }
.dialog-box .dialog-button { width: 100%; }
.dialog-box .dialog-button .dialog-button-item { padding: 6px 16px; margin: 0 8px; text-align: center; border: 1px solid var(--color); background-color: var(--shop-color); border-radius: 2px; font-size: 14px; color: #ffffff; cursor: pointer; }
.dialog-box .dialog-button .dialog-button-item:hover { background-color: var(--color-90); border-color: var(--shop-color-50); color: #ffffff; }
.dialog-box .dialog-button .dialog-button-item.cancel { border: 1px solid #DDDFE6; background-color: #ffffff; color: #3D3D3D; }
.dialog-box .dialog-button .dialog-button-item.cancel:hover { background-color: var(--color-20); border-color: var(--color-20); color: var(--color); }
}
</style>
封装JS
import { createApp, reactive, watch } from 'vue';
import StandardDialog from '../../components/dialog/StandardDialog';
const StandardDialogCompr = (options) => {
const rootProps = reactive(options);
return new Promise((resolve, reject) => {
if (!rootProps.confirmButtonLoading) rootProps.confirmButtonLoading = false;
const dialogInstance = createApp(StandardDialog,{
title: rootProps.title ? rootProps.title : rootProps.iconType && rootProps.iconType === 'success'? '成功' : '提示',
message: rootProps.message || '弹窗内容',
showClose: rootProps.showClose,
showIcon: rootProps.showIcon,
iconType: rootProps.iconType,
showCancelButton: rootProps.showCancelButton,
showConfirmButton: rootProps.showConfirmButton,
cancelButtonText: rootProps.cancelButtonText || '取消',
confirmButtonText: rootProps.confirmButtonText || '确定',
dangerouslyUseHTMLString: rootProps.dangerouslyUseHTMLString || false,
}).mount(document.createElement('div'));
watch(() => rootProps.confirmButtonLoading, (newVal, oldVal) => {
dialogInstance.show_btn_dialog = newVal
});
dialogInstance.confirm = () => {
if (dialogInstance.show_btn_dialog) return false;
if (typeof rootProps.beforeClose === 'function') {
rootProps.beforeClose('confirm', rootProps, () => {
dialogInstance.is_show_dialog = false;
});
} else {
dialogInstance.is_show_dialog = false;
resolve('confirm');
}
};
dialogInstance.cancel = () => {
dialogInstance.is_show_dialog = false;
resolve('cancel');
};
dialogInstance.close = () => {
dialogInstance.is_show_dialog = false;
resolve('close');
};
document.body.appendChild(dialogInstance.$el);
});
}
export default StandardDialogCompr;
在main.js中引用
// 导入自定义弹窗组件
import StandardDialog from './components/dialog/StandardDialog'
import standarddialog from './utils/packageInstall/standard-dialog'
app.component('StandardDialog',StandardDialog)
app.config.globalProperties.$standarddialog = standardDialog
页面应用
<template>
<!--组件方式引用弹窗-->
<standard-dialog :title="'结果通知'" :show="is_show_dialog" dangerouslyUseHTMLString @confirm="handleClickConfirm" @close="is_show_dialog = false">
<template slot="dialog-message">
<ul class="">
<li>
<label>通知时间:</label>
<span>2022-01-11 11:44:22</span>
</li>
</ul>
</template>
</standard-dialog>
</template>
<script>
export default {
data () {
return {
is_show_dialog: false
}
},
methods: {
handleClickShowDialog () {
// JS方式使用弹窗
this.$customdialog({
title: '提示',
message: data.message,
confirmButtonText: '去修改',
cancelButtonText: '确定',
showClose: false,
showIcon: true,
iconType: 'warning',
// 如果需要异步处理弹窗关闭
beforeClose: (action, options, done) => {
if (action !== 'confirm') {
done();
return false;
}
options.confirmButtonLoading = true
setTimeout(() => {
done();
options.confirmButtonLoading = false
}, 3000);
}
}).then(() => {
console.log('success')
}).catch(() => {
console.log('catch')
})
}
}
}
</script>