|
@@ -0,0 +1,198 @@
|
|
|
+<template>
|
|
|
+ <scroll-view
|
|
|
+ :scroll-y="true"
|
|
|
+ scroll-with-animation
|
|
|
+ :refresher-threshold="refresherThreshold"
|
|
|
+ :refresher-default-style="refresherDefaultStyle"
|
|
|
+ :refresherEnabled="refresherEnabled"
|
|
|
+ :refresher-triggered="triggered"
|
|
|
+ :refresher-background="refresherBackground"
|
|
|
+ :scroll-top="scrollTop"
|
|
|
+ @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"
|
|
|
+ :style="{
|
|
|
+ marginTop: lowerThreshold + 'px',
|
|
|
+ }"
|
|
|
+ v-if="refresherLoad"
|
|
|
+ >
|
|
|
+ {{ pageSize >= total ? "没有更多啦~" : isScrolltolower }}
|
|
|
+ </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 } from "vue";
|
|
|
+
|
|
|
+const emit = defineEmits(["load", "refresh"]);
|
|
|
+const props = defineProps({
|
|
|
+ //当前页数量
|
|
|
+ pageSize: {
|
|
|
+ type: Number,
|
|
|
+ default: 30,
|
|
|
+ },
|
|
|
+ //数据总数
|
|
|
+ total: {
|
|
|
+ type: Number,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
+
|
|
|
+ //设置滚动条位置
|
|
|
+ scrollTop: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ //是否开启上拉加载
|
|
|
+ refresherLoad: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ // 距离底部上拉加载距离
|
|
|
+ lowerThreshold: {
|
|
|
+ type: Number,
|
|
|
+ default: 20,
|
|
|
+ },
|
|
|
+ //是否开启下拉刷新
|
|
|
+ refresherEnabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ //距离顶部下拉刷新距离
|
|
|
+ refresherThreshold: {
|
|
|
+ type: Number,
|
|
|
+ default: 45,
|
|
|
+ },
|
|
|
+ //是否使用默认下拉刷新样式(支持设置 black、white、none/none 表示不使用默认样式)
|
|
|
+ refresherDefaultStyle: {
|
|
|
+ type: String,
|
|
|
+ default: "black",
|
|
|
+ },
|
|
|
+ //设置自定义下拉刷新区域背景颜色
|
|
|
+ refresherBackground: {
|
|
|
+ type: String,
|
|
|
+ default: "#fff",
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const { pageSize, total, scrollTop, refresherLoad, lowerThreshold, refresherEnabled, refresherThreshold, refresherDefaultStyle, refresherBackground } = toRefs(props);
|
|
|
+
|
|
|
+const defaultOption = reactive({});
|
|
|
+
|
|
|
+const {} = toRefs(defaultOption);
|
|
|
+
|
|
|
+const defaultArray = reactive({
|
|
|
+ triggered: false,
|
|
|
+ topTis: "松手刷新",
|
|
|
+ isScrolltolower: "上拉加载更多",
|
|
|
+});
|
|
|
+
|
|
|
+const { triggered, topTis, isScrolltolower } = toRefs(defaultArray);
|
|
|
+
|
|
|
+/**
|
|
|
+ * @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: #909399;
|
|
|
+ font-size: 0.75rem;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes color-change {
|
|
|
+ from {
|
|
|
+ background-color: gray;
|
|
|
+ }
|
|
|
+
|
|
|
+ to {
|
|
|
+ background-color: white;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.bottoBox {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 0.75rem;
|
|
|
+}
|
|
|
+</style>
|