WebApp【公共组件库】@前端(For Git Submodule)
‘chensiAb’
2025-03-26 7c51280f1cf4b796f9215133b2f99b397cf5325c
plugins/infiniteScroll/CInfiniteScroll.vue
@@ -5,16 +5,47 @@
<template>
    <scroll-view
        :id="elmId"
        class="c-infinite-scroll"
        :scrollY="true"
        lowerThreshold="100"
        @scroll="evt=>onScroll(evt)"
        @touchstart="evt=>onTouch(evt)"
        @touchmove="evt=>onTouch(evt)"
        @touchend="evt=>onTouch(evt)"
        @scrollToLower="evt=>onScrollToLower(evt)"
    >
        <slot />
        <view
            class="c-infinite-top"
            :class="touching?'touching':''"
            :style="{height: touch.driftTop+'rem'}"
        >
            <view class="inner">
                <view v-if="touch.dargState===2">
                    <AtActivityIndicator />
                    <text class="text">重新加载中...</text>
                </view>
                <view
                    class="tips"
                    v-else
                    :class="touch.dargState===0?'':'release'"
                >
                    <view class="at-icon at-icon-arrow-down"></view>
                    <text class="text">下拉刷新</text>
                    <text class="text">释放刷新</text>
                </view>
            </view>
        </view>
        <view class="c-infinite-content">
            <slot />
        </view>
        <view class="c-infinite-bottom">
            <view
                class="c-infinite-loading"
                v-if="loading"
            >加载中,请稍后...</view>
                v-if="!ending"
            >
                <text v-show="loading">加载中,请稍后...</text>
            </view>
            <view v-if="ending">
                <text
                    class="c-infinite-ended"
@@ -23,14 +54,16 @@
                <text
                    class="c-infinite-empty"
                    v-else
                >暂无数据...</text>
                >(暂无数据)</text>
            </view>
        </view>
    </scroll-view>
