| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- <template>
- <SimpleTransition name="back-to-top" :show="showState" :duration="2000">
- <template #show="{ classNames }">
- <view
- :class="[ 'nana-back-to-top', ...classNames ]"
- :style="{
- right: themeContext.resolveThemeSize(props.right),
- bottom: themeContext.resolveThemeSize(props.bottom),
- zIndex: props.zIndex,
- }"
- @click="onClick"
- >
- <slot>
- <IconButton
- :icon="props.icon"
- :size="40"
- :color="themeContext.resolveThemeColor(props.iconColor)"
- :buttonStyle="{
- ...buttonStyle,
- ...innerStyle,
- }"
- shape="round"
- />
- </slot>
- </view>
- </template>
- </SimpleTransition>
- </template>
- <script setup lang="ts">
- import { onPageScroll } from '@dcloudio/uni-app';
- import { useTheme, type ViewStyle } from '../theme/ThemeDefine';
- import IconButton from '../basic/IconButton.vue';
- import { ref, watch, type Ref } from 'vue';
- import { DynamicColor, DynamicSize, DynamicVar } from '../theme/ThemeTools';
- import SimpleTransition from '../anim/SimpleTransition.vue';
- const themeContext = useTheme();
- export interface BackToTopProps {
- /**
- * 组件距离右侧的距离
- * @default 40
- */
- right?: number|string;
- /**
- * 组件距离底部的距离
- * @default 40
- */
- bottom?: number|string;
- /**
- * 当容器滚动距离大于该值时显示组件(像素)
- * @default 200
- */
- showScrollValue?: number;
- /**
- * 组件的z-index
- * @default 100
- */
- zIndex?: number;
- /**
- * 是否自定义监听滚动容器,否则为监听页面滚动。
- * @default false
- */
- customScrollValue?: boolean;
- /**
- * 内部显示的图标。
- * @default 'arrow-up'
- */
- icon?: string;
- /**
- * 内部图标颜色
- * @default 'white'
- */
- iconColor?: string;
- /**
- * 内部图标样式
- */
- innerStyle?: ViewStyle;
- }
- export interface BackToTopInstance {
- /**
- * 滚动事件,用于自定义滚动容器,若要更换监听的滚动容器,将其绑定至scroll-view的滚动事件上即可:
- * ```
- * <scroll-view @scroll="onScroll"></scroll-view>
- * ```
- * @param e
- */
- onScroll: (e: any) => void;
- /**
- * 自定义滚动容器的滚动距离
- */
- customScrollTop: Ref<number>;
- }
- const emit = defineEmits([
- 'click',
- 'show',
- 'hide'
- ]);
- const props = withDefaults(defineProps<BackToTopProps>(), {
- showScrollValue: 200,
- zIndex: 100,
- icon: 'arrow-up-bold',
- iconColor: 'white',
- customScrollValue: false,
- right: 40,
- bottom: 40,
- });
- const buttonStyle = themeContext.useThemeStyle({
- width: DynamicSize('BackToTopButtonWidth', 80),
- height: DynamicSize('BackToTopButtonHeight', 80),
- borderRadius: '50%',
- boxShadow: DynamicVar('BackToTopButtonBoxShadow', '0 0 8px 0 rgba(0,0,0,0.2)'),
- backgroundColor: DynamicColor('BackToTopButtonBackgroundColor', 'primary'),
- });
- const customScrollTop = ref(0);
- const showState = ref(false);
- watch(showState, (v) => {
- if (v)
- emit('show');
- else
- emit('hide');
- });
- function onScroll(value: number) {
- customScrollTop.value = value;
- showState.value = value > props.showScrollValue;
- }
- function onClick() {
- if (props.customScrollValue) {
- customScrollTop.value = 0;
- } else {
- uni.pageScrollTo({
- scrollTop: 0,
- });
- }
- emit('click');
- }
- onPageScroll((e) => {
- if (props.customScrollValue)
- return;
- onScroll(e.scrollTop);
- });
- defineExpose<BackToTopInstance>({
- customScrollTop,
- onScroll(e) {
- console.log('onScroll', e);
- if (props.customScrollValue)
- onScroll(e.detail.scrollTop);
- },
- })
- defineOptions({
- options: {
- virtualHost: true,
- styleIsolation: "shared",
- },
- });
- </script>
- <style lang="scss">
- .nana-back-to-top {
- position: fixed;
- transition: all 0.3s ease-in-out;
- &.back-to-top-enter-active,
- &.back-to-top-leave-active {
- transform: scale(1);
- opacity: 1;
- }
- &.back-to-top-enter-from,
- &.back-to-top-leave-to {
- transform: scale(0);
- opacity: 0;
- }
- }
- </style>
|