<template>
<transition name="modal-fade">
<div class="b-modal-container" v-show="$props.visible">
<!-- 头部标题 -->
<div class="b-modal-header">
<div class="b-modal-header-title">
<!--具名插槽内容优先级会高于 props-->
<slot name="title">
<span>{{ title }}</span>
</slot>
</div>
<b-icon name="close" class="b-close-icon" @click="close"></b-icon>
</div>
<!-- 内容区域 -->
<div class="b-modal-content">
<slot></slot>
</div>
<!-- 底部按钮 -->
<div class="b-modal-footer">
<div class="b-modal-btn">
<slot name="footer">
<b-button type="default" @click="close">取消</b-button>
<b-button type="primary" @click="ok">确认</b-button>
</slot>
</div>
</div>
</div>
</transition>
<!-- 遮罩层 -->
<div class="mask" v-show="$props.visible" @click="close"></div>
</template>
<script lang="ts">
import BButton from '@/components/button/src/button.vue'
import BIcon from '@/components/icon/src/icon.vue'
import { defineComponent } from 'vue'
import type { PropType } from 'vue'
export default defineComponent({
name: 'BModal',
components: { BButton, BIcon },
props: {
// 模态框标题
title: {
type: String as PropType<string>,
default: '标题'
},
visible: {
type: Boolean as PropType<boolean>,
default: false
}
},
emits: ['cancel', 'update:visible', 'submit'],
setup(props, { emit }) {
// 取消
const close = () => {
emit('cancel')
emit('update:visible', false)
}
// 确认
const ok = () => {
emit('submit')
emit('update:visible', false)
}
return {
close,
ok
}
}
})
</script>
<style scoped lang="less">
@import "../style/modal.less";
</style>
css部分:
.b-modal-container {
position: fixed;
top: 45%;
left: 50%;
z-index: 999;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 460px;
height: 256px;
background-color: #fff;
border-radius: 8px;
transition: 0.5s;
transform: translate(-50%, -50%);
// 头部标题
.b-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 26px 27px;
.b-close-icon {
width: 14px;
height: 14px;
cursor: pointer;
}
}
// 内容
.b-modal-content {
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
width: 100%;
padding: 0 27px;
overflow-y: auto;
}
// 底部按钮
.b-modal-footer {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
height: 60px;
padding: 0 30px;
border: none;
.b-modal-btn {
display: flex;
justify-content: space-between;
button {
margin-left: 12px;
}
}
}
}
// 遮罩层
.mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
width: 100%;
height: 100%;
background-color: rgb(0 0 0 / 30%);
}
// 模态框展示隐藏的动画
.modal-fade-enter-active {
transition: all 0.3s ease-out;
}
.modal-fade-leave-active {
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
}
.modal-fade-enter-from,
.modal-fade-leave-to {
opacity: 0;
transform: translate(-50%, -50%) scale3d(0, 0, 0);
}
// 滚动条
::-webkit-scrollbar {
width: 4px;
height: 8px;
}
// 滚动条头
::-webkit-scrollbar-thumb {
background-color: rgb(184 198 211 / 20%);
border-radius: 1em;
}
// 滚动条轨道
::-webkit-scrollbar-track {
background-color: rgb(244 237 237 / 20%);
border-radius: 1em;
}