Vue 滚动插件BetterScroll 封装下拉刷新、上拉触底 (待优化)

import BScroll from 'better-scroll'
let wrapper = document.querySelector('.wrapper')
let scroll = new BScroll(wrapper, {})

BScroll初始化时机

 

mounted() {
    this.$nextTick(() => {
        this.scroll = new Bscroll(this.$refs.wrapper, {})
    })
}

 

如果子元素或者父元素 DOM 结构发生改变的时候,必须重新调用 scroll.refresh() 方法重新计算来确保滚动效果的正常。

 

异步数据的处理

 

created() { 
    requestData().then((res) => { 
        this.data = res.data this.$nextTick(() => { 
            this.scroll = new Bscroll(this.$refs.wrapper, {}) 
        }) 
    }) 
}

(为什么这里在 created 这个钩子函数里请求数据而不是放到 mounted 的钩子函数里?因为 requestData 是发送一个网络请求,这是一个异步过程,当拿到响应数据的时候,Vue 的 DOM 早就已经渲染好了,但是数据改变 —> DOM 重新渲染仍然是一个异步过程,所以即使在我们拿到数据后,也要异步初始化 better-scroll。)

 

动态获取数据并刷新BScroll

 

created() {
  this.loadData()
},
methods: {
  loadData() {
    requestData().then((res) => {
      this.data = res.data.concat(this.data)
      this.$nextTick(() => {
        if (!this.scroll) { // 判断是否初始化new BScroll 
          this.scroll = new Bscroll(this.$refs.wrapper, {})
          this.scroll.on('touchend', (pos) => { // 下拉动作 
            if (pos.y > 50) { this.loadData() }
          })
        } else { this.scroll.refresh() }
      })
    })
  }
}

 

封装better-scroll (包含,下拉刷新,到底加载更多)

<template>
  <div class="wrappers">
    <!-- 下拉刷新 -->
    <div v-if="pulldown" class="loading">
      <span class="iconfont"></span>
      <i>{{pulldownTips}}</i>
    </div>
    <!-- 上滑加载更多 -->
    <div v-if="pullup" class="loading-up">
      <div class="content">
        <span class="iconfont"></span>
        <i>{{pullupTips}}</i>
      </div>
    </div>
    <div class="loading-txt" v-show="showLoadingTxt">{{loadingTxt}}</div>
    <div class="wrapper" ref="wrapper">
      <slot></slot>
    </div>
  </div>
</template>
<script>
import BScroll from "better-scroll";
export default {
  name: "BScroll",
  data() {
    return {
      pulldownTips: "下拉刷新",
      pullupTips: "上滑加载更多",
      loadingTxt: "正在加载...",
      pulldownTimer: null,
      showLoadingTxt: false
    };
  },
  props: {
    /**
     * 1 滚动的时候会派发scroll事件,会截流。
     * 2 滚动的时候实时派发scroll事件,不会截流。
     * 3 除了实时派发scroll事件,在swipe的情况下仍然能实时派发scroll事件
     */
    probeType: {
      type: Number,
      default: 1
    },
    /**
     * 点击列表是否派发click事件
     */
    click: {
      type: Boolean,
      default: true
    },
    /**
     * 是否开启横向滚动
     */
    scrollX: {
      type: Boolean,
      default: false
    },
    /**
     * 是否派发滚动事件
     */
    listenScroll: {
      type: Boolean,
      default: false
    },
    /**
     * 列表的数据
     */
    data: {
      type: Array,
      default: null
    },
    /**
     * 是否派发滚动到底部的事件,用于上拉加载
     */
    pullup: {
      type: Boolean,
      default: false
    },
    /**
     * 是否派发顶部下拉的事件,用于下拉刷新
     */
    pulldown: {
      type: Boolean,
      default: false
    },
    /**
     * 是否派发列表滚动开始的事件
     */
    beforeScroll: {
      type: Boolean,
      default: false
    },
    /**
     * 当数据更新后,刷新scroll的延时。
     */
    refreshDelay: {
      type: Number,
      default: 20
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initBScroll();
    });
  },
  methods: {
    initBScroll() {
      if (!this.$refs.wrapper) {
        return;
      }
      // 初始化
      this.scroll = new BScroll(this.$refs.wrapper, {
        probeType: this.probeType,
        click: this.click,
        scrollX: this.scrollX
      });
      // 是否派发滚动事件
      if (this.listenScroll) {
        let me = this;
        this.scroll.on("scroll", pos => {
          if (pos.y > 50) {
            this.pulldownTips = "释放立即刷新";
          }
          if (this.scroll.y > this.scroll.maxScrollY + 50) {
            this.pullupTips = "上滑加载更多";
          }
        });
      }

      // 是否派发滚动到底部事件,用于上拉加载
      if (this.pullup) {
        this.scroll.on("scrollEnd", () => {
          // 滚动到底部
          if (this.scroll.y <= this.scroll.maxScrollY + 100) {
            this.pullupTips = "释放加载下一页";
            this.$emit("scrollToEnd");
          }
        });
      }

      // 是否派发顶部下拉事件,用于下拉刷新
      if (this.pulldown) {
        this.scroll.on("touchEnd", pos => {
          // 下拉动作
          if (pos.y > 50) {
            if (this.pulldownTimer) {
              // 清除计时器,防止频繁触发下拉刷新
              clearTimeout(this.pulldownTimer);
            }
            this.showLoadingTxt = true;
            this.$emit("pulldown");
            this.pulldownTips = "下拉刷新";
            this.loadingTxt = "正在加载";
          }
        });
      }

      // 是否派发列表滚动开始的事件
      if (this.beforeScroll) {
        this.scroll.on("beforeScrollStart", () => {
          this.$emit("beforeScroll");
        });
      }
    },
    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);
    }
  },
  watch: {
    // 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常
    data() {
      setTimeout(() => {
        this.refresh();
        if (this.pulldown) {
          this.loadingTxt = "刷新成功";
          this.pulldownTimer = setTimeout(() => {
            this.showLoadingTxt = false;
            clearTimeout(this.pulldownTimer);
          }, 1000);
        }
      }, this.refreshDelay);
    }
  }
};
</script>

<style  scoped>
.wrappers,
.wrapper {
  position: absolute;
  left: 0;
  right: 0;
  overflow: hidden;
  top: 0;
  bottom: 0;
}
.loading,
.loading-txt,
.loading-up {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 300px;
  background-color: #eee;
  text-align: center;
  line-height: 50px;
  font-size: 14px;
}
.loading-up {
  top: auto;
  bottom: 0;
}
.loading-up > .content {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 50px;
}
.loading-txt {
  height: 30px;
  z-index: 99;
  background-color: rgb(28, 28, 28, 0.38);
  color: #fff;
  line-height: 30px;
}
</style>

引入使用 

<wrapper
      :data="data"
      :probeType="1"
      :pulldown="true"
      :pullup="true"
      :listenScroll="true"
      @pulldown="pulldown"
      @scrollToEnd="scrollToEnd"
    >
      <div class="main">
        <div>
          <p v-for="(i,index) in 100" :key="index">
            <i>00{{i}}</i>
          </p>加载中
        </div>
      </div>
</wrapper>

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值