vue3选项式封装自定义组件并挂载原型上,兼容 Vite

248 阅读2分钟

自定义弹窗组件

封装一个自定义弹窗组件,并挂载到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">&#xe68c;</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' ? '&#xe85a;' : '&#xe81a;' }}</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>