| | |
| | | |
| | | <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" |
| | |
| | | <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 { |
| | |
| | | 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: { |
| | |
| | | // 开始加载 |
| | | 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; |
| | |
| | | } |
| | | // 往下 |
| | | else { |
| | | if (process.env.TARO_ENV !== 'h5') { |
| | | return; |
| | | } |
| | | const viewHeight = evt.target.offsetHeight; |
| | | const { scrollTop, scrollHeight } = evt.detail; |
| | | // 阀值 100 像素,向下滚动到最后 100 像素,识别为启动加载 |
| | |
| | | } |
| | | } |
| | | }, |
| | | 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() { |
| | | // 开启自动初始化 |