微信小程序uniapp的上拉加载与下拉刷新实现

1,574 阅读2分钟

列表页有一个上拉加载与下拉刷新的需求,这边用到了uniapp的<scroll-view></scroll-view>标签

官方文档:scroll-view | uni-app官网

根据文档,这次用到的有以下属性:

scroll-y:开启纵向滚动

refresher-enabled:开启自定义下拉刷新

refresher-triggered:设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发

@scrolltolower:滚动到底部/右边时,会触发 scrolltolower 事件

@refresherrefresh:自定义下拉刷新被触发

refresher-default-style:设置自定义下拉刷新默认样式

这里有两个点需要注意:

  1. scroll-view标签一定要给高度,不然无效
  2. triggered的初始值为false,在下拉刷新触发时,要先变为true,在请求或者其它延时操作之后再将它变为false,才会有效果
<template>
  <view>
    <scroll-view
      style="height: 100%"
      :scroll-y="true"
      :refresher-enabled="true"
      :refresher-triggered="triggered"
      @scrolltolower="scrolltolower"
      @refresherrefresh="onRefresh"
      refresher-default-style="black"
    >
      <!-- 需要滚动的区域 -->
    </scroll-view>
  </view>
</template><script>
export default {
  data() {
    return {
      triggered: false, // 下拉是否激活
      tabDetailList: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
    };
  },
  methods: {
    // 上拉加载
    scrolltolower() {
      if (this.tabDetailList.length < this.total) {
        this.pageNum += 1;
        // 继续请求下一页,记得保留原先数组
        this.getTabCDetail();
      } else {
        uni.showToast({
          title: "没有更多了",
          icon: "none",
          duration: 2000,
        });
        return;
      }
    },
    // 自定义下拉刷新被触发
    onRefresh() {
      // 开启下拉自定义样式
      this.triggered = true;
      //  重新调用
      this.init();
​
      // 1秒之后复位
      setTimeout((e) => {
        this.triggered = false;
      }, 1000);
    },
  },
};
</script><style lang="scss" scoped></style>

当时写完之后,碰到一个可能不算问题的问题

在自定义下拉刷新触发时,由于请求回来的很快,几乎在一瞬间就执行了this.triggered = false,在视觉上有个'一闪而过'的体验,觉得有点怪(我是将this.triggered的状态在请求中进行更改);后面经同事修改,他将this.triggered = false写在了setTimeout里面,这样样式有保留,数据也有更新

这里涉及到一个事件循环的知识点,我是这么理解的:

由于setTimeout与异步请求同属异步宏任务,代码从上往下执行,当 this.init() 被调用时,它会发起一个异步请求。该请求会被放入事件队列中,而不会立即执行,因为JavaScript是单线程的,它会等待事件循环处理这个请求。与此同时,setTimeout 也是一个异步操作,它会被放入事件队列中。在setTimeout中设置了1秒的延迟,因此它会在1秒后被执行。

由于事件队列是先进先出的,所以在事件循环中,this.init() 请求完成后,才会执行 setTimeout 中的操作。也就是说,不管this.init()请求回来得有多慢,setTimeout一定会在this.init()请求回来之后才会执行。