<template> <div class="bs-wrapper" ref="wrapper"> <div class="scroller"> <div class="pull-down-tips" v-if="pulldown"> <div v-html="tipText"></div> </div> <slot> </slot> <div class="pull-up-tips" v-if="!loadOver && pullup"> <div v-if="!isPullUpLoad" class="before-trigger"> <span class="pul-lup-txt">加载更多</span> </div> <div v-else class="after-trigger"> <span class="pull-up-txt">加载中...</span> </div> </div> </div> </div> </template> <script lang="ts"> import { Component, Prop, Vue, Watch } from "vue-property-decorator"; import BScroll from "@better-scroll/core"; import PullDown from "@better-scroll/pull-down"; import Pullup from "@better-scroll/pull-up"; //注册插件 BScroll.use(PullDown); BScroll.use(Pullup); const PHASE: any = { moving: { enter: "enter", leave: "leave", }, fetching: "fetching", succeed: "succeed", }; const ARROW_BOTTOM = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M367.997 338.75l-95.998 95.997V17.503h-32v417.242l-95.996-95.995l-22.627 22.627L256 496l134.624-134.623l-22.627-22.627z"></path></svg>'; const ARROW_UP = '<svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M390.624 150.625L256 16L121.376 150.625l22.628 22.627l95.997-95.998v417.982h32V77.257l95.995 95.995l22.628-22.627z"></path></svg>'; /** * @description: 滚动组件 * @author: ZPFly * @date: 2021/2/3 10:26 */ @Component({ name: "ScrollerView", components: {}, }) export default class ScrollerView extends Vue { /** * 开启横向滚动 */ @Prop({ default: false }) scrollX: boolean | undefined; /** * 滚动高度 */ @Prop({ default: 0 }) height: number | undefined; /** * 是否派发滚动到底部的事件,用于上拉加载 */ @Prop({ default: false }) pullup: boolean | undefined; /** * 是否派发顶部下拉的事件,用于下拉刷新 */ @Prop({ default: false }) pulldown: boolean | undefined; /** * 是否派发滚动事件事件 */ @Prop({ default: false }) listenScroll: boolean | undefined; /** * 刷新数据方法 */ @Prop({ default: () => {} }) refreshData: any | undefined; /** * 加载更多数据方法 */ @Prop({ default: () => {} }) loadData: any | undefined; /***/ scroll: any | undefined; tipText = ""; isPullUpLoad = false; loadOver = false; refresh() { setTimeout(() => { this.scroll.refresh(); }, 100); } // 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常 _initScroll() { if (!this.$refs.wrapper) { return; } // better-scroll的初始化 this.scroll = new BScroll(this.$refs.wrapper as any, { probeType: 1, scrollX: this.scrollX, scrollY: !this.scrollX, preventDefault: false, pullUpLoad: true, pullDownRefresh: { threshold: 80, stop: 60, }, }); // 下拉刷新 if (this.pulldown) { this.scroll.on("enterThreshold", () => { this.setTipText(PHASE.moving.enter); }); this.scroll.on("leaveThreshold", () => { this.setTipText(PHASE.moving.leave); }); this.scroll.on("pullingDown", () => { this.setTipText(PHASE.fetching); this.refreshData().then(() => { this.finishPullDown(); }); }); } else { this.stopPullDown(); this.scroll.on("scrollEnd", () => { this.finishPullDown(); }); } // 上拉加载 if (this.pullup) { this.scroll.on("pullingUp", () => { this.isPullUpLoad = true; if(!this.loadOver) { this.loadData().then((loadOver: boolean) => { this.loadOver = loadOver; this.isPullUpLoad = false; this.scroll.finishPullUp(); this.refresh(); }); } }); } // 是否派发滚动事件 if (this.listenScroll) { this.scroll.on("scroll", (pos: any) => { this.$emit("scroll", pos); }); } this.refresh(); } // 不用下拉刷新时,阻止下拉 stopPullDown() { const scroller: any = this.$el.querySelector(".scroller"); const hooks = this.scroll.scroller.actions.hooks; const top = scroller.getBoundingClientRect().top; hooks.on("beforeMove", (e: any) => { return scroller.getBoundingClientRect().top > top; }); } finishPullDown() { this.setTipText(PHASE.succeed); this.scroll.finishPullDown(); this.refresh(); } setTipText(phase = PHASE.default) { const PULL_DOWN_TEXTS: any = { enter: `${ARROW_BOTTOM} 下拉刷新`, leave: `${ARROW_UP} 释放刷新`, fetching: "加载中...", succeed: "刷新成功", }; this.tipText = PULL_DOWN_TEXTS[phase]; } mounted() { this.initHeight(); // 保证在DOM渲染完毕后初始化better-scroll this.$nextTick(() => { this._initScroll(); }); } // 初始化高度 initHeight() { const el: any = this.$el; if (this.height) { el.style.height = this.height + "px"; } } } </script> <style lang="scss" scoped> .bs-wrapper { position: relative; height: inherit; overflow: hidden; } .scroller { padding-bottom: 2px; } .pull-down-tips { position: absolute; width: 100%; padding: 20px; box-sizing: border-box; transform: translateY(-100%) translateZ(0); text-align: center; color: #999; } .pull-up-tips { padding: 10px; text-align: center; color: #999; } </style>