通过 Vue.extend() 创建可指令调用的 messageBox 弹窗组件源码
程序员文章站
2024-03-04 17:37:53
...
前言
本文是《通过 Vue.extend() 创建可指令调用的组件——MessageBox 弹框》的扩展。关于Vue.extend()
的用法以及 messageBox 弹窗实现的思路,可查看前文。
项目目录
...
├── src
...
│?? ├── plugins
│?? │?? ├── messageBox
│?? │?? │?? ├── messageBox.vue
│?? │?? │?? └── main.js
...
│?? ├── App.vue
│?? └── main.js
...
messageBox 弹窗组件代码—— messageBox.vue
<template>
<transition name="extends">
<div v-show="visible" id="messageBox" class="messageBox" @click="cloceModal">
<div class="contain">
<header>
<i class="close el-icon-close" v-if="showClose" @click="close"></i>
</header>
<main>
<div>
<img v-if="type === 'success'" src="@/plugins/modules/messageBox/assets/success.svg" />
<img v-if="type === 'warning'" src="@/plugins/modules/messageBox/assets/warning.svg" />
<img v-if="type === 'error'" src="@/plugins/modules/messageBox/assets/error.svg" />
<img v-if="type === 'info'" src="@/plugins/modules/messageBox/assets/info.svg" />
<img v-if="type === 'question'" src="@/plugins/modules/messageBox/assets/question.svg" />
</div>
<div class="content">
<h3 v-if="title">{{ title }}</h3>
<p v-if="dangerouslyUseHTMLString" v-html="message"></p>
<p v-else :class="{ large: !title }">{{ message }}</p>
</div>
</main>
<footer>
<el-button v-if="showCancelButton === true" @click="close">{{ cancelButtonText }}</el-button>
<el-button type="primary" @click="confirm">{{ confirmButtonText }}</el-button>
</footer>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'message-box',
data() {
return {
visible: false,
message: '',
title: '',
lockScroll: true,
showCancelButton: true,
dangerouslyUseHTMLString: false,
showClose: false,
closeOnClickModal: false,
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'success', // success、warning、error、info、question
callback: null
};
},
created() {
if (this.lockScroll) {
// 是否在 MessageBox 出现时将 body 滚动锁定
document.body.classList.add('messageBox-srcoll-hideen');
}
this.$nextTick(() => {
this.visible = true;
});
},
methods: {
close() {
this.visible = false;
this.callback && this.callback(false);
this.remove();
},
cloceModal() {
if (this.closeOnClickModal) {
this.close();
}
},
confirm() {
this.visible = false;
this.callback && this.callback(true);
this.remove();
},
// 组件移除事件
remove() {
// 等过渡效果结束后,再移除组件
setTimeout(() => {
this.$destroy(this);
document.body.classList.remove('messageBox-srcoll-hideen'); // 移除蒙版
this.$el.remove(); // 移除组件 DOM
}, 500);
}
}
};
</script>
<style lang="scss">
.messageBox-srcoll-hideen {
overflow: hidden;
}
.messageBox {
position: fixed;
top: 0;
left: 0;
z-index: 3000;
width: 100%;
height: 100%;
background-color: rgba($color: #000000, $alpha: 0.2);
.contain {
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%);
width: 500px;
height: 240px;
border-radius: 4px;
background-color: #ffffff;
box-shadow: 0 0 16px 0 rgba($color: #000000, $alpha: 0.1);
header {
width: 100%;
height: 36px;
text-align: right;
padding: 5px;
.close {
display: inline-flex;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
font-weight: bold;
cursor: pointer;
&:hover,
&:focus {
background: rgba($color: #1367da, $alpha: 0.08);
border-radius: 4px;
color: #1367da;
}
}
}
main {
display: flex;
width: 100%;
max-height: 127px;
overflow-y: hidden;
padding: 30px 40px;
& > div:first-child {
width: 40px;
height: 40px;
}
.content {
display: flex;
flex-wrap: wrap;
align-items: center;
width: 350px;
min-height: 40px;
padding-left: 16px;
& * {
width: 100%;
}
h3 {
margin-bottom: 4px;
font-size: 18px;
font-weight: bold;
color: #333333;
line-height: 22px;
}
p {
text-align: left;
font-size: 14px;
color: #999999;
}
.large {
font-size: 18px;
color: #333333;
}
}
}
footer {
position: absolute;
bottom: 0;
width: 100%;
height: 67px;
padding: 13px 16px;
text-align: right;
}
}
}
</style>
messageBox 弹窗组件代码——main.js
import Vue from 'vue';
import messageBoxVue from '@/plugins/modules/messageBox/messageBox.vue';
const MessageBox = Vue.extend(messageBoxVue); // 直接将Vue组件作为Vue.extend的参数
const messageBox = (message, title, config = {}) => {
return new Promise((resolve, reject) => {
const callback = ret => {
if (ret === true) {
resolve();
} else if (ret === false) {
reject();
}
};
const messageBox = document.querySelector('#messageBox'); // 查询页面现有的 messageBox
if (messageBox) {
// 如果已经存在 messageBox,则停止新的 messageBox 创建
return false;
}
const instance = new MessageBox({
data: {
message: message,
title: title,
lockScroll: config?.lockScroll === false ? false : true, // 是否在 MessageBox 出现时将 body 滚动锁定
dangerouslyUseHTMLString: config?.dangerouslyUseHTMLString || false, // 是否将 message 属性作为 HTML 片段处理, 默认为 false
showCancelButton: config?.showCancelButton === false ? false : true, // 取消按钮显示隐藏,默认 true
showClose: config?.showClose === false ? false : true, // 默认 true
confirmButtonText: config?.confirmButtonText || '确认', // 未配置文本,默认‘确认’
cancelButtonText: config?.cancelButtonText || '取消', // 未配置文本,默认‘取消’
type: config?.type || 'success', // 弹窗类别
callback: callback
}
});
instance.$mount(); // 挂载但是并未插入dom,是一个完整的Vue实例
document.body.appendChild(instance.$el); // 将dom插入body
});
};
export default {
install: Vue => {
Vue.prototype.$messageBox = messageBox; // 将组件暴露出去,并挂载在Vue的prototype上
}
};
在 vue 入口文件 main.js 中引用
import Vue from 'vue';
import messageBox from '@/plugins/messageBox/main.js';
Vue.use(messageBox);