Files
timi-tdesign-mobile/src/components/bottom-popup/index.vue
T
2026-08-31 15:57:20 +08:00

133 lines
2.8 KiB
Vue

<template>
<t-popup v-model="visible" placement="bottom">
<div class="bottom-popup" :style="{ height: props.height }">
<div v-if="hasHeader" class="header">
<div class="button left">
<slot name="leftButton" :on-click="emitLeftButtonClick">
<t-button v-if="leftButtonText" variant="text" size="small" @click="emitLeftButtonClick">
<span v-text="leftButtonText" />
</t-button>
</slot>
</div>
<div class="title text-bold">
<slot name="title">
<span v-text="title" />
</slot>
</div>
<div class="button right">
<slot name="rightButton" :on-click="emitRightButtonClick">
<t-button v-if="rightButtonText" theme="primary" variant="text" size="small" @click="emitRightButtonClick">
<span v-text="rightButtonText" />
</t-button>
</slot>
</div>
</div>
<div class="body">
<slot />
</div>
</div>
</t-popup>
</template>
<script lang="ts" setup>
defineOptions({
name: "BottomPopup"
});
export interface BottomPopupProps {
modelValue?: boolean;
leftButtonText?: string;
rightButtonText?: string;
height?: string | number;
title?: string;
}
export interface BottomPopupSlots {
default?: () => unknown;
title?: () => unknown;
leftButton?: (props: { onClick: () => void }) => unknown;
rightButton?: (props: { onClick: () => void }) => unknown;
}
const props = withDefaults(defineProps<BottomPopupProps>(), {
modelValue: false,
leftButtonText: "取消",
rightButtonText: "确定",
height: "auto",
title: ""
});
const emit = defineEmits<{
"update:modelValue": [value: boolean];
leftButtonClick: [];
rightButtonClick: [];
}>();
const slots = useSlots() as BottomPopupSlots;
const visible = computed({
get: () => props.modelValue,
set: value => emit("update:modelValue", value)
});
const hasHeader = computed<boolean>(() => Boolean(
props.title
|| props.leftButtonText
|| props.rightButtonText
|| slots.title
|| slots.leftButton
|| slots.rightButton
));
function emitLeftButtonClick(): void {
emit("leftButtonClick");
}
function emitRightButtonClick(): void {
emit("rightButtonClick");
}
defineSlots<BottomPopupSlots>();
</script>
<style lang="less" scoped>
.bottom-popup {
display: flex;
overflow: hidden;
padding-top: 1rem;
background: var(--td-bg-color-container, #fff);
border-radius: 1.25rem 1.25rem 0 0;
flex-direction: column;
.header {
flex: none;
padding: 0 1rem;
display: grid;
align-items: center;
grid-template-columns: 4rem 1fr 4rem;
}
.button {
min-width: 0;
display: flex;
&.right {
justify-content: flex-end;
}
}
.title {
margin: 0;
overflow: hidden;
text-align: center;
white-space: nowrap;
text-overflow: ellipsis;
}
.body {
flex: 1;
padding: 0 0 env(safe-area-inset-bottom, 0);
overflow: auto;
min-height: 0;
}
}
</style>