美文网首页
better-scroll在vue的使用

better-scroll在vue的使用

作者: 小虾米前端 | 来源:发表于2019-12-10 09:53 被阅读0次

    某一个页面的列表使用better-scroll的上拉加载和下拉刷新功能,better-scroll被封装成vue的组件

    1。页面中

     <my-scroll
            ref="myScroll"
            :startY="parseInt(startY)"
            :listArr="state.testList"  // 列表数据
            :haveDataFlag="state.listHaveDataFlag" //分页请求,下一页是否有数据的标识
            :pullup="pullupFlag" // 是否开启上拉加载
            @scrollEnd="onLoadFun" // 上拉加载的方法
            :pullDownRefresh="pullDownRefreshObj" // 是否派发下拉刷新
            @pullingDown="onPullingDown" //下拉刷新的方法
          >
            <test-list></test-list> //列表
          </my-scroll>
    
    data() {
        return {
          pullDownRefresh: true,
          startY: 0,
          pullDownRefreshThreshold: 90, 
          pullDownRefreshStop: 40,
          pullupFlag: true, // 上拉加载
        };
      },
    
    computed:{
      pullDownRefreshObj() {
          return this.pullDownRefresh
            ? {
                threshold: parseInt(this.pullDownRefreshThreshold),
                stop: parseInt(this.pullDownRefreshStop)
              }
            : false;
        }
    }
    methods:{
        // 上拉加载
        async onLoadFun() {
          await this.updateInfo({
            pageNum: this.state.pageNum+ 1
          });
          if (this.state.nextTestList.length === 0) {
    // 如果下一页没有数据,停止上拉加载
            this.pullupFlag = false;
            return;
          }
    // 请求接口
          await this.listRequest();
        },
        // 下拉刷新
        async onPullingDown() {
        //打印this可以看到_isDestroyed,当前实例是否已经被销毁
          if (this._isDestroyed) return;
          await this.updateInfo({
            stockMarketPageNum: 1, // 行情列表分页
            stockMarketList: [], // 行情列表
            nextStockMarketList: [] //行情新请求列表
          });
          this.listRequest();
        },
    // 重新初始化组件
    rebuildScroll() {
          Vue.nextTick(() => {
            this.$refs.myScroll.destroy();
            this.$refs.myScroll.initScroll();
          });
        },
    },
     watch: {
        startY(nval,oval) {
          this.rebuildScroll();
        }
      },
    
    
    1. 组件中
    <template>
      <div class="my-scroll" ref="myScroll">
        <div class="scroll-content">
          <slot></slot>
          <div class="pull-up-box" v-if="fatherNeedPullFlag">
            <img
              v-show="isPullUp"
              src="@/assets/img/loading_01.gif"
              alt
              style="width:0.2rem;height0.2rem;"
            />
            <div :class="listArr.length > 0 ? 'have-data':'no-data'">
              <span v-show="haveDataFlag">没有更多数据了</span>
            </div>
          </div>
        </div>
        <slot
          name="pulldown"
          :pullDownRefresh="pullDownRefresh"
          :pullDownStyle="pullDownStyle"
          :beforePullDown="beforePullDown"
          :isPullingDown="isPullingDown"
        >
          <div ref="pulldown" class="pulldown-wrapper" :style="pullDownStyle" v-if="pullDownRefresh">
            <div class="before-trigger" v-if="beforePullDown"></div>
            <div class="after-trigger" v-else>
              <div v-if="isPullingDown" class="loading">
                <img style="width:0.3rem;height:0.3rem;" src="@/assets/img/loading_01.gif" />
              </div>
              <div v-else>
                <p class="refresh-txt">{{ refreshTxt }}</p>
              </div>
            </div>
          </div>
        </slot>
      </div>
    </template>
    
    <script type="text/ecmascript-6">
    import BScroll from "better-scroll";
    export default {
      name: "myScroll",
      data() {
        return {
          beforePullDown: true,
          pullDownStyle: "",
          isPullingDown: false,
          isRebounding: false
        };
      },
      props: {
        scrollFun: {
          type: Function,
          default: function() {
            return f => f;
          }
        },
        /**
         * 1 滚动的时候会派发scroll事件,会截流。
         * 2 滚动的时候实时派发scroll事件,不会截流。
         * 3 除了实时派发scroll事件,在惯性或动画的情况下仍然能实时派发scroll事件
         */
        probeType: {
          type: Number,
          default: 1
        },
        /**
         * 点击列表是否派发click事件
         */
        click: {
          type: Boolean,
          default: true
        },
        /**
         * 是否开启横向滚动
         */
        scrollX: {
          type: Boolean,
          default: false
        },
        /**
         * 是否派发滚动事件
         */
        listenScroll: {
          type: Boolean,
          default: false
        },
        /**
         * 列表的数据
         */
        listArr: {
          type: Array,
          default: null
        },
        /**
         * 是否派发滚动到底部的事件,用于上拉加载
         */
        pullup: {
          type: Boolean,
          default: false
        },
        /**
         * 是否派发顶部下拉的事件,用于下拉刷新
         */
        pullDownRefresh: {
          type: null,
          default: false
        },
        /**
         * 是否派发列表滚动开始的事件
         */
        beforeScroll: {
          type: Boolean,
          default: false
        },
        /**
         * 当数据更新后,刷新scroll的延时。
         */
        refreshDelay: {
          type: Number,
          default: 20
        },
        bounce: {
          // 当滚动超过边缘的时候会有一小段回弹动画
          type: Boolean,
          default: true
        },
        fatherNeedPullFlag: {
          // 是否展示底部加载动画和文字
          type: Boolean,
          default: true
        },
        // nextListArr: { // 下次请求的新数据
        //   type:Array,
        //   default:[]
        // },
        isPullUp: {
          type: Boolean,
          default: false
        },
        haveDataFlag: {
          type: Boolean,
          default: false
        }
      },
      created() {
        this.pullDownInitTop = -40;
      },
      computed: {
        refreshTxt() {
          return (this.pullDownRefresh && this.pullDownRefresh.txt) || "刷新成功";
        }
      },
      mounted() {
        this.$nextTick(() => {
          this._initScroll();
        });
      },
      destroyed() {
        this.$refs.myScroll && this.$refs.myScroll.destroy();
      },
      methods: {
        _initScroll() {
          if (!this.$refs.myScroll) {
            return;
          }
          let options = {
            probeType: this.probeType,
            scrollX: this.scrollX,
            bounce: this.bounce, // 回弹动画
            pullup: this.pullup,
            pullDownRefresh: this.pullDownRefresh,
            taps: true,
            click: true
          };
          // better-scroll的初始化
          this.scroll = new BScroll(this.$refs.myScroll, options);
          // 是否派发滚动事件
          if (this.listenScroll) {
            this.scroll.on("scroll", pos => {
              this.$emit("scroll", pos);
            });
          }
          // 是否派发滚动到底部事件,用于上拉加载
          if (this.pullup) {
            this.scroll.on("scrollEnd", () => {
              // 滚动到底部
              if (this.scroll.y <= this.scroll.maxScrollY + 50) {
                this.$emit("scrollEnd");
              }
            });
          }
          // 监听滚动高度
          if (this.scrollFun) {
            this.scroll.on("scroll", scrollValue => {
              // 滚动到底部
              // console.log(scrollValue.y)
              this.$emit("scrollFun", scrollValue);
            });
          }
    
          // 是否派发顶部下拉事件,用于下拉刷新
          if (this.pullDownRefresh) {
            this._initPullDownRefresh();
          }
          // 是否派发列表滚动开始的事件
          if (this.beforeScroll) {
            this.scroll.on("beforeScrollStart", () => {
              this.$emit("beforeScroll");
            });
          }
        },
        forceUpdate() {
          if (this.pullDownRefresh && this.isPullingDown) {
            this.isPullingDown = false;
            this._reboundPullDown().then(() => {
              this._afterPullDown();
            });
          }
          if (this.pullup && this.isPullUp) {
            this.isPullUp = false;
            this.scroll.finishPullUp();
            this.refresh();
          } else {
            this.refresh();
          }
        },
        _afterPullDown() {
          setTimeout(() => {
            this.pullDownStyle = `top:${this.pullDownInitTop}px`;
            this.beforePullDown = true;
            this.isRebounding = false;
            this.refresh();
          }, this.scroll.options.bounceTime);
        },
        _initPullDownRefresh() {
          this.scroll.on("pullingDown", () => {
            this.beforePullDown = false;
            this.isPullingDown = true;
            this.$emit("pullingDown");
          });
    
          this.scroll.on("scroll", pos => {
            if (!this.pullDownRefresh) {
              return;
            }
            if (this.beforePullDown) {
              this.pullDownStyle = `top:${Math.min(
                pos.y + this.pullDownInitTop,
                0
              )}px`;
            }
            if (this.isRebounding) {
              this.pullDownStyle = `top:${0 -
                (this.pullDownRefresh.stop - pos.y)}px`;
            }
          });
        },
        _reboundPullDown() {
          const { stopTime = 300 } = this.pullDownRefresh;
          return new Promise(resolve => {
            setTimeout(() => {
              this.isRebounding = true;
              this.scroll.finishPullDown();
              resolve();
            }, stopTime);
          });
        },
        disable() {
          // 代理better-scroll的disable方法
          this.scroll && this.scroll.disable();
        },
        enable() {
          // 代理better-scroll的enable方法
          this.scroll && this.scroll.enable();
        },
        refresh() {
          // 代理better-scroll的refresh方法
          this.scroll && this.scroll.refresh();
        },
        scrollTo() {
          // 代理better-scroll的scrollTo方法
          this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments);
        },
        scrollToElement() {
          // 代理better-scroll的scrollToElement方法
          this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments);
        },
        destroy() {
          this.scroll.destroy();
        }
      },
      watch: {
        // 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常,如果是下拉刷新,时间稍微调整长点
        listArr(nVal, oVal) {
          let times = 800;
          if (this.isPullingDown) {
            times = 800;
          } else {
            times = 30;
          }
          setTimeout(() => {
            this.refresh();
            this.forceUpdate();
          }, times);
        }
      }
    };
    </script>
    
    <style scoped lang='less'>
    .no-data {
      margin-top: 2.4rem;
    }
    .have-data {
      margin-top: 0.2rem;
    }
    .my-scroll {
      overflow: hidden;
      height: 100%;
      position: relative;
    }
    .pulldown-wrapper {
      height: 0.5rem;
      position: absolute;
      top: -9px;
      left: 0;
      width: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: all;
    }
    .scroll-content {
      position: relative;
      z-index: 2000;
    }
    .pull-up-box {
      width: 100%;
      height: 0.2rem;
      // margin: 0.2rem 0 0.2rem 0;
      color: #999;
      font-size: 14px;
    }
    .refresh-txt {
      height: 0.3rem;
      width: 1rem;
      border-radius: 3px;
      background-color: black;
      opacity: 0.7;
      color: #fff;
      z-index: 2999;
      position: fixed;
      top: 2rem;
      left: 50%;
      transform: translate(-50%, 0);
      line-height: 0.3rem;
    }
    </style>
    

    相关文章

      网友评论

          本文标题:better-scroll在vue的使用

          本文链接:https://www.haomeiwen.com/subject/toywgctx.html