90 lines
1.9 KiB
Vue
90 lines
1.9 KiB
Vue
<template>
|
|
<view class="full-page" :class="pageClass" :style="pageStyle">
|
|
<view v-if="hasHeader" class="page-header">
|
|
<slot name="header"></slot>
|
|
</view>
|
|
<view class="page-main" :class="mainClass" :style="mainStyle">
|
|
<view v-if="customScroll" class="page-scroll">
|
|
<slot></slot>
|
|
</view>
|
|
<scroll-view v-else scroll-y="true" :scroll-top="scrollTop" class="page-scroll" @scrolltolower="scrolltolower"
|
|
@scroll="onScroll">
|
|
<slot></slot>
|
|
</scroll-view>
|
|
</view>
|
|
<view v-if="hasFooter" class="page-footer">
|
|
<slot name="footer"></slot>
|
|
</view>
|
|
<!-- #ifdef MP-->
|
|
<view v-if="showSafeArea" class="safeareaBottom"></view>
|
|
<!-- #endif -->
|
|
</view>
|
|
</template>
|
|
<script setup>
|
|
import { computed, useSlots, ref } from 'vue';
|
|
import useDebounce from '@/utils/useDebounce';
|
|
|
|
const emits = defineEmits(['reachBottom']);
|
|
const props = defineProps({
|
|
customScroll: { type: Boolean, default: false },
|
|
mainClass: { type: String, default: '' },
|
|
mainStyle: { default: '' },
|
|
pageClass: { type: String, default: '' },
|
|
pageStyle: { default: '' },
|
|
showSafeArea: { type: Boolean, default: true }
|
|
});
|
|
const slots = useSlots();
|
|
const hasHeader = computed(() => !!slots.header);
|
|
const hasFooter = computed(() => !!slots.footer);
|
|
|
|
const scrollTop = ref(0);
|
|
|
|
const scrolltolower = useDebounce(() => {
|
|
emits('reachBottom');
|
|
});
|
|
|
|
const onScroll = useDebounce((e) => {
|
|
scrollTop.value = e.detail.scrollTop;
|
|
});
|
|
|
|
function scrollToBottom() {
|
|
scrollTop.value = 999999;
|
|
}
|
|
|
|
defineExpose({
|
|
scrollToBottom
|
|
})
|
|
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.full-page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.page-header,
|
|
.page-footer {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.page-main {
|
|
flex-grow: 1;
|
|
position: relative;
|
|
}
|
|
|
|
.page-scroll {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
}
|
|
|
|
.safeareaBottom {
|
|
flex-shrink: 0;
|
|
height: env(safe-area-inset-bottom);
|
|
}
|
|
</style>
|