</template>
<script>
import Taro from '@tarojs/taro';
import { AtActivityIndicator } from 'taro-ui-vue';
import { Tools } from '@components/common/Tools';
import './cInfiniteScroll.scss';
export default {
@@ -39,21 +72,49 @@
        AtActivityIndicator,
    },
    props: {
        // 是否自动初始化(自动加载第一页)
        autoInit: {
            type: Boolean,
            default: false,
        },
        // 发起加载页面数据回调
        //   参数 {
        //     current: 当前页页码,
        //     next: 需要加载的页面页码,
        //     success: 当加载成功后页面调用, 回传参数 { pageTotal: 当前翻页总页数 }
        //     fail: 加载失败后页面调用
        //   }
        onLoadMore: Function,
    },
    data() {
        return {
            elmId: 'cis-' + Tools.createGUID(),
            // 初始化状态
            inital: false,
            // 当前页面
            current: 0,
            // 总共页面
            pageTotal: 1,
            // 加载中状态
            loading: false,
            // 是否结束状态
            ending: false,
            // 上次滚动位置
            lastScrollTop: 0,
            // 滚动节流器
            scrollTimer: 0,
            // 是否已滚动
            scrolled: false,
            // 滑屏数据
            touch: {
                startX: 0,
                startY: 0,
                lastY: 0,
                dargState: 0,
                driftTop: 0,
            },
            // 正在滑屏状态
            touching: false,
        };
    },
    methods: {
@@ -69,35 +130,56 @@
            // 开始加载
            this.inital = true;
            this.loading = true;
            this.onLoadMore({
                current: this.current,
                next: this.current + 1,
                // 加载成功
                success: (options) => {
                    setTimeout(() => {
                        this.loading = false;
                        // 没有数据
                        if (!options.pageTotal || options.pageTotal <= 0) {
                            this.ending = true;
                        }
                        // 有数据
                        else {
                            this.pageTotal = options.pageTotal;
                            this.current = this.current + 1;
                            // 已到最后一页
                            if (this.current >= this.pageTotal) {
            setTimeout(() => {
                this.onLoadMore({
                    current: this.current,
                    next: this.current + 1,
                    // 加载成功
                    success: options => {
                        this.$nextTick(() => {
                            this.loading = false;
                            // 没有数据
                            if (!options.pageTotal || options.pageTotal <= 0) {
                                this.ending = true;
                                this.pageTotal = 0;
                            }
                            // 有数据
                            else {
                                this.pageTotal = options.pageTotal;
                                this.current = this.current + 1;
                                // 已到最后一页
                                if (this.current >= this.pageTotal) {
                                    this.ending = true;
                                }
                            }
                            // 如果下拉刷新,还原下拉
                            if (this.touch.dargState === 2) {
                                this.touch.driftTop = 0;
                                setTimeout(() => {
                                    this.touch.dargState = 0;
                                }, 300);
                            }
                        });
                    },
                    // 加载失败
                    fail: () => {
                        this.loading = false;
                        this.ending = true;
                        this.pageTotal = 0;
                        // 如果下拉刷新,还原下拉
                        if (this.touch.dargState === 2) {
                            this.touch.driftTop = 0;
                            setTimeout(() => {
                                this.touch.dargState = 0;
                            }, 300);
                        }
                    }, 100);
                },
                // 加载失败
                fail: () => {
                    this.loading = false;
                },
            });
                    },
                });
            }, 100);
        },
        onScroll(evt) {
            // 已经滚动(滚动后禁止下拉刷新)
            this.scrolled = true;
            // 往上
            if (this.lastScrollTop >= evt.detail.scrollTop) {
                this.lastScrollTop = evt.detail.scrollTop;
@@ -105,6 +187,9 @@
            }
            // 往下
            else {
                if (process.env.TARO_ENV !== 'h5') {
                    return;
                }
                const viewHeight = evt.target.offsetHeight;
                const { scrollTop, scrollHeight } = evt.detail;
                // 阀值 100 像素,向下滚动到最后 100 像素,识别为启动加载
@@ -116,13 +201,120 @@
                }
            }
        },
        initScroll() {
        // 小程序中滚动到底部
        onScrollToLower() {
            if (process.env.TARO_ENV !== 'weapp') {
                return;
            }
            this.hanldeLoadMore();
        },
        // 手指拨动
        onTouch(evt) {
            // 拉动长度(少于这个值的时候下拉但是不刷新)
            const deviationY = 50;
            // 拉动的最大高度
            const maxTransY = 100;
            // 按下
            if (evt.type === 'touchstart') {
                this.touching = true;
                // 手指按下,重置是否已滚动
                this.scrolled = false;
                if (evt.touches.length !== 1) {
                    return;
                }
                this.touch.startX = evt.touches[0].clientX;
                this.touch.startY = evt.touches[0].clientY;
                this.touch.lastY = evt.touches[0].clientY;
            }
            // 滑动
            else if (evt.type === 'touchmove') {
                // 已滚动跳过
                if (this.scrolled) {
                    return;
                }
                // 加载中跳过
                if (this.loading) {
                    return;
                }
                this.touching = true;
                // 左右偏移判断(向下拉时,如果左右偏移超过阀值不执行下拉操作)
                const ratio =
                    Math.abs(evt.touches[0].clientX - this.touch.startX) /
                    Math.abs(evt.touches[0].clientY - this.touch.startY);
                const dragDown = this.touch.lastY - evt.touches[0].clientY < 0;
                this.touch.lastY = evt.touches[0].clientY;
                if (dragDown && ratio > 0.3) {
                    return;
                }
                // 拖动距离
                const deltY = evt.touches[0].clientY - this.touch.startY;
                // 拖动值=拖动距离/拖动倍率,使拖动的时候有粘滞的感觉
                const transY = Math.min(Math.abs(deltY) / 4, maxTransY);
                if (deltY > 0) {
                    this.touch.driftTop = (transY / maxTransY) * 5;
                    // 超过阀值,可以刷新
                    if (transY >= deviationY) {
                        this.touch.dargState = 1;
                    }
                    // 小于阀值,不能刷新
                    else {
                        this.touch.dargState = 0;
                    }
                } else {
                    this.touch.driftTop = 0;
                }
            }
            // 松开
            else if (evt.type === 'touchend') {
                this.touching = false;
                // 已滚动跳过
                if (this.scrolled) {
                    this.touch.driftTop = 0;
                    return;
                }
                // 加载中跳过
                if (this.loading) {
                    this.touch.driftTop = 0;
                    return;
                }
                // 不刷新
                if (this.touch.dargState === 0) {
                    this.touch.driftTop = 0;
                    return;
                }
                // 刷新数据
                if (this.touch.dargState === 1) {
                    this.touch.driftTop = (deviationY / maxTransY) * 5;
                    // 重新加载
                    this.touch.dargState = 2;
                    this.ending = false;
                    this.current = 0;
                    this.hanldeLoadMore();
                }
            }
        },
        // 初始加载
        $initScroll() {
            // 已初始化,跳过
            if (this.inital) {
                return;
            }
            this.hanldeLoadMore();
        },
        // 刷新加载
        $refresh(autoStart) {
            Taro.pageScrollTo({
                selector: '#' + this.elmId,
                scrollTop: 0,
            });
            this.ending = false;
            this.current = 0;
            if (autoStart === 'off') {
                this.inital = false;
            } else {
                this.hanldeLoadMore();
            }
        },
    },
    mounted() {
        // 开启自动初始化