You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
1.5 KiB
Vue
85 lines
1.5 KiB
Vue
<template>
|
|
<!-- 遮罩层 -->
|
|
<view v-if="visible" class="popup-mask" @click="close">
|
|
<view @click.stop class="popup-content" :style="{ transform: transformStyle }">
|
|
<slot></slot>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
ref,
|
|
computed,
|
|
defineExpose
|
|
} from 'vue'
|
|
|
|
const props = defineProps({
|
|
position: {
|
|
type: String,
|
|
default: 'bottom'
|
|
},
|
|
duration: {
|
|
type: Number,
|
|
default: 300
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(['open', 'close'])
|
|
|
|
const visible = ref(false)
|
|
const animating = ref(false)
|
|
|
|
// 动画样式
|
|
const transformStyle = computed(() => {
|
|
if (animating.value) return 'translateY(0%)'
|
|
if (props.position === 'bottom') return 'translateY(100%)'
|
|
if (props.position === 'top') return 'translateY(-100%)'
|
|
return 'scale(0.8)'
|
|
})
|
|
|
|
// 对外暴露的方法
|
|
function open() {
|
|
visible.value = true
|
|
animating.value = false
|
|
setTimeout(() => {
|
|
animating.value = true
|
|
emit('open')
|
|
}, 20)
|
|
}
|
|
|
|
function close() {
|
|
animating.value = false
|
|
setTimeout(() => {
|
|
visible.value = false
|
|
emit('close')
|
|
}, props.duration)
|
|
}
|
|
|
|
defineExpose({
|
|
open,
|
|
close
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
.popup-mask {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: flex-end;
|
|
z-index: 999;
|
|
}
|
|
|
|
.popup-content {
|
|
width: 100%;
|
|
background: #fff;
|
|
border-radius: 16rpx 16rpx 0 0;
|
|
transition: transform 0.3s ease;
|
|
}
|
|
</style> |