需求
最近项目有需求说要用户在弹窗内做一些事情,考虑使用第三方的Vodal,但是发现这个库好久没有更新了,于是乎就自己封装了一个。
分析
- 弹窗结构主要包括:头部、内容、遮罩;
- 实现的功能:设定宽高、设定弹框标题、设定是否显示遮罩等
预期效果
代码部分
- 在
components文件目录下新建一个MyDialog目录,存放一个index.vue组件
- 逻辑代码
<template>
<div v-if="ifShow" v-show="mainShow" :style="{'z-index': zIndex}" :class="{'window': window}" class="my-dialog-main">
<div v-show="mask && !window" class="my-dialog-mask" />
<transition name="el-zoom-in-center">
<div v-show="show" :style="{'height': height, 'width': width}" class="my-dialog">
<div class="my-dialog-button">
<div class="close">
<i class="el-icon-close" @click="close" />
</div>
</div>
<div class="my-dialog-head">
<div>
<i class="el-icon-info" />
{{ title }}
</div>
</div>
<div class="line" />
<div :class="{'my-dialog-body-padding': padding}" class="my-dialog-body">
<slot />
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: 'DialogIndex',
props: {
show: { // 是否显示
type: Boolean,
default: false
},
title: { // 标题
type: String,
default: '我的弹框组件'
},
height: { // window为false时,控制弹框高度
type: [String, Number],
default: '500px'
},
width: { // window为false时,控制弹框宽度
type: [String, Number],
default: '500px'
},
window: { // window为true时,开启窗口模式
type: Boolean,
default: false
},
padding: { // 是否启用 dialog-body 内置padding: 15px 20px;
type: Boolean,
default: false
},
mask: { // window为false时,控制是否显示遮罩,true:显示,false:不显示
type: Boolean,
default: true
}
},
data() {
return {
ifShow: false,
mainShow: false,
zIndex: 100,
dialogWidth: store.state.sliderCollapse
}
},
watch: {
show(val) {
// 同一页面调用多个弹窗层级问题
if (val) {
const dialogs = document.querySelectorAll('.my-dialog-main')
let maxZindex = 100
dialogs.forEach((item) => {
const zIndex = item.style.zIndex ? Number(item.style.zIndex) : 0
if (item.style.display !== 'none' && zIndex >= maxZindex) {
maxZindex = zIndex + 1
}
})
this.zIndex = maxZindex
this.ifShow = val
this.mainShow = val
} else {
setTimeout(() => {
this.mainShow = val
}, 200)
}
}
},
mounted() {
this.$nextTick(() => {
setTimeout(() => {
const body = document.querySelector('#app')
const child = body ? body.children : ''
let append = ''
if (child) {
for (let i = 0; i < child.length; i++) {
if (child[i].style.display !== 'none') {
append = child[i]
}
}
}
if (append) {
if (append.append) {
append.append(this.$el)
}
}
}, 300)
})
},
methods: {
close() {
this.$emit('close')
}
}
}
</script>
<style lang="scss" scoped>
.my-dialog-main {
position: fixed;
top: 80px;
left: 242px;
width: calc(100% - 280px);
height: calc(100% - 100px);
z-index: 100;
.my-dialog-mask {
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
background: rgba(0,0,0,.3);
}
.my-dialog {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 101;
background: #fff;
border-radius: 3px;
.my-dialog-button {
top: 12px;
right: 12px;
position: absolute;
.close {
font-size: 20px;
font-weight: 600;
color: #999;
cursor: pointer;
&:hover {
color: #333;
}
> i {
font-weight: 600;
}
}
}
.line {
width: 100%;
height: 2px;
background: #99a6ff;
opacity: 1;
}
.my-dialog-head {
height: 30px;
font-size: 16px;
font-weight: 600;
text-align: left;
line-height: 30px;
padding: 12px 0 12px 12px;
}
.my-dialog-body {
height: calc(100% - 42px);
overflow: auto;
}
.my-dialog-body-padding {
padding: 15px 20px;
}
}
}
.window {
position: absolute;
width: 100%;
height: 100%;
-webkit-box-shadow: 1px 1px 8px 6px #eaeaea;
box-shadow: 1px 1px 8px 6px #eaeaea;
z-index: 99;
.my-dialog {
height: 100% !important;
width: 100% !important;
}
}
</style>
使用
写到最后
高度、宽度、支持百分比和px且支持窗口模式和全局模式,如有不足还请大佬指正。