最近项目中的弹窗用到的地方有点多,就基于nut-ui封装了一个自己的弹窗,主要就是写了一个样式,出现的时候增加了从下到上的动画(slide-up)
这是基本的template
<template>
<nut-popup
v-model:visible="isVisible"
:overlay="showOverlay"
round
:overlay-class="overlayClass"
:overlay-style="overlayStyle"
:z-index="zIndex"
position="center"
transition="slide-up"
:style="popupStyle"
@click-overlay="handleClickOverlay"
>
<view class="custom-popup">
<view
class="popup-content"
:style="{ height: popupHeight }"
>
<slot></slot>
</view>
<view class="popup-footer">
<slot name="footer"></slot>
</view>
</view>
</nut-popup>
</template>
import { computed } from 'vue';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
showOverlay: {
type: Boolean,
default: true,
},
height: {
type: [String, Number],
default: 'auto',
},
zIndex: {
type: Number,
default: 2000,
},
closeOnClickOverlay: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['update:visible', 'close']);
const isVisible = computed({
get: () => props.visible,
set: value => emit('update:visible', value),
});
const popupHeight = computed(() => {
if (typeof props.height === 'number') {
return `${props.height}px`;
}
return props.height;
});
const overlayClass = computed(() => ({
'custom-overlay': true,
'no-overlay': !props.showOverlay,
}));
//这里返回一个对象
const overlayStyle = computed(() => ({
background: props.showOverlay ? 'rgba(0, 0, 0, 0.7)' : 'transparent',
}));
const popupStyle = computed(() => ({
maxWidth: '90%',
maxHeight: '90%',
overflow: 'auto',
}));
const handleClickOverlay = () => {
if (props.closeOnClickOverlay) {
isVisible.value = false;
emit('close');
}
};
.custom-popup {
background-color: #fff;
border-radius: 8px;
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.popup-content {
flex: 1;
overflow-y: auto;
}
.popup-footer {
margin-top: 20px;
}
.no-overlay {
pointer-events: none;
}
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.3s ease-out;
}
.slide-up-enter-from,
.slide-up-leave-to {
transform: translateY(100%);
opacity: 0;
}
.slide-up-enter-to,
.slide-up-leave-from {
transform: translateY(0);
opacity: 1;
}Ï