123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- <template>
- <scroll-view
- :class="customClass"
- :style="{
- //#ifdef APP-PLUS || MP-WEIXIN
- height: `calc(100vh - (${!isSticky ? '0px' : '44px'}))`,
- //#endif
- //#ifdef H5
- height: `calc(100vh - (${!isSticky ? '44px' : '88px'}))`,
- //#endif
- ...customStyle,
- }"
- :scroll-y="true"
- scroll-with-animation
- :refresher-threshold="refresherThreshold"
- :refresher-default-style="refresherDefaultStyle"
- :refresherEnabled="refresherEnabled"
- :refresher-triggered="triggered"
- :refresher-background="refresherBackground"
- :scroll-top="scrollTop"
- :scroll-into-view="scrollIntoView"
- @refresherrefresh="onRefresh"
- @scrolltolower="scrolltolower"
- >
- <slot name="topLoading" v-if="refresherDefaultStyle === 'none'">
- <view
- class="topBox"
- :style="{
- marginTop: '-' + refresherThreshold + 'px',
- height: refresherThreshold + 'px',
- }"
- >
- <view class="loader">
- <view v-for="(v, i) in 10" :key="v" :style="{ transform: 'rotate(' + i * 36 + 'deg)', animationDelay: v == 10 ? 1 + 's' : '0.' + v + 's' }"> </view>
- </view>
- <view class="title">
- {{ topTis }}
- </view>
- </view>
- </slot>
- <slot name="default"> </slot>
- <slot name="bottomLoading">
- <div class="bottoBox">
- <span
- v-show="total != 0 && refresherLoad && refresherLoadTitle"
- :style="{
- marginTop: '20px',
- marginBottom: '20px',
- }"
- >
- {{ pageSize >= total ? "没有更多啦~" : isScrolltolower }}
- </span>
- <span
- v-show="total == 0 && refresherEnabled && refresherEnabledTitle && !triggered"
- :style="{
- marginTop: '20px',
- marginBottom: '20px',
- }"
- >
- <image style="width: 160px; height: 160px" src="@/static/images/data.png"></image>
- <view>暂无数据</view>
- </span>
- </div>
- </slot>
- </scroll-view>
- </template>
- <script setup>
- import { onReady, onLoad, onShow, onNavigationBarButtonTap, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
- import { ref, onMounted, inject, shallowRef, reactive, getCurrentInstance, watchEffect, toRefs, toRef, watch, computed } from "vue";
- const emit = defineEmits(["load", "refresh"]);
- const props = defineProps({
- //当前页数量
- pageSize: {
- type: Number,
- default: 30,
- },
- //数据总数
- total: {
- type: Number,
- default: 0,
- },
- //设置滚动条位置
- scrollTop: {
- type: String,
- default: "",
- },
- //设置外部class
- customClass: {
- type: String,
- default: "",
- },
- //设置外部style
- customStyle: {
- type: [String, Object],
- default: {},
- },
- //是否开启吸顶高度自适应
- isSticky: {
- type: Boolean,
- default: false,
- },
- //是否开启上拉加载
- refresherLoad: {
- type: Boolean,
- default: false,
- },
- //是否显示上拉加载文字
- refresherLoadTitle: {
- type: Boolean,
- default: true,
- },
- //是否开启下拉刷新
- refresherEnabled: {
- type: Boolean,
- default: false,
- },
- //是否显示下拉刷新文字
- refresherEnabledTitle: {
- type: Boolean,
- default: true,
- },
- //距离顶部下拉刷新距离
- refresherThreshold: {
- type: Number,
- default: 44,
- },
- //是否使用默认下拉刷新样式(支持设置 black、white、none/none 表示不使用默认样式)
- refresherDefaultStyle: {
- type: String,
- default: "black",
- },
- //设置自定义下拉刷新区域背景颜色
- refresherBackground: {
- type: String,
- default: "#fff",
- },
- //是否滚动到指定id的位置
- scrollIntoView: {
- type: String,
- default: "",
- },
- });
- const {
- pageSize,
- total,
- scrollTop,
- customClass,
- customStyle,
- refresherLoad,
- refresherLoadTitle,
- refresherEnabled,
- refresherEnabledTitle,
- refresherThreshold,
- refresherDefaultStyle,
- refresherBackground,
- } = toRefs(props);
- const state = reactive({
- StatusBarHeight: computed(() => {
- let systemInfo = uni.getSystemInfoSync();
- return systemInfo.statusBarHeight + "px";
- }),
- tabBarHeight: computed(() => {
- let systemInfo = uni.getSystemInfoSync();
- return systemInfo.screenHeight - systemInfo.safeArea.bottom + "px";
- }),
- triggered: false,
- topTis: "松手刷新",
- isScrolltolower: "上拉加载更多",
- });
- const { StatusBarHeight, tabBarHeight, triggered, topTis, isScrolltolower } = toRefs(state);
- /**
- * @scrollView上拉刷新
- */
- function onRefresh() {
- isScrolltolower.value = "上拉加载更多";
- topTis.value = "努力加载中";
- //做一个判断,判断triggered 是否为true
- if (!triggered.value) {
- triggered.value = true;
- setTimeout((e) => {
- triggered.value = false;
- topTis.value = "松手刷新";
- emit("refresh");
- }, 1000);
- }
- }
- /**
- * @scrollView触底事件
- */
- function scrolltolower(e) {
- if (!refresherLoad.value || pageSize.value >= total.value) {
- return;
- } else {
- isScrolltolower.value = "正在加载中~";
- setTimeout(() => {
- emit("load");
- isScrolltolower.value = "上拉加载更多";
- }, 1000);
- }
- }
- onLoad((option) => {});
- </script>
- <style scoped>
- .topBox {
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- color: gray;
- }
- .topBox .loader {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- position: relative;
- margin-top: -25rpx;
- }
- .topBox .loader view {
- width: 2px;
- height: 6px;
- background-color: gray;
- transform-origin: 50% 150%;
- position: absolute;
- animation: color-change 1s infinite;
- }
- .topBox .title {
- position: relative;
- margin-left: 35rpx;
- color: #c0c4cc;
- font-size: 14px;
- }
- @keyframes color-change {
- from {
- background-color: gray;
- }
- to {
- background-color: white;
- }
- }
- .bottoBox {
- display: flex;
- align-items: center;
- text-align: center;
- justify-content: center;
- color: #c0c4cc;
- font-size: 14px;
- }
- </style>
|